Как извлечь полезную информацию из полезной нагрузки GADT/экзистенциального типа?

Я пытаюсь использовать Menhir API добавочного синтаксического анализа и API самоанализа в сгенерированном синтаксическом анализаторе. Я хочу, скажем, определить семантическое значение, связанное с конкретной записью стека LR(1); токен, который ранее использовался синтаксическим анализатором.

Имея абстрактную контрольную точку синтаксического анализа, инкапсулированную в тип 'a env Менгира, я могу извлечь «элемент стека» из автомата LR; это выглядит так:

type element =
  | Element: 'a lr1state * 'a * position * position -> element

Элемент type описывает одну запись в стеке автомата LR(1). В элементе стека формы Element (s, v, startp, endp) s — это (не начальное) состояние, а v — семантическое значение. Значение v связано с входящим символом A состояния s. Другими словами, значение v было помещено в стек непосредственно перед переходом в состояние s. Таким образом, для некоторого типа 'a состояние s имеет тип 'a lr1state, а значение v имеет тип 'a...

Чтобы сделать что-нибудь полезное со значением v, нужно получить информацию о типе 'a путем проверки состояния s. Пока что тип 'a lr1state является абстрактным, поэтому нет возможности проверить s. API проверки (§9.3) предлагает дополнительные инструменты для этой цели.

Хорошо! Итак, я иду и углубляюсь в API проверки:

Терминал представляет собой обобщенный алгебраический тип данных (GADT). Значение типа 'терминал представляет терминальный символ (без семантического значения). Индекс 'a - это тип семантических значений, связанных с этим символом...

type _ terminal =
| T_A : unit terminal
| T_B : int terminal

Тип нетерминала также является GADT. Значение типа 'a nonterminal представляет собой нетерминальный символ (без семантического значения). Индекс 'a - это тип семантических значений, связанных с этим символом...

type _ nonterminal =
| N_main : thing nonterminal

Собрав их вместе, я получаю что-то вроде следующего (где команда — это один из нетерминалов моей грамматики, и, таким образом, N_command — это string nonterminal):

let current_command (env : 'a env) =
   let rec f i =
      match Interpreter.get i env with
      | None -> None
      | Some Interpreter.Element (lr1state, v, _startp, _endp) ->
      match Interpreter.incoming_symbol lr1state with
      | Interpreter.N Interpreter.N_command -> Some v
      | _ -> f (i + 1)
   in
   f 0

К сожалению, это вызывает у меня очень запутанные ошибки типа:

File "src/incremental.ml", line 110, characters 52-53:
Error: This expression has type string but an expression was expected of type
         string
       This instance of string is ambiguous:
       it would escape the scope of its equation

Это немного выше моего уровня! Я почти уверен, что понимаю, почему я не могу сделать то, что пытался сделать выше; но я не понимаю, каковы мои альтернативы. На самом деле, в руководстве Menhir конкретно упоминается об этой сложности:

Эту функцию можно использовать для получения доступа к семантическому значению v в элементе стека Element (s, v, _, _). В самом деле, анализируя случай символа incoming_symbol s, можно получить информацию о типе 'a, следовательно, получить возможность сделать что-то полезное со значением v.

Хорошо, но это то, что, как я думал, я сделал выше: анализ случая путем match обработки incoming_symbol s, извлечения случая, когда v относится к одному конкретному типу: string.

Вкратце: как мне извлечь полезную нагрузку строки из этого GADT и сделать с ней что-нибудь полезное?


person ELLIOTTCABLE    schedule 11.08.2019    source источник


Ответы (1)


Если ваша ошибка звучит как

Этот экземпляр строки неоднозначен: он выходит за рамки своего уравнения

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

 | Interpreter.(N N_command) -> Some (v:string)
person octachron    schedule 11.08.2019