我想看看列表有多长,但没有使用 length
这个函数。我写了这个程序,它不起作用。也许你可以告诉我为什么?谢谢!
let y = 0
main = do
list (x:xs) = list (xs)
y++
list :: [Integer] -> Integer
list [] = y
答案 0 :(得分:5)
Your program looks quite "imperative": you define a variable y
, and then somehow write a do
, that calls (?) the list
function (?) that automagically seems to "return y
" and then you want to increment y
.
That's not how Haskell (and most functional and declarative) languages work:
do
usually is used for monads, whereas the length
is a pure function,let
is a syntax construction to define a variable within the scope of an expression,In order to program Haskell (or any functional language), you need to "think functional": think how you would solve the problem in a mathematical way using only functions.
In mathematics, you would say that the empty list []
clearly has length 0
. Furthermore in case the list is not empty, there is a first element (the "head") and remaining elements (the "tail"). In that case the result is one plus the length of the tail. We can convert that in a mathematical expression, like:
Now we can easily translate that function into the following Haskell code:
ownLength :: [a] -> Int
ownLength [] = 0
ownLength (_:xs) = 1 + ownLength xs
Now in Haskell, one usually also uses accumulators in order to perform tail recursion: you pass a parameter through the recursive calls and each time you update the variable. When you reach the end of your recursion, you return - sometimes after some post-processing - the accumulator.
In this case the accumulator would be the so far seen length, so you could write:
ownLength :: [a] -> Int
ownLength = ownLength' 0
where ownLength' a [] = a
ownLength' a (_:xs) = ownLength' (a+1) xs
答案 1 :(得分:4)
It looks you still think in an imperative way (not the functional way). For example:
y++
)y
) in the body of the list
functionHere is the possible solution to your problem:
main = print $ my_length [1..10]
my_length :: [Integer] -> Integer
my_length [] = 0
my_length (_:xs) = 1 + my_length xs
You can also run this code here: http://ideone.com/mjUwL9.
Please also note that there is no need to require that your list consists of Integer
values. In fact, you can create much more "agnostic" version of your function by using the following declaration:
my_length :: [a] -> Integer
Implementation of this function doesn't rely on the type of items from the list, thus you can use it for a list of any type. In contrast, you couldn't be that much liberal for, for example, my_sum
function (a potential function that calculates the sum of elements from the given list). In this situation, you should define that your list consists of some numerical type items.
At the end, I'd like to suggest you a fantastic book about Haskell programming: http://learnyouahaskell.com/chapters.
答案 2 :(得分:2)
其他答案已经很好地解释了正确的功能方法。它看起来像是一种矫枉过正,但这是通过仅使用可用的高阶函数来实现length
函数的另一种方法。
my_length :: [a] -> Integer
my_length = foldr (flip $ const . (+1)) 0
答案 3 :(得分:0)
最简单的方法可能是将所有元素都转换为1
,然后对新元素求和:
sum . map (const 1)
要提高速度:
foldl' (+) 0 . map (const 1)