2

在解决了 Project Euler 上的一个问题后,我在论坛中遇到了以下 Haskell 代码:

fillRow115 minLength = cache where
  cache = ((map fillRow115' [0 ..]) !!)
  fillRow115' 0 = 1
  fillRow115' cells = sum (map cache [0..cells-minLength]) + cache (cells-1)

我这周刚开始学习 Haskell,似乎无法理解这段代码。有人可以解释以下两项:

  1. 对我来说,它看起来只有一个参数minLength,但该函数需要 2 个参数才能在 ghci 中运行。这另一个论点在哪里发挥作用?
  2. 从我在网上可以找到!! 的是列表索引运算符,并在调用时返回第 n 个元素[list] !! n。上面的代码似乎只用一个参数调用它。那是在做什么?

PS如果有人想复制这段代码来解决Project Euler问题,它似乎没有给出正确的答案。

4

2 回答 2

5

这另一个论点在哪里发挥作用?

让我们进一步简化这个问题。您可能知道该head功能:

head [] = error "something bad"
head (x:_) = x

您可能很愚蠢并定义自己的 head 函数,该函数只调用head

myHead xs = head xs

注意左右两边都应用了变量xs,所以我们可以做所谓的 eta-reduction 并得到:

myHead = head

类型签名可能会敲定要点:

myHead :: [a] -> a
myHead = (head :: [a] -> a)

所以在你的情况下,fillRow115接受第二个参数,因为它等于cache,它接受一个参数 - 这将我们带到你的第二个问题。

上面的代码似乎只用一个参数调用它。那是在做什么?

考虑函数+。如果您希望创建一个始终添加 2 的函数,您可以“部分应用” 2 到该函数+

addTwo  = (+2)    -- (2+) would work just as well

因此,您正在查看列表索引功能!!

(!!) :: [a] -> Int -> a

并对自己说,这仅适用于某些列表。应用我们对部分应用的了解,我们得到一种:

(someList !!) :: Int -> a

所以这实际上是一个从 Ints 到列表元素的函数。

如果这还没有点击,只需替换someList为您正在使用的列表:

someList = map fillRow115' [0..]
(someList !!) === ((map fillRow 115' [0..]) !!)
于 2013-07-04T17:37:20.243 回答
2

这个概念被称为partial application
它之所以有效,是因为在 Haskell 中,所有函数实际上只有一个参数。
一个函数a -> b -> c可能看起来像一个带有两个参数
(一个是 a 类型,一个是 b 类型)的函数,但它实际上是一个函数a -> ( b -> c)
即一个带有一个参数(a 类型)的函数,它返回一个带有参数的函数 ( b) 类型。

请参阅http://www.haskell.org/haskellwiki/Partial_application
(或者只是一般地,给http://learnyouahaskell.com/去)

于 2013-07-04T17:28:12.140 回答