[英]First experience with monads (Haskell)
对于这个主题不清楚,我深表歉意。 我正在初学者学习Haskell 99,并且在我的67A解决方案中第一次遇到了monad的概念。 我苦苦挣扎的问题的一部分是定义一个函数stringToTree
,该函数将a(b,c)
类a(b,c)
序列转换为Tree
: Branch a (Branch b Empty Empty) (Branch c Empty Empty)
。
我已经尝试了几种有关monad的“软”介绍,但与其他许多例子一样都失败了。 我希望通过了解此解决方案最终能带领我进入室内,因此我决定在此进行尝试。
stringToTree :: (Monad m) => String -> m (Tree Char)
是什么? 为了使这个问题自成一体,我从那里复制了代码 stringToTree :: (Monad m) => String -> m (Tree Char)
stringToTree "" = return Empty
stringToTree [x] = return $ Branch x Empty Empty
stringToTree str = tfs str >>= \ ("", t) -> return t
where tfs a@(x:xs) | x == ',' || x == ')' = return (a, Empty)
tfs (x:y:xs)
| y == ',' || y == ')' = return (y:xs, Branch x Empty Empty)
| y == '(' = do (',':xs', l) <- tfs xs
(')':xs'', r) <- tfs xs'
return $ (xs'', Branch x l r)
tfs _ = fail "bad parse"
monad
在这里有用? 我希望看到单子如何在定义此功能的同时大幅度减少困难,当然只有在了解了这一点之后。 简而言之,定义使呼叫者可以选择要使用的单声道。 这使我们可以自定义处理失败的方式。 例如,我们可以使用Maybe
:
>>> stringToTree "" :: Maybe (Tree Char)
Just Empty
>>> stringToTree "9 +" :: Maybe (Tree Char)
Nothing
或[]
:
>>> stringToTree "" :: [Tree Char]
[Empty]
>>> stringToTree "9 +" :: [Tree Char]
[]
该代码本身不假设使用哪个 monad。 它仅使用>>=
, return
,并且fail
处理递归调用的结果。
键入String -> Tree Char
表示失败根本不会发生。 每个字符串都必须产生一个有效的Tree Char
值(否则我们会引发运行时错误,这是您在Haskell中应避免的事情)。
但是请注意,并非所有monad都提供了避免运行时错误的fail
定义。
>>> stringToTree "" :: Either () (Tree Char)
Right Empty
>>> stringToTree "9 +" :: Either () (Tree Char)
*** Exception: bad parse
为什么monad有用? 一些更广泛的背景。
Monad是传统上由不同语言机制处理的几件事的统一 。 其中有
排序(例如在IO或状态下)
非确定性(例如清单monad)
失败和异常(例如Maybe)
保存和恢复计算(将来会遇到的Cont monad)
原子交易(STM monad)
解析(Parsec及其亲属)
所谓“统一”,是指牛顿将地球上和天空中的事物的物理定律统一起来,或者将麦克斯韦将电磁力统一到电磁场中时所做的事情。 它是一种更深层的基础理论,将以上所有内容作为特殊情况进行了介绍,并展示了如何沿着相同思路创造新事物。
在monad中,“ bind”函数的类型(>>=)
是理论中的中心方程; 它描述了如何将计算的一个步骤以菊花链方式链接到下一个步骤。 return
是原始的空步骤。 这是您在Haskell中习惯的; 一切都有某种零或空或身份值。 fail
是不起作用的步骤,部分功能需要该步骤(如@chepner在其他评论中所述)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.