15

For some reason I can't find the answer to this anywhere. I tried Googling "Haskell equal sign arrow" and I'm not getting any results. Let's say we have the following function:

sendMessage :: MonadM e m => Message -> m ()
sendMessage message = do
    mClient  <- getMessageClient
    liftIO $ send mClient message

Where exactly are e and m getting used? Are they being passed into the Message object (function?) and then outputted as a single type, m ()?

I don't think it helps that I'm very new to Haskell, but any help is appreciated here.

Niko
  • 984
  • 1
  • 7
  • 15

2 Answers2

15

First off: if you want to know what such and such operator does, don't ask StackOverflow, ask Hoogle!

But in fact Hayoo is no use for => in particular because, unlike almost everything else in Haskell, this is built-in syntax and not an operator that's defined in some library.

Your signature

sendMessage :: MonadM e m => Message -> m ()

means the following: the type of sendMessage is Message -> m (), where m can be any monad that has an instance of the MonadM type class.

That probably doesn't help you much, because in fact MonadM is a rather involved type class. Better consider a simpler example:

sum :: Num n => [n] -> n

This means: the type of sum is [n] -> n, where n can be any number type that's an instance of the Num class, i.e. the class of types supporting subtraction, multiplication, obviously addition etc.. Actually the syntax is shorthand for

sum :: ∀ n . Num n => [n] -> n

meaning that for all types n which fulfill the constraint Num n, the function sum has the signature [n] -> n.

You can instantiate such a polymorphic function with any concrete number type: e.g.

sum :: [Int] -> Int

In your example you'd probably instantiate it to something like

sendMessage :: Message -> MessageT IO ()
leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
  • Thanks for the Hayoo reference; I'll totally be using that a ton. So, if I understand this correctly, anything before the => sign is just a type restriction to the matching input/output elements? – Niko Aug 22 '16 at 17:11
  • 1
    Basically yes. In fact it's often useful to disregard the constraints at first, and either consider an example instantiation or the unconstrained polymorphic function to figure out what's going on. – leftaroundabout Aug 22 '16 at 17:21
  • Got it. Thanks for your help. – Niko Aug 22 '16 at 17:40
  • [hoogle](https://hackage.haskell.org/package/hoogle) instead of [hayoo](https://hackage.haskell.org/package/Hayoo), as the latter has no upload since 2012, and the link above is not reachable, either. – Roland Puntaier Jun 01 '20 at 15:24
  • @RolandPuntaier yes, thanks. Please don't hesitate to make such remarks directly as _edits_ in the future. – leftaroundabout Jun 01 '20 at 15:46
3

The type signature

sendMessage :: MonadM e m => Message -> m ()

can be read

Assuming that the constraint MonadM e m holds, sendMessage has type Message -> m ()

MonadM is (almost certainly) a multi-parameter type class with a functional dependency. Its definition probably looks vaguely like

class Monad m => MonadM e m | m -> e where ....

You don't have to worry about that right now. Writing such classes is a somewhat advanced topic. But it expresses that some operations are available that relate the types e and m, where the type e is determined by the type m.

dfeuer
  • 48,079
  • 5
  • 63
  • 167
  • So are e & m still inputs to this function? Or is it just Message? Or...both? – Niko Aug 22 '16 at 17:08
  • The input to this function is just a `Message`. The output is of any `m` type you choose, *so long as* `m` is an instance of the typeclass `MonadM e m`. – amalloy Aug 22 '16 at 17:10
  • @Niko: they are _type-level arguments_ of the function, if you will. But it's not necessarily helpful to look at it this way. – leftaroundabout Aug 22 '16 at 17:10
  • Okay I think I understand. My only question is how can you verify that m is of type MonadM e m if you don't know what e is? Or am I misinterpreting what "e" is – Niko Aug 22 '16 at 17:13
  • @Niko, you shouldn't need to worry about `e` here, because it seems to be irrelevant to `sendMessage`, though it's presumably important for some other operations. `e` will be fixed by whatever instance `m` has. You'll have to check the documentation or GHC to see if your particular `m` has an instance. Note also that `m` *is* a type, and does not have *type* `MonadM e m`, but rather *satisfies the constraint* `MonadM e m`. – dfeuer Aug 22 '16 at 18:00
  • @dfeuer That clears it up. Thanks for your patience. – Niko Aug 22 '16 at 18:52