Spec-Zone.ru › Haskell 9

6.2.10. Переназначаемый синтаксис и неявный импорт Prelude

ImplicitPrelude
Подразумевается расширением:

RebindableSyntax подразумевает NoImplicitPrelude.

Начиная с версии:

6.8.1

По умолчанию неявно импортировать модуль Prelude.

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

import Prelude (foo)

Вместо всего модуля неявный импорт будет импортировать из Prelude только foo.

Обычно GHC импортирует за вас модуль Prelude. Если вы предпочитаете, чтобы этого не происходило, укажите параметр -XNoImplicitPrelude. Идея в том, что тогда вы сможете импортировать собственный Prelude.

RebindableSyntax
Подразумевает:

NoImplicitPrelude

Начиная с версии:

7.0.1

Разрешить переназначение ряда обычно встроенных операций.

Предположим, вы импортируете собственный Prelude, чтобы определить собственную иерархию числовых классов. Такой подход теряет смысл, если литерал «1» означает «Prelude.fromInteger 1», как указано в отчёте Haskell. Поэтому расширение RebindableSyntax приводит к тому, что следующие элементы встроенного синтаксиса ссылаются на то, что находится в области видимости, а не на версии из Prelude:

  • Целочисленный литерал 368 означает «fromInteger (368::Integer)», а не «Prelude.fromInteger (368::Integer)».
  • Дробные литералы обрабатываются точно так же, за исключением того, что их преобразование — fromRational (3.68::Rational).
  • Строковые литералы обрабатываются аналогичным образом, за исключением того, что их преобразование — fromString ("368"::String).
  • Для проверки равенства в числовом шаблоне с перегрузкой используется то, что находится в области видимости под именем (==).
  • Для операции вычитания и проверки «больше или равно» в шаблонах n+k используются те, что находятся в области видимости под именами (-) и (>=).
  • Отрицание (например, «- (f x)») означает «negate (f x)» как в числовых шаблонах, так и в выражениях.
  • Условные выражения (например, «if e1 then e2 else e3») означают «ifThenElse e1 e2 e3». Однако выражения case не затрагиваются.
  • Нотация «do» преобразуется с использованием функций, которые находятся в области видимости под именами (>>=), (>>) и fail (а не версий из Prelude). Списковые включения, mdo (Рекурсивная do-нотация) и параллельные включения для массивов не затрагиваются.
  • В нотации стрелок (см. раздел Нотация стрелок) используются функции, которые находятся в области видимости под именами arr, (>>>), first, app, (|||) и loop. Однако, в отличие от других конструкций, типы этих функций должны очень точно соответствовать типам из Prelude. Детали пока не окончательны; если вы хотите это использовать, спросите!
  • Нотацию списков, например [x,y] или [m..n], также можно обрабатывать с помощью переназначаемого синтаксиса, если использовать -XOverloadedLists; см. раздел Перегруженные списки.
  • Перегруженная метка «#foo» означает «fromLabel @"foo"», а не «GHC.OverloadedLabels.fromLabel @"foo"» (см. раздел Перегруженные метки).

RebindableSyntax подразумевает NoImplicitPrelude.

Во всех случаях (кроме нотации стрелок) статическая семантика должна соответствовать десахаризованной форме, даже если это кажется неожиданным. Например, статическая семантика литерала 368 в точности совпадает со статической семантикой fromInteger (368::Integer); допустимо, чтобы fromInteger имело любой из следующих типов:

fromInteger :: Integer -> Integer
fromInteger :: forall a. Foo a => Integer -> a
fromInteger :: Num a => a -> Integer
fromInteger :: Integer -> Bool -> Bool

Обратите внимание: это экспериментальная возможность, предусматривающая меньше проверок, чем обычно. Используйте -dcore-lint для проверки типов десахаризованной программы. Если Core Lint не выдаёт ошибок, всё должно быть в порядке.

6.2.10.1. Пользовательские модули Prelude с именем Prelude

Если назвать пользовательский модуль Prelude Prelude и поместить его в файл с именем Prelude.hs, он будет неявно импортирован вместо Prelude по умолчанию.

Вот пример, который компилируется:

$ cat Prelude.hs
module Prelude where

a = ()

$ cat B.hs
module B where

foo = a

$ ghc Prelude.hs B.hs
[1 of 2] Compiling Prelude          ( Prelude.hs, Prelude.o )
[2 of 2] Compiling B                ( B.hs, B.o )

Новый Prelude неявно импортируется в B.hs.

Вот пример, который не компилируется:

$ cat Prelude.hs
module Prelude where

foo = True

$ ghc Prelude.hs
[1 of 1] Compiling Prelude          ( Prelude.hs, Prelude.o )

Prelude.hs:3:7: error: Data constructor not in scope: True

В этом случае исходный модуль Prelude скрывается пользовательским Prelude. Чтобы включить исходный Prelude в пользовательский Prelude, его можно явно импортировать с параметром -XPackageImports и import "base" Prelude.

Явный импорт Prelude подавляет неявный импорт. Это позволяет уточнить неявный импорт:

$ cat Prelude.hs
module Prelude where

a = ()

b = ()

$ cat B.hs
module B where

import Prelude (b)

-- a is now not in scope, there is no implicit Prelude import
foo = a
qux = b

$ ghc Prelude.hs B.hs
[1 of 2] Compiling Prelude          ( Prelude.hs, Prelude.o )
[2 of 2] Compiling B                ( B.hs, B.o )
  B.hs:5:7: error: [GHC-88464]
      Variable not in scope: a
      Suggested fix:
        Add 'a' to the import list in the import of 'Prelude'
        (at B.hs:3:1-18).
    |
  5 | foo = a
    |

Примечание

Импорт модуля с именем Prelude с расширением PackageImports не влияет на неявный импорт Prelude:

> cat Prelude.hs
module Prelude where

a = ()

> cat B.hs
{-# LANGUAGE PackageImports #-}
module B where

import "base" Prelude

-- This definition comes from the implicit prelude import
foo = a

-- These definitions come from the package import
baz :: Int -> Int -> Int
baz = (+)

> ghc B.hs
[1 of 2] Compiling Prelude          ( Prelude.hs, Prelude.o )
[2 of 2] Compiling B                ( B.hs, B.o )

Чтобы использовать пакетные импорты, следует явно отключить импорт неявного модуля prelude, включив расширение NoImplicitPrelude.

6.2.10.2. Что не затрагивается расширением RebindableSyntax

RebindableSyntax не применяется к коду, сгенерированному из предложения или объявления deriving. Чтобы понять почему, рассмотрим следующий код:

{-# LANGUAGE RebindableSyntax, OverloadedStrings #-}
newtype Text = Text String

fromString :: String -> Text
fromString = Text

data Foo = Foo deriving Show

При этом будет сгенерирован код, эквивалентный следующему:

instance Show Foo where
  showsPrec _ Foo = showString "Foo"

Но поскольку включены расширения RebindableSyntax и OverloadedStrings, строковый литерал "Foo" теперь будет иметь тип Text, а не String, который не принимает showString! Из-за этого сгенерированный экземпляр Show не пройдёт проверку типов. Трудно представить ситуацию, в которой поведение RebindableSyntax в производном коде было бы желательным, поэтому GHC полностью игнорирует RebindableSyntax при проверке производного кода.

6.2.11. Постфиксные операторы

PostfixOperators
Начиная с версии:

7.10.1

Статус:

Включено в GHC2024, GHC2021

Разрешает использование постфиксных операторов

Расширение PostfixOperators добавляет небольшое расширение к синтаксису левых сечений операторов, позволяя определять постфиксные операторы. Суть расширения такова: для любого выражения e и оператора (!) левое сечение

(e !)

эквивалентно (с точки зрения как проверки типов, так и выполнения) выражению

((!) e)

В строгой интерпретации Haskell 98 сечение эквивалентно

(\y -> (!) e y)

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

Расширение не распространяется на левую часть определения функции; такую функцию необходимо определять в префиксной форме.

© 2002–2007 The University Court of the University of Glasgow. All rights reserved.
Licensed under the Glasgow Haskell Compiler License.
https://downloads.haskell.org/~ghc/9.14.1/docs/users_guide/exts/rebindable_syntax.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API