Расширение 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, а не путем вызова некоторой функции в скомпилированном коде, правильно?

Ответы

Ответ 1

Другие ответы правильны относительно включения расширения в 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.

Ответ 2

Ваша прагма правильна; проблема заключается в том, что вы пытаетесь использовать его изнутри GHCi, который не наследует расширения загруженного модуля, 1 но передает параметры, предоставленные GHC, для компиляции файлов, которые вы перечисляете (поэтому он имеет тот же эффект, что и прагма).

Вы должны сохранить прагму и либо пройти -XTypeOperators при запуске GHCi, либо включить его после загрузки файла следующим образом:

GHCi> :set -XTypeOperators

1 что может быть очень нежелательным и, вероятно, невозможно во многих случаях, например. загрузка скомпилированных модулей.

Ответ 3

Прагма LANGUAGE работает для исходного файла, она не распространяется на ghci -prompt. Поскольку в нескольких исходных файлах проекта можно иметь конфликтующие прагмы, исходные прагмы не могут по умолчанию распространяться на ghci -prompt. Было бы возможно, чтобы прагмы из *module были эффективными в подсказке, я не уверен, но я думаю, что это задумано, чтобы реализовать это, так или иначе, пока это не реализовано, поэтому вам нужно установить расширения для ghci явно.