简体   繁体   English

初体验Monads(Haskell)

[英]First experience with monads (Haskell)

I apologize for the subject being unclear. 对于这个主题不清楚,我深表歉意。 I'm doing Haskell 99 as a beginner, and have encountered the concept of monad first time in my life in the solution to 67A . 我正在初学者学习Haskell 99,并且在我的67A解决方案中第一次遇到了monad的概念。 The part of the problem I'm struggling with is to define a function stringToTree that translates sequences like a(b,c) to a Tree : Branch a (Branch b Empty Empty) (Branch c Empty Empty) . 我苦苦挣扎的问题的一部分是定义一个函数stringToTree ,该函数将a(b,c)a(b,c)序列转换为TreeBranch a (Branch b Empty Empty) (Branch c Empty Empty)

I have tried several "soft" introductions to monads, and failed like many others. 我已经尝试了几种有关monad的“软”介绍,但与其他许多例子一样都失败了。 I hope by understanding this solution will finally lead me in-door, so I decided to give it a shot here. 我希望通过了解此解决方案最终能带领我进入室内,因此我决定在此进行尝试。

Questions 问题

  1. Would anyone briefly explain what the function stringToTree :: (Monad m) => String -> m (Tree Char) defined in the solution? 谁能简要解释一下解决方案中定义的函数stringToTree :: (Monad m) => String -> m (Tree Char)是什么? To make this question self-contained, I copied the code from there 为了使这个问题自成一体,我从那里复制了代码
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"
  1. Why is monad useful here? 为什么monad在这里有用? I hope to see how monads largely reduce the difficulties, of course only after one understands it, while defining this function. 我希望看到单子如何在定义此功能的同时大幅度减少困难,当然只有在了解了这一点之后。

In short, the definition lets the caller choose which monad to use. 简而言之,定义使呼叫者可以选择要使用的单声道。 This lets us customize how we deal with failure. 这使我们可以自定义处理失败的方式。 For example, we can use Maybe : 例如,我们可以使用Maybe

>>> stringToTree "" :: Maybe (Tree Char)
Just Empty
>>> stringToTree "9 +" :: Maybe (Tree Char)
Nothing

or [] : []

>>> stringToTree "" :: [Tree Char]
[Empty]
>>> stringToTree "9 +" :: [Tree Char]
[]

The code itself makes no assumptions about which monad is used; 该代码本身不假设使用哪个 monad。 it only uses >>= , return , and fail for working with the results of recursive calls. 它仅使用>>=return ,并且fail处理递归调用的结果。

Making the type String -> Tree Char would indicate that failure simply cannot happen; 键入String -> Tree Char表示失败根本不会发生。 every string has to produce a valid Tree Char value (or we raise a runtime error, which is something you should strive to avoid in Haskell). 每个字符串都必须产生一个有效的Tree Char值(否则我们会引发运行时错误,这是您在Haskell中应避免的事情)。

Note, though, that not all monads provide a definition of fail that avoids runtime errors. 但是请注意,并非所有monad都提供了避免运行时错误的fail定义。

>>> stringToTree "" :: Either () (Tree Char)
Right Empty
>>> stringToTree "9 +" :: Either () (Tree Char)
*** Exception: bad parse

Why monads are useful? 为什么monad有用? Some broader context. 一些更广泛的背景。

Monads are a unification of several things that traditionally have been handled by different language mechanisms. Monad是传统上由不同语言机制处理的几件事的统一 Among them are 其中有

  • Sequencing (like in IO or State) 排序(例如在IO或状态下)

  • Non-determinism (like in the list monad) 非确定性(例如清单monad)

  • Failure and exceptions (like in Maybe) 失败和异常(例如Maybe)

  • Saving and resuming computations (the Cont monad, which you will encounter in the future) 保存和恢复计算(将来会遇到的Cont monad)

  • Atomic transactions (the STM monad) 原子交易(STM monad)

  • Parsing (Parsec and its relatives) 解析(Parsec及其亲属)

By "unification" I mean the kind of thing that Newton did when he unified the laws of physics for things on Earth and things in the sky, or when Maxwell unified electricity and magnetism into the electromagnetic field; 所谓“统一”,是指牛顿将地球上和天空中的事物的物理定律统一起来,或者将麦克斯韦将电磁力统一到电磁场中时所做的事情。 its a deeper underlying theory which yields all of the above as special cases and shows how you can create new things along the same lines. 它是一种更深层的基础理论,将以上所有内容作为特殊情况进行了介绍,并展示了如何沿着相同思路创造新事物。

In monads the type of the "bind" function (>>=) is the central equation in the theory; 在monad中,“ bind”函数的类型(>>=)是理论中的中心方程; it describes how one step in the computation can be daisy-chained on to the next. 它描述了如何将计算的一个步骤以菊花链方式链接到下一个步骤。 return is the primitive null step. return是原始的空步骤。 This is something you get used to in Haskell; 这是您在Haskell中习惯的; everything has some kind of zero or null or identity value. 一切都有某种零或空或身份值。 fail is a step that doesn't work, which (as @chepner says in a comment elsewhere) is needed for partial functions. fail是不起作用的步骤,部分功能需要该步骤(如@chepner在其他评论中所述)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM