В чем разница между одинарным двойным qoute/апострофом в шаблоне-хаскелл?

#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