在 monad 的上下文中是否一定要使用 do 符号?
Is do notation used necessarily in the context of monad?
Haskell 2010 年报告说
A do expression provides a more conventional syntax for monadic
programming. It allows an expression such as
putStr "x: " >>
getLine >>= \l ->
return (words l)
to be written in a more traditional way as:
do putStr "x: "
l <- getLine
return (words l)
Haskell Thompson 的函数式编程技巧说
We'll continue to use the do notation, but will keep in mind that it essentially
boils down to the existence of a function (>>=) which does the work of sequencing I/O
programs, and binding their results for future use.
以上是否意味着在 monad 上下文中必须使用 do 符号?
如果是,为什么下面的仿函数使用do表示法?
instance Functor IO where
-- fmap :: (a -> b) -> IO a -> IO b
fmap g mx = do {x <- mx; return (g x)}
是的。正如引用的文章所述,do
-notation 只是 语法糖 用于 monad 操作。
这些是 the rules 用于脱糖的 do
-notation:
do {foobar; ...} = foobar >> do {...}
(又名 foobar >>= \_ -> do {...}
)
do {a <- foobar; ...} = foobar >>= \a -> do {...}
do {foobar} = foobar
这必然意味着 do
-notation 完全适用于 monad,除了规则 3 描述的微不足道的情况。
因此,例如,如文章所述,do {putStr "x: "; l <- getLine; return (words l)}
正好等于 putStr "x: " >> (getLine >>= \l -> return (words l))
,您可以通过脱糖规则来确认。
在您上面引用的 Functor IO
的定义中,已经定义了 Monad IO
实例,因此我们也使用它来定义 Functor
实例。
注意到所有 monads 都必然是函子可能也很有用(参见 definition of the Monad
typeclass),所以当有人说 do
-notation 对 monads 起作用时,它也必然对函子起作用以及。我怀疑这可能是一个混淆点。
值得注意的是,在某些受限制的情况下,可以仅使用 Applicative
操作而不是更通用的 Monad
操作。比如文章提供的例子可以写成putStr "x: " *> (pure words <*> getLine)
。有一个名为 ApplicativeDo
的实验性语言扩展,它增加了 GHC 识别这些情况的能力,并将 do
-notation 的某些情况推广到所有应用程序,而不仅仅是所有 monad。
好吧,有了 RebindableSyntax 扩展,它将使用范围内的任何 (>>=)
、(>>)
和 fail
。所以技术上 Monad
在这种情况下不是必需的,你可以做一些愚蠢的事情:
{-# LANGUAGE RebindableSyntax #-}
a >>= b = b a
return a = a
-- test == ("foo","boo")
test = do
a <- "foo"
b <- "boo"
return (a,b)
Haskell 2010 年报告说
A do expression provides a more conventional syntax for monadic programming. It allows an expression such as
putStr "x: " >> getLine >>= \l -> return (words l)
to be written in a more traditional way as:
do putStr "x: " l <- getLine return (words l)
Haskell Thompson 的函数式编程技巧说
We'll continue to use the do notation, but will keep in mind that it essentially boils down to the existence of a function (>>=) which does the work of sequencing I/O programs, and binding their results for future use.
以上是否意味着在 monad 上下文中必须使用 do 符号?
如果是,为什么下面的仿函数使用do表示法?
instance Functor IO where
-- fmap :: (a -> b) -> IO a -> IO b
fmap g mx = do {x <- mx; return (g x)}
是的。正如引用的文章所述,do
-notation 只是 语法糖 用于 monad 操作。
这些是 the rules 用于脱糖的 do
-notation:
do {foobar; ...} = foobar >> do {...}
(又名foobar >>= \_ -> do {...}
)do {a <- foobar; ...} = foobar >>= \a -> do {...}
do {foobar} = foobar
这必然意味着 do
-notation 完全适用于 monad,除了规则 3 描述的微不足道的情况。
因此,例如,如文章所述,do {putStr "x: "; l <- getLine; return (words l)}
正好等于 putStr "x: " >> (getLine >>= \l -> return (words l))
,您可以通过脱糖规则来确认。
在您上面引用的 Functor IO
的定义中,已经定义了 Monad IO
实例,因此我们也使用它来定义 Functor
实例。
注意到所有 monads 都必然是函子可能也很有用(参见 definition of the Monad
typeclass),所以当有人说 do
-notation 对 monads 起作用时,它也必然对函子起作用以及。我怀疑这可能是一个混淆点。
值得注意的是,在某些受限制的情况下,可以仅使用 Applicative
操作而不是更通用的 Monad
操作。比如文章提供的例子可以写成putStr "x: " *> (pure words <*> getLine)
。有一个名为 ApplicativeDo
的实验性语言扩展,它增加了 GHC 识别这些情况的能力,并将 do
-notation 的某些情况推广到所有应用程序,而不仅仅是所有 monad。
好吧,有了 RebindableSyntax 扩展,它将使用范围内的任何 (>>=)
、(>>)
和 fail
。所以技术上 Monad
在这种情况下不是必需的,你可以做一些愚蠢的事情:
{-# LANGUAGE RebindableSyntax #-}
a >>= b = b a
return a = a
-- test == ("foo","boo")
test = do
a <- "foo"
b <- "boo"
return (a,b)