haskell 函数声明

haskell function declaration

我一直在玩haskell,我发现如果我在代码文件中编写以下函数:

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

那么这完全没问题。自然地,我认为没有参数的代码看起来会更好。

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

但是当我尝试将其加载到 gchi 时会产生错误

1
2
3
4
5
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)

失败,加载模块:无。

我有点搞不懂这怎么会发生...


你误解了优先级。这:

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

解析如下:

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

不是(如你所想)这样:

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

$ 的优先级是所有运算符中最低的,而函数调用的优先级最高。 . 具有第二高,因此 (take . succ) 在绑定到 last $ 之前绑定到它的参数 (idx str)。

此外,该函数(在它编译时)并没有按照您希望的那样执行。它递增 idx,然后从字符串中获取该字符。如果那是您想要的,为什么在 (+1) 有效时使用 succ ?您已经将类型限制为整数。

正如所写,您的函数与 !! 运算符相同 - 它只是一个数组索引函数。这是你想要的吗?或者你想 succ 给定索引处的项目?您可以通过以下方式完成:

1
2
3
4
5
6
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)

我仍在制作一个没有书面论据的版本。也许编写工作代码更重要? ;)


当您尝试将 last(take . succ)

组合时会发生这种情况

1
2
3
4
5
6
7
8
: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]

b 的类型从 last 推断为 [t],但它无法与 (take . succ) 中的 b 类型匹配,即 [t] -> [t]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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