【问题标题】:Haskell: Understanding the bind operator (>>=) for MonadsHaskell:了解 Monad 的绑定运算符 (>>=)
【发布时间】:2019-07-15 20:28:17
【问题描述】:

我有以下功能:

parse :: String -> Maybe Token

我正在尝试实现以下功能:

maketokenlist :: String -> Maybe [Token]

如果存在无法解析的标记,则该函数返回 Nothing(即,如果标记不是整数或算术运算符,则 parse 返回 Nothing),否则返回 Token 列表。

由于 Maybe 是 Monad 类型类的一个实例,我有以下方法:

maketokenlist str =  return (words str) >>= parse

我将字符串转换为单个标记的列表(例如 "2 3 +" 变为 ["2","3","+"] ,然后将解析函数映射到列表中的每个字符串。

由于列表的 Monad 实例被定义为:

instance Monad [] where
   return x = [x] 
   xs >>= f = concat (map f xs)
   fail _ = []

但是,假设我有字符串列表 [2, 3, "+", "a"] 并且在使用 >>= 映射解析每个元素后,我得到 [Just 2, Just 3, Just (+) , Nothing],因为“a”无法解析。有没有办法只使用 >>= 运算符使函数 maketokenlist 返回 Nothing?任何见解都值得赞赏。

【问题讨论】:

  • [2, 3, "+", "a"],这既不是一个列表,也不是任何在 Haskell 中有意义的构造。列表必须由单一类型组成,例如[a]。所以你可以有[2,3]["+","a"]。重新考虑问题,然后重试。
  • return 将其参数包装在 monad 中,>>= 立即将其解包。所以return (words str) >>= parse 等价于parse (words str)。您是否有理由需要使用>>=,而不是maketokenlist str = map parse (words str)

标签: haskell functional-programming monads


【解决方案1】:

如果parse :: String -> Maybe Token,那么:

traverse parse :: [String] -> Maybe [Token]

这个版本的traverse(我专门将它作为Traversable 实例和Maybe 作为Applicative 实例作用于列表)确实可以使用(>>=) 来实现:

listMaybeTraverse parse [] = pure []
listMaybeTraverse parse (s:ss) =
    parse s >>= \token ->
    listMaybeTraverse parse ss >>= \tokens ->
    pure (token:tokens)

我选择了名称parsestoken 来显示与您计划使用的对应关系,但当然它适用于任何适当类型的函数,而不仅仅是parse

列表的Monad 实例没有出现在此代码中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    • 2013-05-16
    相关资源
    最近更新 更多