Понимание этого определения HList
Я относительно новичок в Haskell и пытаюсь понять одно из определений HList.
data instance HList '[] = HNil
newtype instance HList (x ': xs) = HCons1 (x, HList xs)
pattern HCons x xs = HCons1 (x, xs)
У меня есть пара конкретных вопросов:
Что
'[]
а также(x ': xs)
синтаксис я вижу? Похоже, что это сопоставление с образцом для параметров типа variadic, но я никогда раньше не видел этот синтаксис, и я не знаком с параметрами типа variadic в Haskell. Я предполагаю, что это является частью семейства типов GHC, но я ничего не вижу об этом на связанной странице, и довольно сложно найти синтаксис в Google.Есть ли смысл использовать
newtype
объявление с кортежем (вместоdata
объявление с двумя полями) кроме того, чтобы избежать боксаHCons1
?
2 ответа
Во-первых, вам не хватает части определения: data family
сама декларация.
data family HList (l :: [*])
data instance HList '[] = HNil
newtype instance HList (x ': xs) = HCons1 (x, HList xs)
Это называется data family
(доступно под TypeFamilies
расширение).
pattern HCons x xs = HCons1 (x, xs)
Это двунаправленный шаблон (доступен под PatternSynonyms
расширение).
Что
'[]
а также(x ': xs)
синтаксис я вижу?
Когда ты видишь '
знаки перед конструкторами, это означает их продвинутые аналоги уровня типа. В качестве синтаксического удобства продвигаемым спискам и кортежам также просто нужна дополнительная галочка (и мы все еще можем писать '[]
для пустого списка уровня типа и ':
для типового уровня минусы. Все это доступно через DataKinds
расширение.
Есть ли смысл использовать
newtype
объявление с кортежем (вместо объявления данных с двумя полями), кроме того, чтобы избежать боксаHCons1
?
Да, чтобы убедиться, что HList
имеет представительскую роль, что означает, что вы можете принуждать HList
с 1. Это слишком сложно, чтобы объяснить просто ответом, но вот пример того, как все идет не так, как мы хотим, когда у нас есть
data instance HList (x ': xs) = HCons x (HList xs)
вместо newtype instance
(и без рисунка). Рассмотрим следующее newtype
s, которые в представительстве эквивалентны Int
, Bool
, а также ()
соответственно
newtype MyInt = MyInt Int
newtype MyBool = MyBool Bool
newtype MyUnit = MyUnit ()
Напомним, мы можем использовать coerce
обернуть или развернуть эти типы автоматически. Ну, мы бы хотели сделать то же самое, но в целом HList
:
ghci> l = (HCons 3 (HCons True (HCons () HNil))) :: HList '[Int, Bool, ()]
ghci> l' = coerce l :: HList '[MyInt, MyBool, MyUnit]
Это работает с newtype instance
вариант, но не тот data instance
один из-за ролей. (Подробнее об этом здесь.)
1 технически, для data family
в целом: роли могут быть разными для каждого instance
/ newtype
- здесь нам действительно нужно только HCons
случай, чтобы быть представительным, так как это тот, который подвергается принуждению. Проверьте этот билет Trac.
'[]
а также (x ': xs)
являются синтаксисом для списков уровня типа в том смысле, что DataKinds
расширение языка позволяет продвигать типы к видам и конструкторы к типам; т.е. если k
какой-то '[k]
тоже своего рода, и '[]
это тип вида '[k]
, и если t :: k
а также ts :: '[k]
, затем t ': ts :: '[k]
, Все сдвигается на один.
Так в HList (x ': xs)
, x
а также xs
соответствуют два типа: x
соответствует "нормальному" типу вида *
(например Int
) а также xs
соответствует другому списку типов '[*]
, Правая часть определяет (newtype
) тип данных, который имеет конструктор HCons1
с параметром типа (x, HList xs)
,
В качестве примера мы можем иметь
HCons1 (1, HCons1 (True, HNil)) :: HList '[Int, Bool]
Или, используя синоним шаблона:
1 `HCons` True `HCons` HNil :: HList '[Int, Bool]
У меня нет хорошего ответа на ваш второй вопрос о том, почему он представлен как новый тип с кортежем.