Search code examples
monadspurescript

Bind class instance for partially applied functions


The definition of the Bind class in the Prelude is:

class Apply m <= Bind m where
  bind :: forall a b. m a -> (a -> m b) -> m b

It can be read as a function taking two input parameters, a value in a monadic context (m a) and a function (a -> m b) and returning a value in a monadic context (m b).

The instance of Bind for partially-applied function is defined as:

instance bindFn :: Bind ((->) r) where
  bind m f x = f (m x) x

Which is a function taking three parameters. How does that typecheck?

If I try to replace m a by a more concrete type I get (correct me if I am wrong):

(((->) ??) a) -> (a -> (((->) ??) b)) -> (((->) ??) b)

which is equivalent to

(?? -> a) -> (a -> (?? -> b)) -> (?? -> b)

Assuming the variable m is bound to (?? -> a), f would get bound to a -> ?? -> b, and x to the second ??.

Is my reasoning correct?


Solution

  • To add to what swizard said (which is correct), one way to check what the type signature of a type class function is once it's been specialized to a particular instance is to write it out and see if psci agrees:

    > :type bind :: forall r a b. (r -> a) -> (a -> r -> b) -> (r -> b)
    forall r a b. (r -> a) -> (a -> r -> b) -> r -> b
    

    So your reasoning is indeed correct. If we'd written out an incorrect type, we would have been given a type error:

    > :type bind :: forall r. r -> r
    Error found:
    [...]
       Could not match type [...] with [...]
    [...]
    

    Also, just in case you weren't already aware, the function type constructor -> is right-associative, so a -> (r -> b) is the same as a -> r -> b.