开发者

haskell function declaration

开发者 https://www.devze.com 2023-02-13 02:05 出处:网络
I have been pl开发者_StackOverflowaying around with haskell and I found out that if I write the following function in a code file:

I have been pl开发者_StackOverflowaying around with haskell and I found out that if I write the following function in a code file:

f :: Int -> [a] -> a
f idx str = last $ (take . succ) idx str

then this works totally fine. Naturally, I figured the code would look better without the arguments.

f :: Int -> [a] -> a
f = last $ (take . succ)

But this generates an error when I try to load it into gchi

Couldn't match expected type `[a]'
       against inferred type `Int -> [a1] -> [a1]'
In the second argument of `($)', namely `(take . succ)'
In the expression: last $ (take . succ)
In the definition of `f': f = last $ (take . succ)

Failed, modules loaded: none.

I'm kind of confused about how this could be happening...


You're misunderstanding the precedence. This:

f idx str = last $ (take . succ) idx str

Is parsed like this:

f idx str = last $ ( (take . succ) idx str )

Not (as you think) like this:

f idx str = ( last $ (take . succ) ) idx str

$ has extremely the lowest precedence of any operator, and function calling has extremely the highest. . has the second highest, so (take . succ) binds to it's arguments (idx str) before it binds to last $.

Furthermore, the function (as it compiles) doesn't do what it looks like you want it to do. It increments idx, then takes that character from the string. If that's what you want, why use succ when (+1) works? You've already restricted the type to integers.

As written, your function is identical to the !! operator - it's just an array index function. Is this what you want? Or do you want to succ the item at the given index? You could accomplish that with the following:

f :: Enum a => Int -> [a] -> a
f idx str = succ $ str !! idx
-- or
f idx str = succ $ (!!) str idx
-- or, only one argument
f idx = succ . (!! idx)

I'm still working on a version with no written arguments. Perhaps it's more important to write working code? ;)


This is what happens when you try to compose last with (take . succ)

:t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

last :: [t] -> t  ~ (b -> c)  
-- so b ~ [t] and c ~ t   

(take . succ) :: Int -> [t] -> [t]  
-- so a ~ int and b ~ [t] -> [t]  

Type of b is inferred to be [t] from last but it couldn't match against the type of b in (take . succ) which is [t] -> [t]


f idx str = last $ (take . succ) idx str
-- applying definition of ($)
f idx str = last ((take . succ) idx str)
-- adding parentheses for clarity
f idx str = last (((take . succ) idx) str)
-- using definition of (.)
f idx str = (last . (take . succ) idx) str
-- η-conversion
f idx = last . (take . succ) idx
-- infix to prefix notation
f idx = (.) last ((take . succ) idx)
-- ading parentheses for clarity
f idx = ((.) last) ((take . succ) idx)
-- using definition of (.)
f idx = ((.) last . (take . succ)) idx
-- η-conversion
f = (.) last . (take . succ)
-- remove parentheses: (.) is right-associative
f = (.) last . take . succ
0

精彩评论

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