It is possible to rebind the (>>=) and return for a monad using explicit dictionary passing like this:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RebindableSyntax #-}
module Lib where
import Prelude hiding ((>>=), return)
data MonadDict m = MonadDict {
bind :: forall a b. m a -> (a -> m b) -> m b ,
ret :: forall a. a -> m a }
(>>=) :: (MonadDict m -> m a) -> (a -> (MonadDict m -> m b)) -> (MonadDict m -> m b)
return :: a -> (MonadDict m -> m a)
monadDictIO :: MonadDict IO
usage = let
monadicCode = do
ln <- const getLine
const . putStrLn $ ln
in monadicCode monadDictIO
Is there a better way, how to represent the monad so one can avoid ignoring the MonadDict
monad instance argument (using const
) in every usage of the monadic action?
You can do like this:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE RecordWildCards #-}
module Lib where
import Prelude hiding(return, fail, (>>=), (>>))
data MonadDict m = MonadDict
{ (>>=) :: forall a b. m a -> (a -> m b) -> m b
, (>>) :: forall a b. m a -> m b -> m b
, return :: forall a. a -> m a
, fail :: forall a. String -> m a
}
monadDictIO :: MonadDict IO
monadDictIO = ...
foo :: MonadDict m -> String -> m ()
foo = ...
usage = let
monadicCode m@MonadDict{..} = do
ln <- getLine
putStrLn ln
foo m ln
in monadicCode monadDictIO