Данный текст является переводом документации Template Haskell, написанной Булатом Зиганшиным. Перевод всего текста разбит на несколько логических частей для облегчения восприятия. Далее курсив в тексте — примечания переводчика. Предыдущие части:
Материализация (reification) — это средство Template Haskell, позволяющее программисту получить информацию из таблицы символов компилятора. Монадическая функция
Материализация может быть использована для того, чтобы получить структуру типа, но таким образом нельзя получить тело функции. Если вам нужно материализовать тело функции, то определение функции нужно процитировать и дальше можно будет работать с этим определением с помощью другого шаблона. Например так:
или так
На самом деле, в оригинальной статье больше ничего не говорится про материализацию. Не знаю, насколько это содержательная тема – необходимый минимум знаний о ней ограничивается функцией
Чтобы получить имя (
Эта новая форма тем не менее является цитированием и подчиняется тем же правилам, что и цитирующие скобки
Haskell’евские пространства имён немного всё усложняют. Цитата
Материализация
Материализация (reification) — это средство Template Haskell, позволяющее программисту получить информацию из таблицы символов компилятора. Монадическая функция
reify
∷ Name → Q Info
возвращает информацию о данном имени: если это глобальный идентификатор (функция, константа, конструктор) – вы получите его тип, если это тип или класс – вы получите его структуру. Определение типа Info
можно найти в модуле Language.Haskell.TH.Syntax
.Материализация может быть использована для того, чтобы получить структуру типа, но таким образом нельзя получить тело функции. Если вам нужно материализовать тело функции, то определение функции нужно процитировать и дальше можно будет работать с этим определением с помощью другого шаблона. Например так:
$(optimize [d| fib = … |])
или так
fib = $(optimize [| … |])
На самом деле, в оригинальной статье больше ничего не говорится про материализацию. Не знаю, насколько это содержательная тема – необходимый минимум знаний о ней ограничивается функцией
reify
и типом Info
, но есть некоторые тонкости, связанные например с тем, что можно получить информацию не о любом имени. Если эта тема интересна, я могу собрать какую-нибудь информацию и написать об этом отдельную заметку (или вклеить сюда).Облегчённое цитирование имён
Чтобы получить имя (
∷ Name
), соответствующее интересующему идентификатору, можно использовать функцию mkName
, но это не безопасное решение, потому что mkName
возвращает не квалифицированное имя, которое может интерпретироваться по-разному в зависимости от контекста. А вот код VarE id ← [| foo |]
безопасен в этом смысле, так как цитирование квалифицирует имена (получится что-то типа My.Own.Module.foo
), но этот код слишком многословный и требует монадический контекст для использования. К счастью, Template Haskell, имеет другую простую форму цитирования имён: 'foo
(одинарная кавычка перед foo
) имеет тип Name
и содержит квалифицированное имя, соответствующее идентификатору foo
, так что код let id = 'foo
эквивалентен по смыслу коду VarE id ← [| foo |]
. Обратите внимание, что эта конструкция имеет простой тип Name
(а не Q Exp
или Q Name
), так что она может быть использована там, где не возможно использование монад, например:f ∷ Exp → Exp
f (App (Var m) e) | m == 'map = …
Эта новая форма тем не менее является цитированием и подчиняется тем же правилам, что и цитирующие скобки
[| … |]
. Например, она не может быть использована внутри этих скобок (так нельзя: [| 'foo |]
), но и вклеивание к ней не может быть применено (так тоже нельзя: $( 'foo )
), потому что для вклейки нужен тип Q …
. Более важно то, что эта форма определяется статически, возвращая полностью квалифицированное имя, с однозначной интерпретацией.Haskell’евские пространства имён немного всё усложняют. Цитата
[| P |]
означает конструктор данных P
, в то время как [t| P |]
означает конструктор типа P
. Поэтому для “облегчённого цитирования” необходим такой же способ разделения этих сущностей. Для контекста типов используется просто две одинарные кавычки:'Foo
означает “конструктор данныхFoo
в контексте выражения”'foo
означает “имяfoo
в контексте выражения”''Foo
означает “конструктор типаFoo
в контексте типов”''foo
означает “переменная типаfoo
в контексте типов”
Show
, который разбирается в конце.