2016-08-20 3 views
6

Вот синтаксис для исчисления лямбды с зависимой типией.Взаимно-рекурсивные синтаксисы с привязкой

data TermI a = Var a 
      | App (TermI a) (TermC a) -- when type-checking an application, infer the type of the function and then check that its argument matches the domain 
      | Star -- the type of types 
      | Pi (Type a) (Scope() Type a) -- The range of a pi-type is allowed to refer to the argument's value 
      | Ann (TermC a) (Type a) -- embed a checkable term by declaring its type 
      deriving (Functor, Foldable, Traversable) 

data TermC a = Inf (TermI a) -- embed an inferrable term 
      | Lam (Scope() TermC a) 
      deriving (Functor, Foldable, Traversable) 

type Type = TermC -- types are values in a dependent type system 

(я более или менее поднял это от Simply Easy.) Система типа bidirectional, расщепляющие термины в тех, чьи типе может быть выведена из контекста набора текста, и те, которые могут быть проверены только против цели тип. Это полезно в системах зависимых типов, поскольку в общем случае лямбда-члены не будут иметь принципиального типа.

Во всяком случае, я застрял, пытаясь определить Monad экземпляр для этого синтаксиса:

instance Monad TermI where 
    return = Var 
    Var x >>= f = f x 
    App fun arg >>= f = App (fun >>= f) (arg >>= Inf . f) -- embed the substituted TermI into TermC using Inf 
    Star >>= _ = Star 
    Pi domain range >>= f = Pi (domain >>= Inf . f) (range >>>= Inf . f) 
    Ann term ty >>= f = Ann (term >>= Inf . f) (ty >>= Inf . f) 

instance Monad TermC where 
    return = Inf . return 
    Lam body >>= f = Lam (body >>>= f) 
    Inf term >>= f = Inf (term >>= _) 

Чтобы заполнить дыру в последней строке, например TermC «s, мне нужно что-то типа a -> TermI b но f имеет тип a -> TermC b. Я не могу вставить полученный TermC в TermI с помощью конструктора Ann, потому что я не знаю тип TermC.

Является ли этот тип данных несовместимым с моделью bound? Или есть трюк, который я могу использовать, чтобы сделать экземпляр Monad?

+0

Если запустить (злоупотребление обозначения) '(вар 0 (Var 1)) [\ х -> х]', вы получите '(\ x -> x) (var 1)', который не имеет синтаксического представления в вашей системе типов. Обратите внимание, что оба '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ' Не обязательно иметь двунаправленную систему типов, чтобы определить двунаправленную проверку типов, поэтому вы можете просто свернуть эти взаимно-рекурсивные типы данных в один «Term». – user3237465

+1

'bound' не поддерживает взаимные данные, но (как было сказано выше) вы можете выполнить проверку вашего типа с помощью единого определения данных. Индексированная версия 'bound' может делать взаимные данные ([например] (http://lpaste.net/79582)), но она не существует как опубликованная библиотека. –

+0

Бросать все в один тип данных не без недостатков: он позволяет вам писать 'Lam' без аннотации, которая не должна быть синтаксически действительной. Я предполагаю, что мне может потребоваться тип в конструкторе 'Lam' (' Lam (Scope() Term a) Type'), но затем вы получаете лишние аннотации для вложенных lambdas, и вам нужно поддерживать дополнительную конструкцию для аннотирования других терминов. –

ответ

2

Это просто невозможно сделать: TermC не является монадой. Замещение ставит термины вместо переменных. Для того чтобы это имело смысл, термины должны быть в состоянии соответствовать, то есть быть достаточно похожими, чтобы полученный в результате термин по-прежнему обладал хорошими свойствами. Здесь это означает, что его тип должен быть неопровержимым. TermC не делаю.

Вы можете осуществить:

substI :: TermI a -> (a -> TermI b) -> TermI b 
substC :: TermC a -> (a -> TermI b) -> TermC b 

и имеют

instance Monad TermI where 
    return = Var 
    bind = substI 
+0

Этот вид работы - вы получаете экземпляр «Монады», но он заканчивается уродливо.Вы не можете использовать большинство комбинаторов 'bound' (в том числе' >>> = '- вам нужно реализовать' subst' '' fmap'ping под 'Scope'), потому что для этого требуется экземпляр' Monad' для ' Второй параметр Scope. Таким образом, вы в конечном итоге переопределяете большую часть 'bound'. –

Смежные вопросы