Phi*_*lip 1 haskell types type-inference instance
我是Haskell的初学者.我有这个功能
test f xs
| length xs == 0 = []
| f (head xs) = head xs : test f (tail xs)
| otherwise = test f (tail xs)
Run Code Online (Sandbox Code Playgroud)
此函数应该从列表xs的每个元素中创建一个列表,该列表与f值匹配,但它会返回错误:
test 1 [1,2]
ERROR - Cannot infer instance
*** Instance : Num (a -> Bool)
*** Expression : test 1 [1,2]
Run Code Online (Sandbox Code Playgroud)
这部分:
| f (head xs)
Run Code Online (Sandbox Code Playgroud)
应该是Bool但是呢?它是否作为过滤器工作?如何使此功能起作用?提前致谢.
显然,f它是一种谓词:您将它应用于列表中的值,并产生一个布尔值.所以类型test是
test :: (a -> Bool) -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)
BTW的标准名称是filter.
如果你自己不确定签名,你可以问GHCi
> :t test
test :: (a -> Bool) -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)
...但我强烈建议从签名开始:先考虑一下你希望你的功能完成什么,然后担心实现.
无论如何,要测试test函数,你需要给它一个(a -> Bool)函数和一个列表.是1功能吗?我不敢†因此test 1 [1,2]无法理解.你可能意味着什么test (\x -> x==1) [1,2],也可以简单地写test (==1) [1,2].
关于您的代码的几点评论:
length- 这需要遍历整个列表.你可以使用这个null功能 - 检查容器是否为空............但是仍然存在实际从列表中取出值的问题.您确实可以使用非空列表的第一个值head,但这只在您首次检查它是非空的分支中是安全的.这很容易出错.一个更好的解决方案是在列表头上进行模式匹配:而不是
test f xs
| length xs == 0 = []
| f (head xs) = ...
Run Code Online (Sandbox Code Playgroud)
写
test f [] = []
test f (x:xs)
| f x = ...
Run Code Online (Sandbox Code Playgroud)
这样,您就不会错误地评估空列表的头部,因为编译器确保x仅在已检查为非空的子句的范围内.
查看标准函数的源代码以filter供最终参考.
† 实际上,1 可以是一个函数...数字文字在Haskell中被重载; 你理论上可以写
instance Num (Integer -> Bool) where
fromInteger n x = x == n
Run Code Online (Sandbox Code Playgroud)
然后你可以定义f = 1 :: Integer -> Bool,也可以使用它test.但是......这将是一个非常糟糕的主意; 这样的实例会造成非常混乱的代码.