Есть ли список расширений GHC, которые считаются "безопасными"?

Иногда кусок кода, который я хочу написать, не является законным без хотя бы одного расширения языка. Это особенно актуально, когда вы пытаетесь внедрить идеи в исследовательские документы, которые, как правило, используют ту, которая была доступна в момент, когда была написана статья, сверхбыстрая версия GHC, не указав, какие расширения действительно необходимы.

В результате я часто получаю что-то вроде этого в верхней части моих файлов .hs:

{-# LANGUAGE TypeFamilies
           , MultiParamTypeClasses
           , FunctionalDependencies
           , FlexibleContexts
           , FlexibleInstances
           , UndecidableInstances
           , OverlappingInstances #-}

Я не против этого, но часто чувствую, что я делаю слепые жертвы, чтобы успокоить Великого Бога GHC. Он жалуется, что определенный фрагмент кода недействителен без расширения языка X, поэтому я добавляю прагму для X. Затем он требует включения Y, поэтому я добавляю прагму для Y. К тому времени, когда это закончится, я включите три или четыре расширения языка, которые я действительно не понимаю, и я понятия не имею, какие из них "безопасны".

Чтобы объяснить, что я подразумеваю под "безопасным":

  • Я понимаю, что UndecidableInstances безопасен, потому что хотя это может привести к тому, что компилятор не завершится, пока компиляция кода не будет иметь неожиданных побочных эффектов.

  • С другой стороны, OverlappingInstances явно небезопасен, потому что мне очень легко случайно записать код, который дает ошибки времени выполнения.

Итак, мой вопрос:

Есть ли список GHCextensions, которые считаются "безопасными" и которые являются "небезопасными"?

Ответ 1

Вероятно, лучше всего посмотреть, что SafeHaskell позволяет:

Безопасный язык

Безопасный язык (включен через -XSafe) ограничивает вещи двумя способами:

  • Некоторые расширения GHC LANGUAGE полностью запрещены.
  • Некоторые расширения GHC LANGUAGE ограничены в функциональности.

Ниже точно указаны флаги и расширения в каждой категории:

  • Запрещено полностью: GeneralizedNewtypeDeriving, TemplateHaskell
  • Ограниченная функциональность: OverlappingInstances, ForeignFunctionInterface, RULES, Data.Typeable
    • См. раздел Ограниченные функции ниже
  • Не имеет значения: все остальные флаги.

Ограниченные и отключенные функции GHC Haskell

На диалекте "Безопасный язык" мы ограничиваем следующие возможности языка Haskell:

  • ForeignFunctionInterface: это в основном безопасно, но запрещены импортные импортные объявления, которые импортируют функцию с типом, отличным от IO. Весь импорт FFI должен находиться в IO Monad.
  • RULES: поскольку они могут непредсказуемо изменять поведение доверенного кода, нарушая семантическую согласованность, они ограничены в функции. В частности, все RULES, определенные в модуле M, скомпилированном с -XSafe, отбрасываются. RULES, определенный в надежных модулях, что импорт M по-прежнему действителен и будет срабатывать, как обычно.
  • OverlappingInstances: это расширение может использоваться для нарушения семантической согласованности, поскольку вредоносный код может переопределять экземпляр типа (путем определения более конкретного экземпляра) таким образом, который изменяет поведение кода, импортирующего ненадежный модуль. Расширение не отключено для модуля M, скомпилированного с помощью -XSafe, но ограниченного. Пока M может определять перекрывающиеся объявления экземпляров, их можно использовать только в M. Если в модуле N, который импортирует M, на сайте вызова, который использует функцию класса типа, существует выбор того, какой экземпляр использовать (т.е. перекрытие), а наиболее конкретный выбор - от M (или любого другой безопасный скомпилированный модуль), то компиляция завершится неудачно. Не имеет значения, если модуль N считается безопасным, или заслуживающим доверия, или ни тем, ни другим.
  • Data.Typeable: Мы разрешаем вывод Data.Typeable, но мы не разрешаем экземпляры вручную. Производные экземпляры являются машинами, сгенерированными GHC, и должны быть абсолютно безопасными, но обработанные вручную могут лежать о своем типе и допускать небезопасные принуждения между типами. Это находится в духе оригинального дизайна SYB.

В диалоговом языке "Безопасный язык" мы полностью отключим следующие возможности языка Haskell:

  • GeneralizedNewtypeDeriving: он может использоваться для нарушения контроля доступа к конструктору, позволяя ненадежному коду манипулировать защищенными типами данных способами, которые не создавал автор типа данных. I. можно использовать для разрыва инвариантов структур данных.
  • TemplateHaskell: Это особенно опасно, так как это может вызвать побочные эффекты даже во время компиляции и может использоваться для доступа к абстрактным типам данных. Очень легко сломать границы модулей с помощью TH.

Я помню, что прочитал, что взаимодействие FunctionalDependencies и UndecidableInstances также может быть небезопасным, поскольку за пределами возможности неограниченной глубины стека контекста UndecidableInstances также поднимается так называемый условие покрытия (раздел 7.6.3.2), но я не могу найти ссылку для этого на данный момент.

EDIT 2015-10-27: С тех пор, как GHC получил поддержку ролей типов, GeneralizedNewtypeDeriving уже не является безопасным. (Я не уверен, что еще могло измениться.)