1
votes

I have a data type that resembles Blah below but because of a quirk with the type I cannot automatically derive Functor, Applicative, and Monad. So I must do it manually, but I'm not sure how. I tried to take inspiration from the instances for ((->) a), but I can't quite figure out the Monad instance.

newtype Blah a = Blah (String -> a) -- deriving (Functor, Applicative, Monad)

-- this seems right
instance Functor Blah where
  fmap f (Blah g) = Blah (f .  g)

instance Applicative Blah where
  pure = Blah . const
  -- This is right, right?
  (<*>) (Blah f) (Blah g) = Blah $ \x -> f x (g x)

instance Monad Blah where
  return = pure

  -- I'm not having any luck here.
  (>>=) a b = Blah $ \c -> _

Edit: Someone marked this as a duplicate of another, but I don't see where I would've gotten the answer from that. The newtype wrapper is what made this difficult. I looked up the Monad instance in base for (->) a before I wrote this question, but the gymnastics in the answer here are what I needed.

3
Why has this been marked down? It seems like a perfectly good question.Paul Johnson

3 Answers

3
votes

How about

Blah f >>= g = Blah $ \s ->
    let Blah h = g $ f s in h s
2
votes

You can derive those instances. You just need to turn on the GeneralizedNewtypeDeriving flag, which enables GHC to simply reuse the instance for the wrapped type.

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype Blah a = Blah (String -> a) deriving (Functor, Applicative, Monad)
1
votes

Here’s how you can derive this yourself using typed holes. Starting from your code, renamed a bit:

instance Monad Blah where
  return = pure
  f >>= g = Blah $ \s -> _

You’ll get a message like this:

Found hole ‘_’ with type: b
Relevant bindings include
  s :: String
  g :: a -> Blah b
  f :: Blah a

So we need to produce a b, given a String, a Blah a, and an a -> Blah b. Well, we already know how to produce an a from a Blah a and a String, by pattern-matching and applying the function in the Blah:

Blah f >>= g = Blah $ \s -> let h = f s in _
------                      -----------

Now we get:

Found hole ‘_’ with type: b
Relevant bindings include
  h :: a
  s :: String
  g :: a -> Blah b
  f :: String -> a

So we have an a, which we can give to g to get a Blah b, and pattern-matching on that gives us a String -> b:

Blah f >>= g = Blah $ \s -> let Blah h = g (f s) in _
                                ----------------

Now we get:

Found hole ‘_’ with type: b
Relevant bindings include
  h :: String -> b
  s :: String
  g :: a -> Blah b
  f :: String -> a

So we need a b, and we have a String and a String -> b. That’s easy:

Blah f >>= g = Blah $ \s -> let Blah h = g (f s) in h s
                                                    ---

And there you go, a correct implementation, guided by the types. You may also find it clearer if you define a helper function to “run” a Blah:

newtype Blah a = Blah { runBlah :: String -> a }
-- or:
runBlah :: Blah a -> String -> a
runBlah (Blah f) = f

instance Monad Blah where
  f >>= g = Blah $ \s -> runBlah (g (runBlah f s)) s