错误 - 无法推断实例

时间:2016-08-11 09:44:04

标签: haskell types instance type-inference

我是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,但是呢?它是否作为过滤器工作?如何使此功能起作用? 提前谢谢。

1 个答案:

答案 0 :(得分:5)

始终使用类型签名

显然,f是一种谓词:您将它应用于列表中的值,并产生一个布尔值。所以test的类型是

test :: (a -> Bool) -> [a] -> [a]

BTW标准名称为filter

如果你自己不确定签名,你可以问GHCi

> :t test
test :: (a -> Bool) -> [a] -> [a]

...但我强烈建议使用签名启动:首先考虑一下你希望你的功能完成什么,然后担心实现。

无论如何,为了测试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)     = ...
    

    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。但是......这将是一个非常糟糕的主意;这样的实例会造成非常混乱的代码。

相关问题