我是一个非常新的Haskell学习者。我有一个工作表达式:
do x <- try parseA <|> parseB
return x
看起来效果很好(我使用Parsec
包,但我希望这个问题与其功能无关,据我所知<|>
是Parsec-定义的中缀运算符)。 parseA
和parseB
都具有Parser Foo
monad类型,整个表达式也是如此。
根据我到目前为止所读到的内容,它似乎应该等同于
do return (try parseA <|> parseB)
和
do return $ try parseA <|> parseB
但后者没有编译,他们抱怨不匹配的类型(下面的错误)。
我的其他尝试重写此内容,如
(try parseA <|> parse B) >>= return
似乎有效。但如果我也误解了这一点,请说。
所以我的问题是,有人可以解释为什么前三个是不同的。我很困惑他们为什么不等同。我错过了什么?
错误(如果这是相关的,虽然我不希望修复我的代码 - 我有一个工作版本,我想了解版本的不同之处):
do return (try parseA <|> parseB)
给出
parse.hs:76:11:
Couldn't match expected type ‘Foo’
with actual type ‘Text.Parsec.Prim.ParsecT
[Char] () Data.Functor.Identity.Identity Foo’
和
do return $ try parseA <|> parseB
给出
parse.hs:76:3:
Couldn't match type ‘Text.Parsec.Prim.ParsecT
[Char] () Data.Functor.Identity.Identity Foo’
with ‘Foo’
Expected type: Parser Foo
Actual type: Text.Parsec.Prim.ParsecT
String
()
Data.Functor.Identity.Identity
(Text.Parsec.Prim.ParsecT
[Char] () Data.Functor.Identity.Identity Foo)
答案 0 :(得分:11)
rules for do notation desugaring暗示
do x <- try parseA <|> parseB
return x
相当于
(try parseA <|> parse B) >>= return
($)
与(>>=)
由于(=<<)
是(>>=)
的翻转版本,因此两者都等同于
return =<< (try parseA <|> parse B)
这意味着您的正确版本与return $ try parseA <|> parse B
之间的唯一区别是(=<<)
和($)
之间的差异,其类型为:
($) :: (a -> b) -> a -> b
(=<<) :: (a -> m b) -> m a -> m b
您可以看到($)
不是(=<<)
的替代品,但也许您也可以看到它们有些相似。查看它的一种方法是(=<<)
- 因此也(>>=)
- 是一种应用&#34; monadic函数的函数应用程序&#34;对于某些Monad a -> m b
到&#34; monadic值&#34;类型为m
的类型对于某些Monad m a
类型m
,而($)
是通常类型的函数应用程序,它将类型a -> b
的函数应用于类型a
的值。< / p>
monad laws中的一个就是那个
k >>= return = k
这意味着
(try parseA <|> parse B) >>= return
也可以写成
try parseA <|> parse B
这意味着使用do notation的原始表单也可以这样写。