Haskell: переменные типов и универсальные типы

Когда я упоминаю в подписи типа функции 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)

3 ответа

Решение

Первое наблюдение заключается в том, что

last xs == something

может работать только при наличии определения (==) в области для элементов xs, Но так как компилятор ничего не знает о aнет такой вещи. Вы должны сузить a быть подмножеством типов с равенством:

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

Второе наблюдение состоит в том, что something это 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 "?"

Тип [a] -> Maybe b это сокращение для forall a b. [a] -> Maybe b, Но isQuestion не работает для всех типов a а также bработает только если a является Char а также b является Bool,

Параметрический полиморфизм не является подтипом или супертипированием. Это утверждение, что реализация значения не зависит от части типа. Фактически, реализация работает для любого выбора типа вообще.

Ваша реализация не работает для любого выбора типа. Это работает только если a является Char а также b является Bool, Вы можете сказать это, потому что он использует (== '?') там, который является функцией типа Char -> Bool,

Другие вопросы по тегам