So I'm writing a line to get the second to last element of a list. Initially my code was
mySLast x = last.take ((length x) - 1) x
Which worked up until the last
function. Realized the my take
business is already included in Haskell as init
so I rewrote as
mySLast = last.init
This still doesn't work. I find this puzzling because init::[a]->[a]
and last::[a]->a
so they definitely should be composable morphisms in the Hask Category.
I tried asking Haskell what it thinks the type is and it said
ghci> :t last.init
last.init :: [c] -> c
ghci> last.init [3,2,4,1]
<interactive>:45:6:
Couldn't match expected type ‘a -> [c]’
with actual type ‘[Integer]’
Relevant bindings include
it :: a -> c (bound at <interactive>:45:1)
Possible cause: ‘init’ is applied to too many arguments
In the second argument of ‘(.)’, namely ‘init [3, 2, 4, 1]’
In the expression: last . init [3, 2, 4, 1]
Even though
ghci> init [3,2,4,1]
[3,2,4]
ghci> last [3,2,4]
4
So I must be misunderstanding something about composing functions in Haskell. Any insight would be greatly appreciated!
Function application binds more tightly than (.)
so
last.init [3,2,4,1]
is being parsed as
last . (init [3,2,4,1])
you can use
(last . init) [3,2,4,1]
or
last . init $ [3,2,4,1]
You forgot the $
between init and your list, eg
last . init $ [3,2,4,1]
↑ See here
An alternative solution to this problem that only evaluates the (spine of the) list up to the needed element, rather than using length (which will evaluate the entire spine before walking back to the needed element):
takeTail n xs = go (drop n xs) xs
where
go (_:ys) (_:xs) = go ys xs
go [] xs = xs -- Stop and return xs when ys runs out
> head . takeTail 2 $ [1,2,3,4]
3
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.