在哈斯克尔守卫和纯洁

时间:2015-09-11 21:44:11

标签: haskell

我正在阅读Dynamic programming example,有这样的代码:

buy n = r!n
    where r = listArray (0,n) (Just (0,0,0) : map f [1..n])
          f i = do (x,y,z) <- attempt (i-6)
                   return (x+1,y,z)
                `mplus`
                do (x,y,z) <- attempt (i-9)
                   return (x,y+1,z)
                `mplus`
                do (x,y,z) <- attempt (i-20)
                   return (x,y,z+1)
          attempt x = guard (x>=0) >> r!x

我的问题是attempt x = guard (x>=0) >> r!x是如何运作的?

根据此Control.Monad源代码,

guard True      =  pure ()
guard False     =  empty

pure :: a -> f a

m >> k = m >>= \_ -> k

所以如果x> 0,那么:

attempt x
    = (guard True) >> (r!x) = (pure ()) >> (r!x)
    = (pure ()) >>= \_ -> r!x = (f ()) >>= (\_ -> r!x)

因此f ()应该是m a类型(在这种情况下为Maybe a),但Haskell如何知道f是什么? f ()可能会返回empty,因为它从未被指定过。 (f表示纯粹的f

如果x <0,empty不在Maybe中,那么这仍然适用于>>=

2 个答案:

答案 0 :(得分:3)

这是一个多个问题,但让我们看看我是否可以让事情变得更清楚。

Haskell在解释f时如何知道pure ()是什么? pure是一个类型类方法,所以这只是来自我们所处类型的实例声明。这最近改变了,所以你可能必须按照不同的路径来达到答案,但结果最终会相同:pure for Maybe is defined as Just

以同样的方式,empty is in Maybe, and is defined as Nothing

通过在ghci提示符下键入:i pure:i empty,您将找到类型类提供这些功能的内容。那么你可以寻找实例声明Maybe为他们做的。

从SO的角度来看,这很不幸,最近发生了变化,所以在不知道你正在使用的特定版本的情况下,没有明确的永久答案。希望这很快就会解决。

答案 1 :(得分:2)

在您对attempt x的手动评估的最后一个表达中,您正在混淆类型和值。 pure :: a -> f a不是定义;它是一种类型签名(请注意::)。要完全引用它,pure类型是:

GHCi> :t pure
pure :: Applicative f => a -> f a

此处,f代表Applicative的任何实例,a代表任何类型。在您的情况下,您正在使用Maybe monad / applicative仿函数,因此fMaybepure ()的类型为Maybe ()。 (() :: ()是您对结果不感兴趣时​​使用的虚拟值。()中的pure ()是值,但()中的Maybe ()是一个类型 - ()值的类型。

我们将从您评估的最后一个正确步骤继续:

(pure ()) >>= \_ -> r!x
  

Haskell如何知道[pure ()]是什么?

从某种意义上说,它并不需要。这里使用pure ()的函数是(>>=)。它有以下类型:

GHCi> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b

m设置为Maybe,就像您的情况一样,我们得到:

Maybe a -> (a -> Maybe b) -> Maybe b

第一个参数的类型是Maybe a,因此(>>=)能够处理任何Maybe a值,包括pure (),无论它是否为{{} 1}} - 某事或Just。当然,它会处理NothingJust 不同,因为这是the Monad instance的全部要点:

Nothing

我们仍然需要完成评估。为此,我们需要了解(Just x) >>= k = k x Nothing >>= _ = Nothing 的{​​{1}}定义方式。我们可以在the Applicative instance of Maybe中找到定义:

pure

现在我们终于可以继续了:

Maybe