Подтвердить что ты не робот

Каково влияние синонимов типов на экземпляры классов типов? Что делает прагма TypeSynonymInstances в GHC?

Я читаю Real World Haskell Pg 151, и я смотрел на следующий отрывок более часа:

Напомним, что String является синонимом [ Char], который, в свою очередь, является типом [a] где Char заменяется типом параметр a. Согласно Haskell 98's правил, нам не разрешено предоставлять введите вместо параметра типа, когда мы пишем экземпляр. Другими словами, нам было бы законно писать экземпляр для [a], но не для [Char]. 16 комментариев 5335

Он просто не погружается. Посмотрите на (свободная не пиратская) копия главы 6 RWH Я вижу много других люди действительно страдают от этого. Я все еще не понимаю этого из комментариев...

Во-первых, все об этом меня смущает, поэтому, пожалуйста, если вы чувствуете, что можете объяснить что-нибудь об этом отрывке, или TypeSynonymInstances сделайте.

Вот моя проблема:

  • Int - конструктор данных
  • String - это конструктор данных И синоним типа

Теперь я не могу ответить на эти вопросы:

  • Почему синоним типа исключает возможность создания типа члена класса типа (я ищу какую-то причину, которая, вероятно, связана с компиляцией или импликацией синонима типа)?
  • Почему разработчики языка не хотят этого синтаксиса (я прошу рассуждать о небрежной математике или математике или юникоде).
  • Я вижу эту строку "тип [a], где Char заменяется параметром типа a", и я хочу знать, почему я не могу его заменить "для типа a, где Int заменяется на type a".

Спасибо!

4b9b3361

Ответ 1

Я думаю, что часть проблемы заключается в том, что в игре играют две, в основном несвязанные ограничения:

  • Ни один экземпляр синонима типа не означает, что экземпляры могут быть объявлены только с помощью data или newtype, а не type. Это запрещает String, но не [Char].
  • Никакие гибкие экземпляры не означают, что экземпляры могут упоминать только один тип, который не является переменной, и только этот тип может использоваться как конструктор типа. Это запрещает Maybe Int и f Int, но не Maybe a.

Здесь GHCi говорит о Int, Char и String:

data Char = GHC.Types.C# GHC.Prim.Char#
data Int = GHC.Types.I# GHC.Prim.Int#
type String = [Char]

Int и Char являются простыми типами без переменных типа; там нет конструктора типов, поэтому вы можете делать экземпляры с ними довольно свободно.

Строка, однако, терпит неудачу по обоим пунктам. Это синоним типа, который недопустим, а также конструктор типа, примененный к непеременной, а именно конструктор типа списка, примененный к Char.

Для сравнения отметим, что [a], Maybe a и Either a b являются действительными в случаях, но [Int], Maybe [a] и Either String a запрещены; надеюсь, теперь вы можете понять, почему.

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

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}

Вы всегда можете посмотреть пакеты, которые используют прагмы. Гибкие экземпляры, похоже, действительно пользуются достаточным количеством ресурсов и из "респектабельных" пакетов (например, пара попадает в источник для Parsec).

Ответ 2

Собственно, ни Int, ни String не являются конструкторами данных. То есть вы не можете использовать их для создания значения

> (Int 42, String "bob")
<interactive>:1:1: Not in scope: data constructor `Int'
<interactive>:1:9: Not in scope: data constructor `String'

Int называет новый, отличный, алгебраический тип данных. String является "синонимом типа" или псевдонимом для уже существующего типа: [Char]. Проблема в том, что Haskell 98 говорит, что вы не можете использовать синоним типа в объявлении экземпляра.

Не могу сказать, почему авторы отчета Haskell 98 решили ограничить синонимы типов в этом случае. На них существует целый ряд ограничений. Например, они не могут быть частично применены (если они принимают аргументы типа). Я думаю, что подсказка приходит в конце §4.2.2:

Синонимы типов удобны, но строго синтаксический механизм тип подписи более читабельны. синоним и его определение полностью взаимозаменяемы, за исключением тип экземпляра экземпляра (раздел 4.3.2).

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

Что касается вашего последнего вопроса, я считаю, что объяснение объединяет две вещи: 1) String - синоним типа [Char], который, в свою очередь, специализируется на более общем типе [a] и 2), который даже без синонима, [Char] не может использоваться в голове экземпляра.

Эта вторая проблема не имеет ничего общего с синонимами типа, но в этих главах экземпляров все параметры типа для конструктора типов должны быть переменными, а не конкретными типами. То есть вы не можете определить отдельные экземпляры для [Int] и [Char] для некоторого класса, вы можете определить только экземпляры [a]. (Помните, что, несмотря на удобный синтаксис, [] является конструктором типа, а вещь внутри является параметром типа.)

Опять же, я не знаю, почему отчет ограничивает их, но я подозреваю, что это также связано с стратегией компиляции. Поскольку стратегия компиляции GHC для экземпляров может справиться с этим, вы можете уменьшить это ограничение в GHC через -XFlexibleInstances.

Наконец, я видел, что оба расширения включены в довольно много кода, но, возможно, кто-то с большим опытом Haskell может взвесить, если они "лучшие практики" или нет.

Ответ 3

Haskell 98

  • глава экземпляра должен иметь форму C (T u1... uk), где T - конструктор типа, определенный объявлением данных или newtype (см. TypeSynonymInstances), а ui - разные переменные типа, а
  • каждое утверждение в контексте должно иметь вид C 'v, где v является одним из ui.

Поэтому допустимо использовать instance ClassName TypeConstructor where и TypeConstructor MUST, такие как Int, Double или [a], убедитесь, что задействован только конструктор типов!!

BTW, [] - это конструктор типа, поэтому [TypeConstructor] не может использоваться, но [NewType] и [TypeVariable] разрешены.

Это ограничение Haskell, и мы можем избежать его, включив FlexibleInstances.

Ответ 4

Int и String являются типами, а не конструкторами данных. Строка является псевдонимом для [ Char], который также может быть записан в список Char. Конструктор данных - это что-то вроде Just, поэтому Just 3 - значение типа Maybe Int. Типовые экземпляры синонима объясняются здесь:

http://hackage.haskell.org/trac/haskell-prime/wiki/TypeSynonymInstances