Haskell 中没有 "length" 函数的列表长度

The length of a list without the "length" function in Haskell

我想看看一个列表有多长,但是没有使用函数length。我写了这个程序,但它不起作用。也许你能告诉我为什么?谢谢!

let y = 0
main = do
  list (x:xs) = list (xs)
  y++

list :: [Integer] -> Integer
list [] = y

看来你还是用命令式的方式思考(不是函数式的方式)。例如:

  • 您尝试更改 "variable" 的值(即 y++
  • 您尝试在 list 函数的主体中使用 "global variable"(即 y

以下是您的问题的可能解决方案:

main = print $ my_length [1..10]

my_length :: [Integer] -> Integer
my_length [] = 0
my_length (_:xs) = 1 + my_length xs

您也可以在此处 运行 此代码:http://ideone.com/mjUwL9

另请注意,没有必要要求您的列表包含 Integer 个值。事实上,您可以使用以下声明创建更多 "agnostic" 版本的函数:

my_length :: [a] -> Integer

此函数的实现不依赖于列表中项目的类型,因此您可以将它用于任何类型的列表。相反,对于 my_sum 函数(计算给定列表中元素总和的潜在函数),您不能那么自由。在这种情况下,您应该定义您的列表由一些数字类型的项目组成。

最后,我想向您推荐一本关于 Haskell 编程的好书:http://learnyouahaskell.com/chapters

你的程序看起来很“势在必行”:你定义了一个变量y,然后以某种方式写了一个do,调用(?) list 函数 (?) 似乎自动 "return y" 然后你想增加 y.

这不是 Haskell(以及大多数函数式和声明式)语言的工作方式:

  • 在声明式语言中,您只定义一个变量一次,设置值后,通常无法更改其值,
  • 在Haskell中,do通常用于单子,而length是一个函数,
  • let是在表达式范围内定义变量的语法结构,
  • ...

为了编程Haskell(或任何函数式语言),您需要"think functional":思考如何用数学解决问题仅使用 函数的方法 .

在数学中,你会说空列表[]显然有长度0。此外,如果列表不为空,则有第一个元素("head")和其余元素("tail")。在这种情况下,结果是尾部长度加一。我们可以将其转换为数学表达式,例如:

现在我们可以轻松将该函数转换为以下 Haskell 代码:

ownLength :: [a] -> Int
ownLength [] = 0
ownLength (_:xs) = 1 + ownLength xs

现在Haskell,通常也使用累加器来执行尾递归:你传递一个参数通过递归调用以及每次 更新 变量。当你到达递归的末尾时,你 return - 有时在一些 post 处理之后 - 累加器。

在这种情况下,累加器将是目前看到的长度,因此您可以这样写:

ownLength :: [a] -> Int
ownLength = ownLength' 0
    where ownLength' a [] = a
          ownLength' a (_:xs) = ownLength' (a+1) xs

其他答案已经很好地解释了正确的功能方法。这看起来有点矫枉过正,但这是另一种实现 length 函数的方法,它只使用可用的高阶函数。

my_length :: [a] -> Integer
my_length = foldr (flip $ const . (+1)) 0

可能最简单的方法是将所有元素转换为1,然后对新元素求和:

sum . map (const 1)

增加速度:

foldl' (+) 0 . map (const 1)

我在 Learn you a haskell 中找到了这个解决方案。

length' xs = sum [1 | _ <- xs]

它将列表中的每个元素替换为 1 并求和。