当我尝试在Haskell中编写本地函数的类型定义时,为什么会出现此错误?

时间:2014-02-08 19:37:30

标签: haskell functional-programming ghci hugs

这是我对函数的定义'

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

当我删除步骤的类型定义它工作正常,所以我的问题是...... 有一种方法可以正确地编写该类型定义,或者我是否处理了无法显式键入本地函数的情况之一?

2 个答案:

答案 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和明确的forallt纳入内部函数的范围。

{-# 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
相关问题