简体   繁体   中英

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

I want to see how long a list is, but without using the function length . I wrote this program and it does not work. Maybe you can tell me why? Thanks!

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

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

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:

  • in a declarative language, you define a variable only once, after the value is set, there is usually no way to alter its value,
  • in Haskell a do usually is used for monads, whereas the length is a pure function,
  • the 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

It looks you still think in an imperative way (not the functional way). For example:

  • you try to change the value of a "variable" (ie y++ )
  • you try to use "global variable" (ie y ) in the body of the list function

Here 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 .

Other answers have already beautifully explained the proper functional approach. It looks like an overkill but here is another way of implementing the length function by using only available higher order functions.

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

I've found this solution in Learn you a haskell .

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

It replaces every element of the list with 1 and sums it up.

Probably the simplest way is to convert all elements to 1 and then to sum the new elements:

sum . map (const 1)

For added speed:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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