1

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

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

但是,当我转向“通用”代码时,它不起作用:

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)
4

3 回答 3

4

类型[a] -> Maybe b是 的简写forall a b. [a] -> Maybe b。但isQuestion不适用于所有类型aand b,它仅适用于aisCharbis Bool

于 2018-04-11T00:57:55.253 回答
4

第一个观察是

last xs == something

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

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

第二个观察是在你的代码( )中something是 a ,所以这个方法只能在. 相反,您可以将其添加为参数:Char'?'a ≡ Char

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

最后,正如已经指出的那样,您有一个具体的返回类型,Maybe Bool

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

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

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

为清楚起见编辑了本段请注意,根据您的业务逻辑,您可能不希望对空字符串进行特殊处理。如果您唯一关心的是字符串是否以问号结尾,那么Nothing实际上Just false意味着同一件事。在这种情况下,您的功能变成“是或否”问题,您可以删除Maybe

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

或者干脆

isQuestion :: String -> Bool
isQuestion = isSuffixOf "?"
于 2018-04-11T06:18:27.607 回答
2

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

您的实现不适用于任何类型的选择。它仅在aisCharbis时有效Bool。您可以告诉这一点,因为它(== '?')在那里使用,这是 type 的函数Char -> Bool

于 2018-04-11T02:29:37.727 回答