Расширение XTypeOperators не работает как прагма
Я использую GHCi 7.0.3 со следующей программой, которая реализует список уровня типа:
{-# LANGUAGE TypeOperators #-}
data True
data False
-- List
data Nil
data Cons x xs
-- Type-level infix operator must begin with ':'
data x ::: xs
infixr 5 ::: -- set precedence level to 5 (tight)
Это компилируется, но когда я проверяю это с:
:t (undefined :: True:::Nil)
(какой тип undefined
когда приведен к типу True:::Nil
?) Я получаю эту ошибку:
Illegal operator `:::' in type `True ::: Nil'
Use -XTypeOperators to allow operators in types
И действительно, когда я запускаю GHCi с флагом
-XTypeOperators
Я получаю ожидаемый результат:
(undefined :: True ::: Nil) :: True ::: Nil
Мой вопрос: почему не работает эквивалентная прагма:
{-# LANGUAGE TypeOperators #-}
Редактировать: Если прагмы не распространяются на среду GHCi, чем у меня есть еще одна загадка. Я попробовал эту программу:
class And b1 b2 b | b1 b2 -> b where
andf :: b1 -> b2 -> b
-- truth table
instance And True True True where andf = undefined
instance And True False False where andf = undefined
instance And False True False where andf = undefined
instance And False False False where andf = undefined
Требуются следующие прагмы:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
Но после компиляции я мог бы использовать его в GHCi:
*Main> :t andf (undefined::True) (undefined::False)
andf (undefined::True) (undefined::False) :: False
Я предполагаю, что в случае со списком интерпретатор даже не смог разобрать выражение с помощью оператора уровня типа :::
тогда как в случае многопараметрических классов командная строка была разбираема. Но если подумать, GHCi выполнил вывод типов, используя многопараметрические классы и функциональные зависимости, не так ли? Вывод этого типа выполняется в GHCi, а не путем вызова какой-либо функции в скомпилированном коде, верно?
3 ответа
Другие ответы правильны в отношении включения расширения в GHCi, либо из приглашения GHCi, либо в виде флага при запуске GHCi. Однако существует третий вариант - вы можете создать .ghci
файл, который будет загружаться и запускаться при каждом запуске GHCi, и использовать его для автоматического включения расширения. Особенно для таких вещей, как TypeOperators
где очень мало вреда в том, что он включен, это очень удобно.
Например, вот как выглядит мой прямо сейчас:
:set prompt "∀x. x ⊢ "
:set -XTypeOperators
import Control.Monad
import Control.Applicative
import Control.Arrow
.ghci
файл идет в любом стандартном месте вашей системы для таких файлов.
Чтобы ответить на ваш расширенный вопрос: рассматриваемый код работает в GHCi примерно, потому что он также работал бы, если бы он использовался в другом модуле, который импортировал модуль с использованием прагм, но не включал их сам. GHC более чем способен включать расширения для каждого модуля, даже если экспортированные определения не могут иметь смысла без расширения или имеют предполагаемые типы, которые в нем нуждаются.
Различие немного нечеткое в GHCi, потому что оно также помещает неэкспортированные определения из модуля в область видимости, но в целом все, что будет работать, если используется из другого модуля, также будет работать в приглашении GHCi.
Ваша прагма верна; проблема в том, что вы пытаетесь использовать его из GHCi, который не наследует расширения загруженного модуля, 1, но передает опции, которые он предоставляет GHC, для компиляции файлов, которые вы перечисляете (именно поэтому он имеет тот же эффект, что и прагма).
Вы должны сохранить прагму, и либо пройти -XTypeOperators
при запуске GHCi или включите его после загрузки файла следующим образом:
GHCi> :set -XTypeOperators
1 Это может быть очень нежелательно и, возможно, невозможно во многих случаях, например, для загрузки скомпилированных модулей.
LANGUAGE
Прагма работает для исходного файла, она не распространяется на ghci
-незамедлительный. Так как в нескольких исходных файлах проекта могут быть конфликтующие прагмы, исходные прагмы не могут по умолчанию распространяться на ghci
-незамедлительный. Было бы возможно иметь прагмы от *module
Это эффективно при подсказке, я не уверен, но я думаю, что это задумано, чтобы реализовать это, во всяком случае, пока, это не реализовано, поэтому вам нужно установить расширения для ghci
в явном виде.