这是我对函数的定义'
any' :: (t -> Bool) -> [t] -> Bool
any' f = foldl' step False
where step :: Bool -> t -> Bool
step b x | f x = True
| otherwise = b
加载拥抱时出现此错误:
ERROR "folds.hs":65 - Inferred type is not general enough
*** Expression : step
*** Expected type : Bool -> a -> Bool
*** Inferred type : Bool -> _7 -> Bool
......这在ghci:
folds.hs:65:27:
Couldn't match expected type `t' with actual type `t1'
`t' is a rigid type variable bound by
the type signature for any' :: (t -> Bool) -> [t] -> Bool
at folds.hs:62:9
`t1' is a rigid type variable bound by
the type signature for step :: Bool -> t1 -> Bool at folds.hs:64:22
In the first argument of `f', namely `x'
In the expression: f x
In a stmt of a pattern guard for
an equation for `step':
f x
当我删除步骤的类型定义它工作正常,所以我的问题是...... 有一种方法可以正确地编写该类型定义,或者我是否处理了无法显式键入本地函数的情况之一?
答案 0 :(得分:3)
签名中的t
where step :: Bool -> t -> Bool
与t
签名中出现的any'
不同。相反,它被解释为一个新的类型变量,它是step
签名的本地变量。
换句话说,您的代码实际上等同于
any' :: (t -> Bool) -> [t] -> Bool
any' f = foldl' step False
where step :: Bool -> a -> Bool -- t renamed to a
step b x | f x = True
| otherwise = b
然后编译器会抱怨,因为其签名中的step
声明适用于任何类型a
,而f需要t
。
可能的解决方法是删除step
签名。在这种情况下,编译器将自己推断出正确的类型。从程序员的角度来看,这并不完全令人愉快,因为编译器现在不会检查step
签名是否真的是程序员想要的签名。
根据评论中的建议,另一个修复是启用Haskell扩展,允许我们编写类型。
{-# LANGUAGE ScopedTypeVariables #-}
import Data.List
any' :: forall t. (t -> Bool) -> [t] -> Bool
any' f = foldl' step False
where step :: Bool -> t -> Bool
step b x | f x = True
| otherwise = b
这里显式量词forall t
告诉编译器t
定义中出现的any'
实际上是t
,而不是新的类型变量。< / p>
答案 1 :(得分:1)
您需要范围类型变量扩展,否则编译器会将第二个t
视为另一个新的多态类型变量,而不是与主类型声明中相同的t
。
发生这种情况的线索在Couldn't match expected type 't' with actual type 't1'
消息中。显然ghci已重命名第二个t
t1
,因为它不认为它们是相同的。
您可以使用ScopedTypeVariables
和明确的forall
将t
纳入内部函数的范围。
{-# LANGUAGE ScopedTypeVariables #-}
any' :: forall t.(t -> Bool) -> [t] -> Bool
any' f = foldl' step False
where step :: Bool -> t -> Bool
step b x | f x = True
| otherwise = b