Почему этот шаблон Haskell работает? - PullRequest
4 голосов
/ 06 марта 2012

Рассмотрим этот код:

magic :: String -> Q Exp
magic s = [e| putStrLn s |]

Теперь, насколько я могу судить, это не должно сработать. Внутри оксфордских скобок s не входит в сферу применения. И все же вышеприведенное, по-видимому, прекрасно работает.

Если мы немного изменим этот пример, он теперь ужасно сломается:

magic :: Exp -> Q Exp
magic (VarE n) = [e| putStrLn (nameBase n) |]

Как и раньше, у нас есть переменная, не входящая в область видимости. И это время, оно ломается. Но он не жалуется на переменную не в области видимости; вместо этого он жалуется, что у какого-то недокументированного класса нет экземпляра.

Кто-нибудь знает, что, черт возьми, происходит?

Ответы [ 2 ]

12 голосов
/ 06 марта 2012

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

Например, экземпляр Lift для Integer s просто создает соответствующий целочисленный литерал, а экземпляр для Maybe просто создает соответствующие приложения-конструктор. Вы даже можете определить свои собственные экземпляры Lift.

Вы получаете ошибку «без экземпляра», потому что n - это Name, что Lift не в состоянии.

2 голосов
/ 06 марта 2012

Я думаю, что короткий ответ заключается в том, что магическая функция должна работать, так как кавычки действительно фиксируют свои локальные переменные (в некотором смысле).По сути, локальные переменные времени компиляции в квадратных скобках заменяются их литеральными значениями и становятся константами времени выполнения.Это достигается путем неявного вызова функции lift, так что [|.. var .. |] становится [|$ (lift var) |].

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

Если это поможет, я лично думаю о кавычках как о «генераторах сплайсинга» - маленьких фрагментах кода на Haskell, которые будут преобразованыв AST во время компиляции и, следовательно, станут соединениями, готовыми для вставки куда угодно.Как указывалось в руководствах Булата ( ссылки из ), они действуют как форма препроцессора макросов, так как они представляют собой смеси функций Haskell, генерирующих код, и простого автоматического преобразования кода haskell в TH AST.

Редактировать: Кажется, я побил меня ответом - я оставляю свой ответ, если он дает какую-то дополнительную ценность.

...