Reputation: 1116
I was reading through Scrap your type classes. This provides an alternatives for type classes. However, I was stuck with a comment by Paul Chiusano which talked about recovering the do notation syntax.
Frankly I could not understand how
return :: a -> (Monad f -> f a)
(>>=) :: (Monad f -> f a) -> (a -> (Monad f -> f b)) -> (Monad f -> f b)
would help recover do notation
You can implement all the monadic combinators like this, and desugar do notation to them. The do block evaluates to a function that accepts the monad dictionary, so you can even conveniently write code that's polymorphic in the choice of monad, without having to thread the dictionary around manually.
And especially, how it would fit int he context of GADT style approach mentioned in the above article?
Upvotes: 9
Views: 144
Reputation:
{-# LANGUAGE Rank2Types, RebindableSyntax #-} import qualified Prelude import qualified System.IO import Prelude (String, ($), (++)) import System.IO (IO)
With Gabriel Gonzales' suggestion
data MonadI f = MonadI { _return :: forall a . a -> f a, _bind :: forall a b . f a -> (a -> f b) -> f b }
you could implement the necessary functions return
and (>>=)
as follows, with the types as suggested by Paul Chiusano:
return :: a -> (MonadI f -> f a) return x = \dict -> (_return dict) x (>>=) :: (MonadI f -> f a) -> (a -> (MonadI f -> f b)) -> (MonadI f -> f b) ma >>= f = \dict -> (_bind dict) (ma dict) (\x -> f x dict)
This is not enough to recover do-notation, because you'll also need (>>)
and (sadly) fail
. You can implement them as follows:
(>>) :: (MonadI f -> f a) -> (MonadI f -> f b) -> (MonadI f -> f b) ma >> mb = ma >>= (\_ -> mb) fail :: String -> MonadI f -> f a fail str = \_ -> Prelude.error str -- Because let's not further entertain that idea.
And now we have the required facilities to write simple programs:
main :: IO () main = (\m -> m monad'IO) $ do putStrLn "What is your name?" name <- getLine putStrLn $ "Hello, " ++ name
Of course, we're going to have to borrow some things from System.IO
for that:
getLine :: MonadI IO -> IO String getLine = \_ -> System.IO.getLine putStrLn :: String -> (MonadI IO -> IO ()) putStrLn str = \_ -> System.IO.putStrLn str monad'IO :: MonadI IO monad'IO = MonadI { _return = (Prelude.return :: a -> IO a), _bind = ((Prelude.>>=) :: IO a -> (a -> IO b) -> IO b) }
Upvotes: 6