Проблема выведения ограничения типа Read - PullRequest
4 голосов
/ 16 апреля 2020

Рассмотрим тип

data MyBool a = TRUE | FALSE 

Обратите внимание, что MyBool a на самом деле не зависит от a, но давайте сделаем это просто для удовольствия.

Теперь представьте, что я хочу определить функцию isParsable :: (Read a) => String -> MyBool a, которая решает, может ли данная строка обрабатываться как a, и выводит результат как MyBool a.

Естественно, я хочу написать:

isParsable :: (Read a) => String -> MyBool a
isParsable str
 | (null parses) = FALSE
 | (otherwise) = TRUE
     where parses = (reads str)::[(a, String)]

Сейчас это не компилируется, но я не совсем понимаю, почему. Я не думаю, что эта функция неоднозначна, потому что любой вызов isParsable должен был бы вызвать выбор a и, следовательно, убедиться, что ограничение Read a выполнено, поскольку оно прямо в сигнатуре типа. Кроме того, where оговорка заставляет reads :: String -> [(a, String)]. Но по какой-то причине GH C выдает ошибку.

Что я здесь недопонимаю и как можно это обойти?

1 Ответ

5 голосов
/ 16 апреля 2020

В стандартном Haskell a в сигнатуре вашего типа не совпадает с сигнатурой в теле. Чтобы они были одинаковыми, вам нужно включить расширение ScopedTypeVariables и явно определить его количество следующим образом:

{-# LANGUAGE ScopedTypeVariables #-}

data MyBool a = TRUE | FALSE

isParsable :: forall a. (Read a) => String -> MyBool a
isParsable str
 | (null parses) = FALSE
 | (otherwise) = TRUE
     where parses = (reads str)::[(a, String)]

Если вы хотите сделать это без расширения языка, вы можете используйте вспомогательную функцию, аналогично тому, как asTypeOf полезен:

data MyBool a = TRUE | FALSE

isParsableHelper :: [(a, String)] -> MyBool a
isParsableHelper parses
 | (null parses) = FALSE
 | (otherwise) = TRUE

isParsable :: (Read a) => String -> MyBool a
isParsable str = (isParsableHelper parses)
     where parses = (reads str)
...