#haskell #template-haskell #lenses #haskell-optics
Вопрос:
Когда я узнал об объективах Haskell с пакетом Optics, я столкнулся со следующим примером:
data Person = Person
{ _name :: String
, _age :: Int
}
makeLenses ''Person
makePrisms 'Person
Что представляет собой значение типа Name
и в чем разница между этим одинарным и двойным одинарным qoute/апострофом?
Оба, похоже, имеют один и тот же тип:
makeLenses, makePrisms :: Name -> DecsQ
Документация по шаблону-хаскеллу мне непонятна. В нем основное внимание уделяется синтаксису и отсутствуют примеры:
* 'f has type Name, and names the function f. Similarly 'C has type Name and names the data constructor C. In general '⟨thing⟩ interprets ⟨thing⟩ in an expression context.
* ''T has type Name, and names the type constructor T. That is, ''⟨thing⟩ interprets ⟨thing⟩ in a type context.
Ответ №1:
У нас есть две формы цитирования, чтобы различать конструктор данных и конструктор типов.
Рассмотрим этот вариант:
data Person = KPerson
{ _name :: String
, _age :: Int
}
makeLenses ''Person -- the type constructor
makePrisms 'KPerson -- the data constructor
Здесь ясно, что в одном случае мы используем a Name
для конструктора типов, в то время как в другом случае мы ссылаемся на a Name
для конструктора данных.
В принципе, Хаскелл мог бы использовать единую форму цитирования при условии, что имена конструкторов, таких как Person
и KPerson
, всегда различаются. Поскольку это не так, нам нужно устранить неоднозначность между наименованием типа и конструкторами данных.
Обратите внимание, что на практике принято использовать одно и то же имя для обоих конструкторов, поэтому эта неоднозначность часто требуется в реальном коде.
Комментарии:
1. Спасибо. Теперь я понимаю кавычки как создание метарепрезентаций конструкторов типов и значений отчетливо. Однако я все еще не понимаю, почему я могу передавать имена типов и значений взаимозаменяемо:
makeLenses ''Person
иmakeLenses 'KPerson
то, и другое, похоже, работает.2. @manews Это хороший аргумент. Внутренне я могу видеть из исходного кода, который
makeLenses
вызываетreifyDatatype
, в документации которого говорится: «Эта функция примет любой конструктор (значение или тип) для типа, объявленного с помощью newtype или данных». Так что, я думаю, это работает и то, и другое. hackage.haskell.org/package/th-abstraction-0.4.3.0/docs/… Похоже, это было сделано для того, чтобы заставить работать семейства данных -не самый распространенный случай.
Ответ №2:
Конструкторы типов и конструкторы терминов могут иметь одно и то же имя в Haskell, поэтому для обозначения разницы используются двойные и одинарные галочки соответственно. Вот этот пример из Оптики с различными названиями:
data Person = P
{ _name :: String
, _age :: Int
}
makeLenses ''Person
makePrisms 'P