Haskell:类型变量和泛型类型

Haskell: type variables and generic types

当我在函数的类型签名中明确提到 isQuestion 类型时,GHCi 完美地编译了它:

isQuestion :: [Char] -> Maybe Bool
isQuestion [] = Nothing
isQuestion xs = Just (last xs == '?')

但是,当我转向 'generic' 代码时,它不起作用:

isQuestion :: [a] -> Maybe b
isQuestion [] = Nothing
isQuestion xs = Just (last xs == '?')

因为我得到以下错误:

<interactive>:138:17: error:
    * Couldn't match type `b' with `Bool'
      `b' is a rigid type variable bound by
        the type signature for:
          isQuestion :: forall a b. [a] -> Maybe b
        at <interactive>:136:1-28
      Expected type: Maybe b
        Actual type: Maybe Bool
    * In the expression: Just (last xs == '?')
      In an equation for `isQuestion':
          isQuestion xs = Just (last xs == '?')
    * Relevant bindings include
        isQuestion :: [a] -> Maybe b (bound at <interactive>:137:1)

对于 forall a b. [a] -> Maybe b,类型 [a] -> Maybe b 是 shorthand。但是 isQuestion 不适用于 所有 类型 ab,它仅在 a 是 [=16= 时才有效] 并且 bBool.

参数多态性 不是 子类型或超类型。它声明值的实现不依赖于部分类型。事实上,该实现适用于任何类型的选择。

您的实施不适用于任何类型选择。它仅在 aCharbBool 时有效。你可以看出这一点,因为它在那里使用了 (== '?'),这是一个 Char -> Bool.

类型的函数

第一个观察结果是

last xs == something

只有在 xs 的元素范围内有 (==) 的定义时才有效。但是由于编译器对 a 一无所知,所以没有这样的东西。您必须将 a 缩小为具有相等性的类型的子集:

isQuestion :: Eq a => [a] -> Maybe b

第二个观察结果是 something 在您的代码 ('?') 中是一个 Char,因此此方法只能在 a ≡ Char 时起作用。相反,您可以将其添加为参数:

isQuestion :: Eq a => a -> [a] -> Maybe b

最后,如前所述,您有一个具体的 return 类型,即 Maybe Bool,如

(==) :: a -> a -> Bool

所以你的函数的签名可以是

isQuestion :: Eq a => a -> [a] -> Maybe Bool

为清楚起见编辑了这一段请注意,根据您的业务逻辑,您可能不想对空字符串进行特殊处理。如果您唯一关心的是字符串是否以问号结尾,那么 NothingJust false 实际上是同一个意思。在这种情况下,你的函数变成了一个 "yes or no" 问题,你可以删除 Maybe:

isQuestion :: Eq a => a -> [a] -> Bool
isQuestion x = isSuffixOf [x]

或者干脆

isQuestion :: String -> Bool
isQuestion = isSuffixOf "?"