在monad的上下文中一定要使用符号吗?

Tim*_*Tim 1 monads haskell do-notation

Haskell 2010年报告说

do表达式为monadic编程提供了更常规的语法。它允许一个表达式,例如

putStr "x: " >>
getLine >>= \l ->
return (words l)
Run Code Online (Sandbox Code Playgroud)

用更传统的方式写成:

do putStr "x: "
   l <- getLine
   return (words l)
Run Code Online (Sandbox Code Playgroud)

汤普森说,Haskell函数编程技巧说

我们将继续使用do表示法,但要记住,它本质上 归结为一个函数(>> =)的存在,该函数负责对I / O程序进行排序并将其结果绑定以供将来使用。

以上是否意味着必须在monad的上下文中使用符号?

如果是,为什么以下函子使用do表示法?

instance    Functor IO  where
    --  fmap    ::  (a  ->  b)  ->  IO  a   ->  IO  b
    fmap    g   mx  =   do  {x  <-  mx; return  (g  x)}
Run Code Online (Sandbox Code Playgroud)

AJF*_*mar 5

是。正如文章所引用的那样,- do符号只是 monad操作的语法糖

这些是去糖符号的规则do

  1. do {foobar; ...} = foobar >> do {...}(又名foobar >>= \_ -> do {...}
  2. do {a <- foobar; ...} = foobar >>= \a -> do {...}
  3. do {foobar} = foobar

必要的是,这意味着- do注释完全适用于monad,除非在规则3所描述的琐碎情况下。

因此,例如,如文章所述,do {putStr "x: "; l <- getLine; return (words l)}它等于putStr "x: " >> (getLine >>= \l -> return (words l)),您可以通过除糖规则进行确认。

Functor IO上面引用的定义中,Monad IO实例已经定义,因此我们也使用它来定义Functor实例。

这也可能是要注意,所有的单子都是必然仿函数(见有用的定义Monad类型类),所以当一个人说do-notation作品的单子,这也必然适用于函子为好。我怀疑这可能是一个混淆点。


值得注意的是,在某些受限情况下,可以仅使用Applicative操作而不是更常规的Monad操作。例如,文章提供的示例可以写为putStr "x: " *> (pure words <*> getLine)。有一个实验语言扩展名为ApplicativeDoGHC,它使GHC能够识别这些情况并将某些do符号的情况推广到所有应用程序,而不仅是所有monad。

  • @Tim我从整体上知道它,因为他们使用`do`表示法来定义`fmap`!但是,通常无法测量Haskell中的定义顺序,因为可以相互递归。相反,我的意思是定义Monad实例,并且以不递归方式引用fmap的方式。我可以通过在[hoogle](https://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#t:IO)上查找定义来发现这一点。 (3认同)