haskell function declaration
我一直在玩haskell,我发现如果我在代码文件中编写以下函数:
那么这完全没问题。自然地,我认为没有参数的代码看起来会更好。
但是当我尝试将其加载到 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 迫使我克服完全缺乏注意力并思考 Haskell,这是我几个月没有看过的。希望我可以更加专注并将我的答案改进为更有用的东西。
-
作为一个经验法则:如果你想摆脱(两边)尾随参数,用 . 替换所有顶级 $ (这仅适用于"简单"情况)
你误解了优先级。这:
解析如下:
不是(如你所想)这样:
$ 的优先级是所有运算符中最低的,而函数调用的优先级最高。 . 具有第二高,因此 (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 ) |
我仍在制作一个没有书面论据的版本。也许编写工作代码更重要? ;)
- 是的,这一切都是正确的。除非您认为 "with type" :: 是一个运算符,它的优先级低于 ($)。
-
@luqui - 是的,我自己在验证这一点。不过,很高兴了解 ::。将其设为最低优先级是有意义的。它被认为是运营商吗?
-
@Chris,技术上没有;它在语法中占有特殊的位置。
-
我实际上是在尝试复制 (!!) 运算符而不使用书面参数。我是一个haskell newb,我认为这可能是一个有趣的练习。如果您尝试 f 20 [1..10] 之类的方法,此版本将无法引发异常,因此它绝对不正确。
-
@chuck taylor - 啊。我想知道你为什么要尝试复制它。我个人使用模式匹配。而且我认为说它"绝对不正确"并不是很好,因为您没有指定任何要求。如果你试图重新实现内置行为,你应该马上说出来。否则你会得到很多答案(比如我的)告诉你不要那样做。
-
@chris lutz-我的意思是我在问题中定义的函数作为 (!!) 的实现肯定是不正确的,这是我自己的错。我没有提出它最初是对 (!!) 的尝试,因为我注意到它实际上并没有与优先级问题分开,我不想分散注意力。
当您尝试将 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 |