恢复do notation语法

Yog*_*kar 9 haskell

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

坦率地说,我无法理解

return :: a -> (Monad f -> f a) 
(>>=) :: (Monad f -> f a) -> (a -> (Monad f -> f b)) -> (Monad f -> f b)
Run Code Online (Sandbox Code Playgroud)

会帮助恢复做法

你可以像这样实现所有的monadic组合器,并且desugar可以为它们做记号.do块计算为接受monad字典的函数,因此您甚至可以方便地编写monad选择中的多态代码,而无需手动编写字典.

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

小智 6

{-# LANGUAGE Rank2Types, RebindableSyntax #-}

import qualified Prelude
import qualified System.IO
import Prelude (String, ($), (++))
import System.IO (IO)
Run Code Online (Sandbox Code Playgroud)

加布里埃尔冈萨雷斯的建议

data MonadI f = MonadI {
    _return :: forall a . a -> f a,
    _bind :: forall a b . f a -> (a -> f b) -> f b
}
Run Code Online (Sandbox Code Playgroud)

您可以使用Paul Chiusano建议的类型实现必要的功能return,(>>=)如下所示:

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)
Run Code Online (Sandbox Code Playgroud)

这还不足以恢复记号,因为你也需要(>>)和(遗憾地)fail.您可以按如下方式实现它们:

(>>) :: (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.
Run Code Online (Sandbox Code Playgroud)

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

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

当然,我们将不得不借用一些东西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)
}
Run Code Online (Sandbox Code Playgroud)