unoldr中的lambda函数如何与Haskell中的两个参数一起使用?

时间:2016-10-22 00:24:15

标签: haskell types lambda functional-programming unfold

阅读this article时,我找到了使用unfoldr函数生成斐波纳契数列的示例:

fibs = unfoldr (\(a,b) -> Just (a,(b,a+b))) (0,1)

但是当我查看documentation时,我发现unfoldr函数中的lambda只接受一个参数b

unfoldr :: (b -> Maybe (a, b)) -> b -> [a]

doc中的示例也只显示了一个参数:

unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10

所以,我很感兴趣如何将它应用于斐波那契例子中的两个参数?

2 个答案:

答案 0 :(得分:6)

这是你的功能:

GHCi> let foo = \(a,b) -> Just(a,(b,a+b))

虽然我们当然可以将它解释为两个参数的函数,但就Haskell而言,只需要一个参数......

foo :: Num t => (t, t) -> Maybe (t, (t, t))
对于(t, t)类中的某些t

...类型Num。那么,您的示例中的所有内容都是b的签名中的unfoldrNum t => (t, t)替换,而aNum t => t取代,结果是:

Num t => ((t, t) -> Maybe (t, (t, t))) -> (t, t) -> [t]

一些额外的证据:

GHCi> :t unfoldr (\(a,b) -> Just (a,(b,a+b)))
unfoldr (\(a,b) -> Just (a,(b,a+b))) :: Num a => (a, a) -> [a]

回答你的问题时,这里有一点题外话。将两个参数传递给Haskell函数的另一种方法是将它们分开传递,而不是成对传递:

GHCi> let foo2 a b = Just(a,(b,a+b))
GHCi> :t foo2
foo2 :: Num t => t -> t -> Maybe (t, (t, t))

显然,如果你仍然有foo,你甚至不需要重写实现:

GHCi> let foo2 a b = foo (a, b)
GHCi> :t foo2
foo2 :: Num t => t -> t -> Maybe (t, (t, t))

事实上,这种转换 - 用行话称为 currying - 总是可能,甚至还有一个功能......

GHCi> let foo2 = curry foo
GHCi> :t foo2
foo2 :: Num t => t -> t -> Maybe (t, (t, t))

......以及另一个朝着相反方向前进的人:

GHCi> :t uncurry foo2
uncurry foo2 :: Num t => (t, t) -> Maybe (t, (t, t))

然而,令人惊讶的是,foo2甚至更像是两个参数的函数而不是foo,它仍然是一个参数的函数!诀窍是像foo2 ...

那样的签名
foo2 :: Num t => t -> t -> Maybe (t, (t, t))

...有一些省略的可选括号。遗漏掩盖了函数箭头->是右关联的事实。如果我们添加它们,我们会得到:

foo2 :: Num t => t -> (t -> Maybe (t, (t, t)))

也就是说,foo2接受一个参数(也就是我们的第一个参数)并返回另一个也接受一个参数的函数(即我们的第二个参数)。

然后,主要的好处是所有Haskell函数只需要一个参数。幸运的是,编写像两个参数一样工作的函数非常容易。通常,这是通过以curry方式编写函数(即,像foo2返回另一个函数的函数)来完成的,但有时在一对中传递多个值是必要或方便的,正如你在你的例子中所做的那样。

答案 1 :(得分:-1)

首先,unforldr适用于func((a,b) - > Just(a,(b,a + b)))

返回函数b - > [一个]。这是一个讨论。

然后将结果函数应用于第二个参数(0,1)

结束最终结果。