Как формируются контексты положения хвоста GH C точек соединения? - PullRequest
10 голосов
/ 02 августа 2020

Компиляция без продолжений описывает способ расширения ANF-системы F с помощью точек соединения. Сам GH C имеет точки соединения в Core (промежуточное представление), а не предоставляет точки соединения непосредственно на языке поверхностей (Haskell). Из любопытства я начал пытаться написать язык, который просто расширяет Систему F точками соединения. То есть точки соединения обращены к пользователю. Однако в правилах набора текста есть что-то, чего я не понимаю. Вот части, которые я понимаю:

  • Существуют две среды: одна для обычных значений / функций и одна, которая имеет только точки соединения. ε в некоторых правилах. В выражении let x:σ = u in ..., u не может ссылаться ни на какие точки соединения (VBIND), потому что точки соединения не могут возвращаться в произвольные места.
  • Странное правило ввода для JBIND. Газета хорошо объясняет это.

Вот чего я не понимаю. В документе вводится обозначение, которое я буду называть «стрелкой сверху», но сам документ не дает ему явного имени и не упоминает его. Визуально это выглядит как стрелка, указывающая вправо, и идет над выражением. Грубо говоря, это указывает на «хвостовой контекст» (в статье этот термин используется). В документе эти служебные стрелки могут применяться к терминам, типам, конструкторам данных и даже средам. Они также могут быть вложенными. Вот основная трудность, с которой я столкнулся. Есть несколько правил с предпосылками, которые включают окружения типов под стрелкой вверху. JUMP, CASE, RVBIND и RJBIND все включают помещения с такой средой (рис. 2 в документе). Однако ни одно из правил типизации не имеет вывода, где окружение типа находится под стрелкой вверху. Итак, я не вижу, как JUMP, CASE, и c. может когда-либо использоваться, поскольку предпосылки не могут быть выведены ни одним из других правил. системы типов System-F-with-join-points (кроме IR в GH C), это тоже будет полезно.

Ответы [ 2 ]

8 голосов
/ 02 августа 2020

В этом документе x⃗ означает «Последовательность x , разделенных соответствующими разделителями» .

Несколько примеров:

Если x - переменная, λ x⃗ . e - это сокращение от λ x 1 . λ x 2 . … Λ x n e . Другими словами, много вложенных лямбд с одним аргументом или лямбда с множеством аргументов.

Если σ и τ являются типами, σ⃗ τ - сокращение для σ 1 σ 2 →… → σ n τ . Другими словами, тип функции с множеством типов параметров.

Если a - это переменная типа, а σ - это тип, ∀ a⃗ . σ - это сокращение от ∀ a 1 . ∀ а 2 . … ∀ a n . σ . Другими словами, многие вложенные функции polymorphi c или функция polymorphi c с множеством параметров типа.

На рисунке 1 в документе синтаксис выражения перехода определяется как:

e , u , v ⩴… | прыжок j ϕ⃗ e⃗ τ

Если это объявление было переведено на a Haskell тип данных, это может выглядеть так:

data Term
  -- | A jump expression has a label that it jumps to, a list of type argument
  -- applications, a list of term argument applications, and the return type
  -- of the overall `jump`-expression.
  = Jump LabelVar [Type] [Term] Type
  | ... -- Other syntactic forms.

То есть конструктор данных, который принимает переменную-метку j , последовательность аргументов типа ϕ⃗ , последовательность аргументов термина e⃗ и тип возвращаемого значения τ .

«Объединение» вещей:

Иногда несколько Использование верхней стрелки накладывает неявное ограничение на то, что их последовательности имеют одинаковую длину. Одно из мест, где это происходит, - это замены.

{ ϕ / ⃗ a } означает «заменить a 1 с ϕ 1 , заменить a 2 на ϕ 2 ,…, заменить a n с ϕ n ”, неявно утверждая, что и a⃗ и ϕ⃗ имеют одинаковую длину, n .

Рабочий пример: правило JUMP:

Правило JUMP интересно тем, что оно обеспечивает несколько вариантов использования секвенирования и даже последовательность из помещений . Вот опять правило:

( j : ∀ a⃗ . σ⃗ → ∀ r . r ) ∈ Δ

(Γ; ε ⊢⃗ u : σ { ϕ / ⃗ а })

Γ; Δ ⊢ прыжок j ϕ⃗ u⃗ τ : τ

Первая посылка должна быть довольно простой, теперь: найдите j в контексте метки Δ и убедитесь, что тип j начинается с набора ∀, за которым следует набором типов функций, заканчивающихся на ∀ r . r .

Вторая «посылка» на самом деле представляет собой последовательность посылок. Что это зацикливается? Пока что последовательности, которые мы имеем в области видимости: ϕ⃗ , σ⃗ , a⃗ и u⃗ .

ϕ⃗ и a⃗ используются во вложенной последовательности, поэтому, вероятно, не эти два.

С другой стороны, u⃗ и σ⃗ кажутся вполне правдоподобными, если учесть, что они означают.

σ⃗ - это список типов аргументов, ожидаемых меткой j и u⃗ - это список терминов аргументов, предоставленный метке j , и имеет смысл, что вы можете захотеть перебирать типы аргументов и термины аргументов вместе.

Итак, эта «предпосылка» на самом деле означает что-то вроде этого:

для каждой пары σ и u :

Γ; ε u : σ { ϕ / ⃗ a }

Псевдо- Haskell реализация

Наконец, вот отчасти полный пример кода, иллюстрирующий, как это правило ввода может выглядеть в реальной реализации. x⃗ реализован как список x значений, а некоторая монада M используется для сигнализации отказа, когда предпосылка не выполняется.

data LabelVar
data Type
  = ...
data Term
  = Jump LabelVar [Type] [Term] Type
  | ...

typecheck :: TermContext -> LabelContext -> Term -> M Type
typecheck gamma delta (Jump j phis us tau) = do
  -- Look up `j` in the label context. If it's not there, throw an error.
  typeOfJ <- lookupLabel j delta
  -- Check that the type of `j` has the right shape: a bunch of `foralls`,
  -- followed by a bunch of function types, ending with `forall r.r`. If it
  -- has the correct shape, split it into a list of `a`s, a list of `\sigma`s
  -- and the return type, `forall r.r`.
  (as, sigmas, ret) <- splitLabelType typeOfJ
  
  -- exactZip is a helper function that "zips" two sequences together.
  -- If the sequences have the same length, it produces a list of pairs of
  -- corresponding elements. If not, it raises an error.
  for each (u, sigma) in exactZip (us, sigmas):
    -- Type-check the argument `u` in a context without any tail calls,
    -- and assert that its type has the correct form.
    sigma' <- typecheck gamma emptyLabelContext u
    
    -- let subst = { \sequence{\phi / a} }
    subst <- exactZip as phis
    assert (applySubst subst sigma == sigma')
  
  -- After all the premises have been satisfied, the type of the `jump`
  -- expression is just its return type.
  return tau
-- Other syntactic forms
typecheck gamma delta u = ...

-- Auxiliary definitions
type M = ...
instance Monad M

lookupLabel :: LabelVar -> LabelContext -> M Type
splitLabelType :: Type -> M ([TypeVar], [Type], Type)
exactZip :: [a] -> [b] -> M [(a, b)]
applySubst :: [(TypeVar, Type)] -> Type -> Type
2 голосов
/ 02 августа 2020

Насколько я знаю стиль обозначений SPJ, и он соответствует тому, что я вижу в статье, он просто означает «0 или больше». Например, вы можете заменить \overarrow{a} на a_1, …, a_n, n >= 0.

В некоторых случаях это может быть «1 или больше», но не составит труда определить, какой из двух.

...