错误 - 无法推断实例
ERROR - Cannot infer instance
我是 Haskell 的初学者。我有这个功能
test f xs
| length xs == 0 = []
| f (head xs) = head xs : test f (tail xs)
| otherwise = test f (tail xs)
此函数应从列表 xs 中与 f 值匹配的每个元素创建一个列表,但它会返回一个错误:
test 1 [1,2]
ERROR - Cannot infer instance
*** Instance : Num (a -> Bool)
*** Expression : test 1 [1,2]
这部分:
| f (head xs)
应该是 Bool 是吗?它作为过滤器工作吗?我怎样才能使这个功能工作?
提前致谢。
始终使用类型签名
显然,f
是一种谓词:您将它应用于列表中的值,它会产生一个布尔值。所以test
的类型是
test :: (a -> Bool) -> [a] -> [a]
顺便说一句,这个的标准名称是 filter
。
如果你自己不确定签名,其实可以问问GHCi
> :t test
test :: (a -> Bool) -> [a] -> [a]
...但我强烈建议改为 start 签名:首先考虑您希望函数完成什么,然后再考虑实现。[=35= ]
无论如何,要测试test
函数,你需要给它一个(a -> Bool)
函数和一个列表。 1
是函数吗?我敢说不是†,所以test 1 [1,2]
说不通。您的意思可能是 test (\x -> x==1) [1,2]
,也可以简单地写成 test (==1) [1,2]
.
关于您的代码的几点说明:
- 您正在使用守卫来检查列表是否为空。首先,为了只检查一个列表是否为空,never 评估它的
length
——这需要遍历整个列表。您 可以 使用 null
函数,它就是这样做的——检查容器是否为空 ...
... 但这仍然存在实际从列表中取出值的问题。您确实可以使用 head
获取非空列表的第一个值,但这仅在您首先 检查 非空的分支中才是安全的。这很容易出错。一个更好的解决方案是仅 模式匹配 在列表头上:而不是
test f xs
| length xs == 0 = []
| f (head xs) = ...
写
test f [] = []
test f (x:xs)
| f x = ...
这样,您不能 错误地计算空列表的头部,因为编译器确保 x
仅在具有以下子句的范围内已检查为非空。
查看标准 filter
函数的 the source code 作为最终参考。
†实际上,1
可以是一个函数... Haskell;理论上你可以写
instance Num (Integer -> Bool) where
fromInteger n x = x == n
然后你可以定义f = 1 :: Integer -> Bool
,并将其用于test
。但是……这将是一个非常糟糕的主意;这种情况会导致代码非常混乱。
我是 Haskell 的初学者。我有这个功能
test f xs
| length xs == 0 = []
| f (head xs) = head xs : test f (tail xs)
| otherwise = test f (tail xs)
此函数应从列表 xs 中与 f 值匹配的每个元素创建一个列表,但它会返回一个错误:
test 1 [1,2]
ERROR - Cannot infer instance
*** Instance : Num (a -> Bool)
*** Expression : test 1 [1,2]
这部分:
| f (head xs)
应该是 Bool 是吗?它作为过滤器工作吗?我怎样才能使这个功能工作? 提前致谢。
始终使用类型签名
显然,f
是一种谓词:您将它应用于列表中的值,它会产生一个布尔值。所以test
的类型是
test :: (a -> Bool) -> [a] -> [a]
顺便说一句,这个的标准名称是 filter
。
如果你自己不确定签名,其实可以问问GHCi
> :t test
test :: (a -> Bool) -> [a] -> [a]
...但我强烈建议改为 start 签名:首先考虑您希望函数完成什么,然后再考虑实现。[=35= ]
无论如何,要测试test
函数,你需要给它一个(a -> Bool)
函数和一个列表。 1
是函数吗?我敢说不是†,所以test 1 [1,2]
说不通。您的意思可能是 test (\x -> x==1) [1,2]
,也可以简单地写成 test (==1) [1,2]
.
关于您的代码的几点说明:
- 您正在使用守卫来检查列表是否为空。首先,为了只检查一个列表是否为空,never 评估它的
length
——这需要遍历整个列表。您 可以 使用null
函数,它就是这样做的——检查容器是否为空 ... ... 但这仍然存在实际从列表中取出值的问题。您确实可以使用
head
获取非空列表的第一个值,但这仅在您首先 检查 非空的分支中才是安全的。这很容易出错。一个更好的解决方案是仅 模式匹配 在列表头上:而不是test f xs | length xs == 0 = [] | f (head xs) = ...
写
test f [] = [] test f (x:xs) | f x = ...
这样,您不能 错误地计算空列表的头部,因为编译器确保
x
仅在具有以下子句的范围内已检查为非空。
查看标准 filter
函数的 the source code 作为最终参考。
†实际上,1
可以是一个函数... Haskell;理论上你可以写
instance Num (Integer -> Bool) where
fromInteger n x = x == n
然后你可以定义f = 1 :: Integer -> Bool
,并将其用于test
。但是……这将是一个非常糟糕的主意;这种情况会导致代码非常混乱。