haskellfunctional-programmingexistential-typexmobar

What are the definitions of Weather and Memory in xmobar repo?


Playing around with xmobar, when I saw this

  , commands = [ Run $ Weather "EGPH" ["-t","<station>: <tempC>C",
                                        "-L","18","-H","25",
                                        "--normal","green",
                                        "--high","red",
                                        "--low","lightblue"] 36000
               , Run $ Network "eth0" ["-L","0","-H","32",
                                        "--normal","green","--high","red"] 10
               , Run $ Network "eth1" ["-L","0","-H","32",
                                        "--normal","green","--high","red"] 10
               , Run $ Cpu ["-L","3","-H","50",
                             "--normal","green","--high","red"] 10
               , Run $ Memory ["-t","Mem: <usedratio>%"] 10
               , Run $ Swap [] 10
               , Run $ Com "uname" ["-s","-r"] "" 36000
               , Run $ Date "%a %b %_d %Y %H:%M:%S" "date" 10
              , Run HelloWorld
              ]

I without thinking too much I said "oh, I can pull that Run out" and wrote

  , commands = Run <$> [Weather {- ... -}
               , Network {- ... -}
               , Network {- ... -}
               , Cpu {- ... -}
               , Memory {- ... -}
               , Swap {- ... -}
               , Com {- ... -}
               , Date  {- ... -}
               , HelloWorld
               ]

but this obviously doesn't work, because for instance Data, HelloWorld and Weather are different types.

But some can go together within a list, e.g. this type checks

foo = [ Weather undefined undefined undefined
      , Cpu undefined undefined
      , DiskU undefined undefined undefined
      , Memory undefined undefined ]

but this doesn't

foo = [ Weather undefined undefined undefined
      , Cpu undefined undefined
      , DiskU undefined undefined undefined
      , Date undefined undefined undefined -- because of this
      , Memory undefined undefined ]

Now I see that Date is an actual data type, but what are the others?

If I open Weather I don't even see the single word Weather other than in a comment and in the name of the module.

So what is Weather? And where do I see its definition?

The fact that Weather and, say, Memory can go in the same list makes me think of existential types of which I have little experience. However, from that wiki page, I see that this

data Worker x y = forall b. Buffer b => Worker {buffer :: b, input :: x, output :: y}

is the way of defining a Worker that can hold a buffer of whatever type, as long as that type implements Buffer.

Now, given that the type of the first foo above has type [Monitors], I guess that Monitors is playing the role of Worker, the existential type, and Weather, Memory and others are value constructors of types that implement whatever interface (corresponding to Buffer) is constraining the the type that the existential type Monitors can wrap. But Date doesn't implement that interface, so it can't go with the others.

Is it like this?

But if that's the case... then where are Weather's, Memory's and others' definitions, togheter with their implementation of the interface?


Solution

  • Instead of searching in just the Weather.hs file, search in the whole repository. You will find Monitors.hs features a definition of Weather:

    data Monitors = Network      Interface   Args Rate
                  -- ...
                  | DiskU        DiskSpec    Args Rate
                  -- ...
                  | Memory       Args        Rate
                  | Swap         Args        Rate
                  | Cpu          Args        Rate
                  -- ...
    #ifdef WEATHER
                  | Weather      Station     Args Rate
                  | WeatherX     Station SkyConditions Args Rate
    #endif
                  -- ...
    

    It is not an existential type, just an ordinary Haskell algebraic data type, so there is no "interface" to support. They can go in a list together because they are all of the same type (Monitors).

    You could also find this out by reading the Haddock documentation for xmobar instead of poring through the source. It's nicely indexed and cross-linked so you can find the definitions you're looking for, and links to the source if you want to see more details.

    There is a closely related existential type Runnable, defined in Runnable.hs, as

    data Runnable = forall r . (Exec r, Read r, Show r) => Run r
    

    This is the existential type that allows Run $ Date ... to be in the same list as the other monitors like Run $ Memory ..., even though the Date type and Monitors type are not directly related. They each satisfy the Runnable constraints, and the Runnable wrapper hides all their other details so they can be treated uniformly.