简体   繁体   English

Haskell:类型变量和泛型类型

[英]Haskell: type variables and generic types

When I mention in the type signature of the function isQuestion the types explicitly, GHCi compiles it perfectly: 当我在函数isQuestion的类型签名中明确isQuestion类型时,GHCi会完美地编译它:

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

However, when I turn to 'generic' code, it doesn't work: 但是,当我转向“通用”代码时,它不起作用:

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

since I get the below error: 因为我得到以下错误:

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

The type [a] -> Maybe b is shorthand for forall a b. [a] -> Maybe b 类型[a] -> Maybe b是所有forall a b. [a] -> Maybe b简写forall a b. [a] -> Maybe b forall a b. [a] -> Maybe b . forall a b. [a] -> Maybe b But isQuestion doesn't work for all types a and b , it only works specifically if a is Char and b is Bool . 但是isQuestion不适用于所有类型ab ,它仅在aChar并且bBool时才有效。

First observation is that 首先观察到的是

last xs == something

can only work if there is a definition of (==) in scope for the elements of xs . 只有在xs元素的范围内定义了(==) ,它才有效。 But as the compiler knows nothing about a , there is no such thing. 但是,由于编译器对a一无所知,所以没有这种事情。 You must narrow a to be the subset of types with equality: 您必须将a缩小a相等的类型的子集:

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

The second observation is that something is a Char in your code ( '?' ), so this method can only ever work when a ≡ Char . 第二个观察结果是代码中的somethingChar'?' ),因此该方法仅在a ≡ Char Instead, you could add that something as a parameter: 相反,您可以添加一些内容作为参数:

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

Finally, as has been pointed out, you have a concrete return type, ie Maybe Bool , as 最后,正如已经指出的那样,您有一个具体的返回类型,即Maybe Bool ,为

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

So your function's signature could be 因此,您函数的签名可能是

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

Edited this paragraph for clarity Note that, depending on your business logic, you might not want to make a special case of the empty string. 为清楚起见编辑了本段。请注意,根据您的业务逻辑,您可能不希望对空字符串进行特殊处理。 If the only thing you care about is whether a string ends with a question mark, then Nothing and Just false would virtually mean the same thing. 如果您唯一关心的是字符串是否以问号结尾,那么NothingJust false实际上意味着同一件事。 In that case, your function becomes a "yes or no" question and you can drop the Maybe : 在这种情况下,您的函数将变成“是或否”的问题,您可以删除Maybe

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

or simply 或简单地

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

Parametric polymorphism is not subtyping or supertyping. 参数多态不是子类型或超类型。 It's a statement that the implementation of a value doesn't depend on part of the type. 声明值的实现不依赖于类型的一部分。 In fact, the implementation works for any choice of type at all. 实际上,该实现完全适用于任何类型的选择。

Your implementation doesn't work for any choice of type. 您的实现不适用于任何类型的选择。 It only works if a is Char and b is Bool . 仅当aChar并且bBool时才有效。 You can tell this because it uses (== '?') in there, which is a function of type Char -> Bool . 您可以说出来,因为它在其中使用(== '?') ,这是Char -> Bool类型的函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM