开发者

Haskell type math problem

I'm haskell beginner. I try to write function that's will return penultimate list element.

I start so:

lastButOne :: [a] -> a
lastButOne list = if null list
           then 
                0
           else 
                length list

0 string i get error:

Couldn't match type `a' with `Int'
      `a' is a rigid type variable bound by
          the type signature for lastButOne :: [a] -> a

I understand it. 开发者_StackOverflow中文版But what can i do here? I don't know list type. What can i put here?

Thank you.


0 is of type int, so it won't work for all a. I would suggest instead to use Maybe a like so:

lastButOne :: [a] -> Maybe a
lastButOne [] = Nothing
lastButOne [x] = Nothing
lastButOne xs = Just $ list !! (length xs - 2)

Using guards:

lastButOne :: [a] -> Maybe a
lastButOne xs | length xs > 1 = Just $ list !! (length list - 2)
              | otherwise = Nothing

Using the MonadPlus instance of Maybe:

import Control.Monad (guard)

lastButOne :: [a] -> Maybe a
lastButOne list = guard (length list > 1) >> return (list !! (length list - 2))

In general, for any instance of MonadPlus:

import Control.Monad (guard)

lastButOne :: MonadPlus m => [a] -> m a
lastButOne list = guard (length list > 1) >> return (list !! (length list - 2))

Although somewhere you will have to specify to the compiler that you want the result as a Maybe. Usually this will be type inferred because it will be passed to a function expecting a Maybe.

Please keep in mind that this runs in O(n). You probably don't want to be finding the penultimate element of a list... Why do you need to do this? At least consider using an array instead.


The signature says "This function takes a list with elements of any type, and returns a value of the same element all the elements of the list". The code, on the other hand, says "This function takes a list with elements of any type, and returns a number". The correct type signature for that would be [a] -> Int* ("This function takes a list with elements of any type, and returns a value of any type that's a Num").

But since you want to return the second-to-last element instead of the length of the list, the type signature is correct but the code isn't. You have to take some item from the list, or somehow (error, using a Maybe return type, using pattern matchign and just omitting clauses for those cases, returning undefined :: a) handle lists that don't have a second-to-last element because they have less than two elements.

(*) It would be (Integral b) => [a] -> b if the prelude length wasn't bent on giving out only Ints for performance.


I'm also new to Haskell. I think your problem is the 0 in your code. I don't really know how to fix it, but here is my solution, hope it's helpful:

lastButOne :: [a] -> a

lastButOne [] = error "empty list"
lastButOne [x1] = error "only one element"
lastButOne [x1,x2] = x1
lastButOne (x:xs) = lastButOne xs

the function removes elements from beginning until there are 2 elements left, then the first of these two is the last-But-One.


Ostentatious solution

lastButOne :: [a] -> a
lastButOne [] = error "empty list"
lastButOne [x] = x
lastButOne xs = head $ drop 1 $ reverse xs
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜