[英]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(以及大多数功能性和声明性)语言的工作方式:
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
可能最简单的方法是将所有元素转换为1
,然后对新元素求和:
sum . map (const 1)
为了提高速度:
foldl' (+) 0 . map (const 1)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.