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 并求和。
我想看看一个列表有多长,但是没有使用函数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 并求和。