错误 - 无法推断实例

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。但是……这将是一个非常糟糕的主意;这种情况会导致代码非常混乱。