Я слежу за этой записью в блоге: http://semantic-domain.blogspot.com/2012/12/total-functional-programming-in-partial.html
На нем показан небольшой компилятор OCaml для System T (простой полностью функциональный язык) а>.
Весь конвейер использует синтаксис OCaml (через метапрограммирование Camlp4), преобразует их в OCaml AST, который транслируется в лямбда-исчисление SystemT (см.: module Term
), а затем, наконец, в комбинаторное исчисление SystemT (см.: module Goedel
). Последний шаг также обернут метапрограммированием OCaml типа Ast.expr
.
Я пытаюсь перевести его на Haskell без использования Template Haskell.
Для формы SystemT Combinator я написал это как
{-# LANGUAGE GADTs #-}
data TNat = Zero | Succ TNat
data THom a b where
Id :: THom a a
Unit :: THom a ()
ZeroH :: THom () TNat
SuccH :: THom TNat TNat
Compose :: THom a b -> THom b c -> THom a c
Pair :: THom a b -> THom a c -> THom a (b, c)
Fst :: THom (a, b) a
Snd :: THom (a, b) b
Curry :: THom (a, b) c -> THom a (b -> c)
Eval :: THom ((a -> b), a) b -- (A = B) * A -> B
Iter :: THom a b -> THom (a, b) b -> THom (a, TNat) b
Обратите внимание, что Compose
— это прямая композиция, которая отличается от (.)
.
Во время преобразования лямбда-исчисления SystemT в комбинаторное исчисление SystemT функция Elaborate.synth
пытается преобразовать переменные лямбда-исчисления SystemT в ряд составных проекционных выражений (связанных с индексами Де Брюжина). Это связано с тем, что комбинаторное исчисление не имеет имен переменных/переменных. Это делается с помощью Elaborate.lookup
, который использует функцию Quote.find
.
Проблема в том, что с моей кодировкой комбинаторного исчисления как GADT THom a b
. Перевод функции Quote.find
:
let rec find x = function
| [] -> raise Not_found
| (x', t) :: ctx' when x = x' -> <:expr< Goedel.snd >>
| (x', t) :: ctx' -> <:expr< Goedel.compose Goedel.fst $find x ctx'$ >>
В Хаскеле:
find :: TVar -> Context -> _
find tvar [] = error "Not Found"
find tvar ((tvar', ttype):ctx)
| tvar == tvar' = Snd
| otherwise = Compose Fst (find tvar ctx)
Приводит к ошибке бесконечного типа.
• Occurs check: cannot construct the infinite type: a ~ (a, c)
Expected type: THom (a, c) c
Actual type: THom ((a, c), c) c
Проблема связана с тем, что использование Compose
, Fst
и Snd
из THom a b
GADT может привести к бесконечным вариациям подписи типа.
В статье нет этой проблемы, потому что она использует Ast.expr
OCaml для переноса основных выражений.
Я не уверен, как разрешить в Haskell. Должен ли я использовать экзистенциально квантифицированный тип, например
data TExpr = forall a b. TExpr (THom a b)
Или какой-то уровень типа Fix
для адаптации проблемы бесконечного типа. Однако я не уверен, как это меняет функции find
или lookup
.
tvar == tvar' = Snd
указывает, что find имеет типfind :: TVar -> Context -> THom (a, b) b
, следовательно,(find tvar ctx)
имеет тот же тип. поэтому тип аргументовCompose Fst (find tvar ctx)
какcompose (Thom (a, b) a) (Thom (a, b) b)
, Обратите внимание, что в определении compose нужно:a == (a, b)
, но это невозможно. - person assembly.jc   schedule 17.11.2018find :: TVar -> Context -> ???
. Простое, но неэстетичное решение — отказаться от GADT дляTHom
(и внедрить пристрастность повсюду). Другое решение состоит в том, чтобы попытаться стать полностью зависимым, введя больше индексов: что-то вродеfind :: TVar v -> Context c -> THom (F v c)
с некоторым семейством типовF
. Я уверен, что в Agda/Coq мы могли бы написать это, если бы у нас было достаточно времени. В Haskell нам, вероятно, нужно больше параметров доказательства, одноэлементных типов, если предположить, что это вообще выполнимо (я не совсем уверен). - person chi   schedule 17.11.2018find
? - person assembly.jc   schedule 17.11.2018(((),x),y)
, и для доступа кx
вы хотите использовать что-то вродеfst;snd
АКА отбросить последнюю переменную, взять следующую. Как правило, в более длинных контекстах вы генерируетеfst;fst;....;fst;snd
, чтобы отбросить многие переменные и взять в конце ту, которую вы хотите. Весь смысл этого заключается в том, чтобы мы выставляли больше информации в типе, в отличие, например. используя обычный список. Однако этот подход требует большого количества зависимых функций. - person chi   schedule 17.11.2018THom
. Вы должны сделать все рекурсивные вхождения строгими. Это не ухудшает и не улучшает проблему, с которой вы столкнулись, просто делает перевод ближе. (По крайней мере, я думаю, что добавление строгости решает проблему. Автор говорит, что лень вызывает пристрастие, но не предлагает решения). - person HTNW   schedule 18.11.2018let bad = Compose bad SuccH in bad
, должны быть запрещены. Я думаю, что либеральное применение аннотаций!
должно устранять такие вещи, например, что еслиfun :: THom a b
, то либоfun = _|_
, либоfun
является реальным, полным, тотальным, 100%-ным функционалом, без каких-либо пристрастий, в любом месте представления функции отa
доb
. - person HTNW   schedule 18.11.2018