繁体   English   中英

Haskell中没有“长度”函数的列表的长度

[英]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

您的程序看起来非常“ 必要 ”:您定义了变量y ,然后以某种方式编写了一个do ,它调用(?) list函数(?),该函数似乎自动“返回y ”,然后您想要递增y

那不是Haskell(以及大多数功能性和声明性)语言的工作方式:

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

为了对Haskell(或任何功能性语言)进行编程,您需要“考虑功能性”:思考如何使用函数数学方式解决问题。

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

胶乳

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

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

现在在Haskell中,通常还使用累加器来执行尾部递归 :您通过递归调用传递参数,并且每次更新变量时都会传递该参数。 递归结束时,有时会经过一些后处理后返回累加器。

在这种情况下,累加器将是迄今为止看到的长度,因此您可以编写:

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

看起来您仍然以命令式的方式(而不是功能性的方式)思考。 例如:

  • 您尝试更改“变量”(即y++ )的值
  • 您尝试在list函数的主体中使用“全局变量”(即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数值。 实际上,可以通过使用以下声明来创建函数的更多“不可知论”版本:

my_length :: [a] -> Integer

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

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

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

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

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

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

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

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

sum . map (const 1)

为了提高速度:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM