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 Int
s 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
精彩评论