1

这是我对任何函数的定义

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

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

4

2 回答 2

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 需要 a 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,而不是新的类型变量。

于 2014-02-08T20:52:26.447 回答
1

您需要作用域类型变量扩展,否则编译器将第二个t视为另一个新的多态类型变量,而不是与t主类型声明中的相同。

正在发生这种情况的线索在消息中Couldn't match expected type 't' with actual type 't1'。显然 ghci 已经重命名了 second 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
于 2014-02-08T20:53:33.297 回答