“< - ”和相关值

时间:2012-04-18 07:32:11

标签: haskell monads

说我写了以下amazin代码:

func = do
  a <- Just 5
  return a

我知道,这是毫无意义的。在此,a5func返回Just 5

现在我改写了我很棒的(但没有意义的)功能:

func' = do
  a <- Nothing
  return a

这个函数返回Nothing,但到底是什么a?没有什么可以从Nothing值中提取,但是当我做这样的事情时程序不会抱怨:

func'' = do
  a <- Nothing
  b <- Just 5
  return $ a+b

我很难看到实际发生的事情。什么是a?换句话说:<- 实际做什么?说它“从右侧提取值并将其绑定到左侧”显然过度简化了它。我没有得到什么?

谢谢:)

5 个答案:

答案 0 :(得分:11)

让我们尝试去除最后一个例子的记号。

func'' = Nothing >>= (\a -> Just 5 >>= (\b -> return $ a+b))

现在,让我们看看如何为Maybe定义&gt;&gt; =。它出现在序曲中:

instance  Monad Maybe  where
    (Just x) >>= k   =  k x
    Nothing  >>= k   =  Nothing
    return           =  Just
    fail s           =  Nothing

所以Nothing >>= foo只是Nothing

答案 1 :(得分:6)

答案在于Monad Maybe实例的定义:

instance Monad Maybe where
   (Just x) >>= k      = k x
   Nothing  >>= _      = Nothing
   (Just _) >>  k      = k
   Nothing  >>  _      = Nothing
   return              = Just

您的func''转换为:

Nothing >>= (\a -> (Just 5 >>= (\b -> return (a+b))))

(>>=)的定义中,您可以看到第一个Nothing只是通过了结果。

答案 2 :(得分:5)

让我们看一下Maybe monad的定义。

instance Monad Maybe where
  return = Just

  Just a  >>= f = f a
  Nothing >>= _ = Nothing

并且在你的函数中使用do - 符号:

func' =
  Nothing >>= \a ->
  return a

>>=的第一个参数是Nothing,从上面的定义我们可以看出>>=只是忽略了第二个参数。所以我们得到:

func' = Nothing

由于永远不会调用函数\a -> ...,因此永远不会分配a。所以答案是:a甚至没有达到。


关于desugaring do - 符号,这里有一个快速草图,说明它是如何完成的(我已经做了一个简化 - 处理fail,即模式不匹配):

do {a; rest} → a >> do rest

请注意,>>通常以>>=a >>= \_ -> do rest实现(即第二个函数忽略参数)。

do {p <- a; rest} → a >>= \p -> do rest

do {let x = a; rest} → let x = a in do rest

最后:

do {a} = a

以下是一个例子:

main = do
  name <- getLine
  let msg = "Hello " ++ name
  putStrLn msg
  putStrLn "Good bye!"
去往:

main =
  getLine >>= \name ->
  let msg = "Hello " ++ name in
  putStrLn msg >>
  putStrLn "Good bye!"

为了让那些好奇的人完整,这里是do {p <- a; rest}的“正确”翻译(直接取自Haskell报告):

do {pattern <- a; rest} → let ok pattern = do rest
                              ok _       = fail "error message"
                          in  a >>= ok

答案 3 :(得分:2)

Nothing并非真的“没有”,它实际上是Maybe monad中某些内容的可能价值:

data Maybe t = Nothing | Just t

也就是说,如果某些类型Maybe t的类型为t,则其值Just x(其中x为{{1}类型}}) t;在这个意义上,Nothing只是扩展Maybe以获得另一个可能的值t。 (它有其他属性,因为它是monad,但除了Nothingdo的句法糖之外,这并不是我们真正关心的问题。)

答案 4 :(得分:1)

我们举个例子:

func = do
  a <- Just 5
  return a

就像在其他编程语言中一样,你可以把它分成两部分,对应于“到目前为止做了什么”和“还有什么要做”。例如,我们可以在Just 5

之间进行中断
a <- ...
return a

在许多流行的编程语言中,您希望将Just 5填充到变量a中,代码将继续。

Haskell做了不同的事情。 “代码的其余部分”可以被认为是一个函数,描述了如果你有一个值可以用a做什么。然后将此函数应用于Just 5。但它并没有直接应用。它适用于>>=适用的任何定义,具体取决于表达式的类型。对于Maybe,定义了>>=,以便在处理Just X时,“其余代码”功能应用于X。但它也被定义为在处理Nothing时,“代码的其余部分”功能被忽略,并返回Nothing

我们现在可以解释您的其他示例

func'' = do
  a <- Nothing
  b <- Just 5
  return $ a+b

将其分为Nothing和:

  a <- ...
  b <- Just 5
  return $ a+b

正如我上面所说,这段代码可以被认为是应用于a的可能值的函数。但它与Nothing一起使用,在这种情况下,>>=被定义为忽略“其余代码”并返回Nothing。这就是你得到的结果。