恢复符号语法

时间:2015-10-29 18:54:05

标签: haskell

我正在阅读Scrap your type classes。这为类型类提供了替代方案。但是,我被Paul Chiusano的评论所困扰,该评论谈到了恢复 do notation 语法。

坦率地说,我无法理解

return :: a -> (Monad f -> f a) 
(>>=) :: (Monad f -> f a) -> (a -> (Monad f -> f b)) -> (Monad f -> f b)

将有助于恢复 do notation

  

你可以实现像这样的所有monadic组合器和desugar   给他们做记号。 do块计算为接受的函数   monad字典,所以你甚至可以方便地编写代码   monad的多态性选择,无需线程化   手动字典。

尤其是,它如何适合上述文章中提到的GADT风格方法的背景?

1 个答案:

答案 0 :(得分:6)

{-# LANGUAGE Rank2Types, RebindableSyntax #-}

import qualified Prelude
import qualified System.IO
import Prelude (String, ($), (++))
import System.IO (IO)

Gabriel Gonzales的建议

data MonadI f = MonadI {
    _return :: forall a . a -> f a,
    _bind :: forall a b . f a -> (a -> f b) -> f b
}

您可以按照以下方式实施必要的功能return(>>=),其中包含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)

这还不足以恢复通知,因为您还需要(>>)和(sadlyfail。您可以按如下方式实现它们:

(>>) :: (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.

现在我们有了编写简单程序所需的工具:

main :: IO ()
main = (\m -> m monad'IO) $ do
    putStrLn "What is your name?"
    name <- getLine
    putStrLn $ "Hello, " ++ name

当然,我们将不得不从System.IO借用一些东西:

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)
}