Last active
May 11, 2020 05:30
-
-
Save brendanzab/7a331adae167ef6399c6b762aa943abd to your computer and use it in GitHub Desktop.
A dependently typed binary data description language, prototyped in Makam!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% Copyright 2020 YesLogic Pty. Ltd. | |
% | |
% Licensed under the Apache License, Version 2.0 (the "License"); | |
% you may not use this file except in compliance with the License. | |
% You may obtain a copy of the License at | |
% | |
% http://www.apache.org/licenses/LICENSE-2.0 | |
% | |
% Unless required by applicable law or agreed to in writing, software | |
% distributed under the License is distributed on an "AS IS" BASIS, | |
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
% See the License for the specific language governing permissions and | |
% limitations under the License. | |
% A dependently typed binary data description language, prototyped in Makam! | |
% | |
% I'm experimenting with Makam as a way of prototyping ideas for my exisiting | |
% ddl implementation at https://github.com/yeslogic/ddl. | |
% | |
% Roadmap: | |
% | |
% - [ ] split specification into multiple files | |
% - [-] core language | |
% - [-] language feautures | |
% - [x] basic MLTT (without identity types) | |
% - [x] basic binary format descriptions | |
% - [ ] unions | |
% - [ ] refinement types | |
% - [ ] multi-stage programming | |
% - [x] normalization by evaluation | |
% - [-] declarative typing rules | |
% - [x] bidirectional type checking rules | |
% - [ ] binary format interpretation | |
% - [ ] bidirectional elaboration | |
% - [ ] compilation passes | |
% - [ ] stratified | |
% - [ ] unkinded | |
% - [ ] uncurried | |
% - [ ] rust | |
% Core language | |
% | |
% The core language is an extension of Martin-Löf type theory, with some builtin | |
% data types, like booleans, integers, and arrays, and support for defining | |
% binary format descriptions. We skip identity types and η-rules for now. | |
% | |
% In making this language, we owe much of our inspiration to the work on PADS/ML | |
% and the data description calculus (DDC) in ["The Next 700 Data Description Languages"]. | |
% In contrast to DDC, we have decided to 'embed' format descriptions within a | |
% dependendently typed language rather than splitting the language up into | |
% separate format and host languages. | |
% | |
% At the moment it's possible to describe 'dependent format descriptions'. This | |
% could be useful for 'extensible' binary formats, but it makes compilation much | |
% harder. We might ultimately want to restrict this in the future for ease of | |
% compilation through some use of [multi-stage programming], either using an | |
% approach based on [modal type theory], or by 'intentionally' conflating | |
% 'phase' with 'universe level', as described in ["Phase Distinctions in Type Theory"]. | |
% | |
% ["Phase Distinctions in Type Theory"]: http://lucacardelli.name/Papers/PhaseDistinctions.A4.pdf | |
% ["The Next 700 Data Description Languages"]: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.156.1375 | |
% [modal type theory]: https://jozefg.github.io/papers/2019-implementing-modal-dependent-type-theory.pdf | |
% [multi-stage programming]: https://github.com/metaocaml/metaocaml-bibliography | |
%extend core. | |
% Syntax | |
% | |
% This section defines the core syntax of the data description language. | |
% | |
% # A note on naming | |
% | |
% In general we try to keep to the following naming scheme: | |
% | |
% - `thing_type` describes the shape of some `thing` | |
% - `thing_intro` introduces an element of `thing_type` | |
% - `thing_elim` eliminates an element of `thing_type` | |
% | |
% Based on this naming-scheme, we follow this terminology mapping: | |
% | |
% | [Type theory] name | Our name | | |
% | ----------------------- | --------------------- | | |
% | [Pi type] | `function_type` | | |
% | [Lambda abstraction] | `function_intro` | | |
% | [Function application] | `function_elim` | | |
% | [Sigma type] | `pair_type` | | |
% | [Pairing] | `pair_intro` | | |
% | Project first | `pair_elim_first` | | |
% | Project second | `pair_elim_second` | | |
% | |
% [Type theory]: https://ncatlab.org/nlab/show/type+theory | |
% [Pi type]: https://ncatlab.org/nlab/show/dependent+product+type | |
% [Lambda abstraction]: https://ncatlab.org/nlab/show/lambda-abstraction | |
% [Function application]: https://ncatlab.org/nlab/show/function+application | |
% [Sigma type]: https://ncatlab.org/nlab/show/dependent+sum+type | |
% [Pairing]: https://ncatlab.org/nlab/show/pairing | |
% | |
% I'm not entirely sold on these suffixes - here are some alternatives that | |
% I've currently come up with: | |
% | |
% - `_type`, `_elem`, `_apply` | |
% - `_type`, `_elem`, `_call` | |
% - `_space`, `_point`, `_???` | |
% | |
% Let me know if you have other ideas! | |
% | |
% # An annoying naming issue | |
% | |
% I have `InputTerm : term` for a function argument, that then gets | |
% evaluated to `InputValue : value`. but then I have `InputType : term` for | |
% a parameter type... but I can't do `InputValue : value` - it's already | |
% taken for the term level! And I can't do `InputType : type` because that's | |
% taken by the term. | |
% Terms | |
term : type. | |
% Variables | |
local : int -> term. % Local variables (using De Bruijn indices) | |
% Annotated terms | |
ann : term -> term -> term. | |
% Universes | |
universe : term. | |
% Void | |
void_type : term. | |
% Unit | |
unit_type : term. | |
unit_intro : term. | |
% Functions | |
function_type : term -> term -> term. % Also known as: Pi type, Dependent product type | |
function_intro : term -> term. % Also known as: Lambda abstraction, anonymous function | |
function_elim : term -> term -> term. % Also known as: Function application | |
% Pairs | |
pair_type : term -> term -> term. % Also known as: Sigma type, Dependent sum type | |
pair_intro : term -> term -> term. % Also known as: Pair constructor | |
pair_elim_first : term -> term. | |
pair_elim_second : term -> term. | |
% Refinements | |
% refine_type : term -> term -> term. | |
% refine_intro : term -> (* some proof from a solver here? *) -> term. | |
% Staging | |
% stage_type : term -> term. | |
% stage_intro : term -> term. | |
% stage_elim : term -> term. | |
% Booleans | |
bool_type : term. | |
bool_intro : bool -> term. | |
bool_elim : term -> term -> term -> term. | |
% Integers | |
int_type : term. | |
int_intro : int -> term. | |
% Arrays | |
array_type : term -> term -> term. | |
array_intro : list term -> term. | |
array_elim : term -> term -> term. | |
% Binary format descriptions | |
format_type : term. | |
format_intro_void : term. | |
format_intro_unit : term. | |
format_intro_u8 : term. | |
format_intro_u16le : term. % TODO: make this a computed format? | |
format_intro_u16be : term. % TODO: make this a computed format? | |
format_intro_u32le : term. % TODO: make this a computed format? | |
format_intro_u32be : term. % TODO: make this a computed format? | |
format_intro_u64le : term. % TODO: make this a computed format? | |
format_intro_u64be : term. % TODO: make this a computed format? | |
format_intro_s8 : term. % TODO: make this a computed format? | |
format_intro_s16le : term. % TODO: make this a computed format? | |
format_intro_s16be : term. % TODO: make this a computed format? | |
format_intro_s32le : term. % TODO: make this a computed format? | |
format_intro_s32be : term. % TODO: make this a computed format? | |
format_intro_s64le : term. % TODO: make this a computed format? | |
format_intro_s64be : term. % TODO: make this a computed format? | |
format_intro_array : term -> term -> term. | |
format_intro_pair : term -> term -> term. | |
format_elim : term -> term. | |
% Items | |
item : type. | |
declaration : string -> term -> item. | |
definition : string -> term -> item. | |
%extend typing. | |
% Declarative Typing | |
% | |
% This section defines the typing rules in a way that is close to a | |
% standard presentation of Martin-Löf Type Theory with explicit | |
% substitutions. The disadvantage of this description is that it's hard | |
% to derive an actual type checker implementation directly from these | |
% rules. We instead to this later on, by describing a bidirectional type | |
% checking algorithm in the `core.typing.bidirectional` namespace. | |
% Further reading: | |
% | |
% - https://intuitionistic.files.wordpress.com/2010/07/martin-lof-tt.pdf | |
% - http://www.cse.chalmers.se/research/group/logic/book/book.pdf | |
%extend declarative. | |
% Declarative typing context | |
context : type. | |
% Empty typing context | |
empty : context. | |
% A typing context, extended with a new binding | |
extend : context -> term -> context. | |
is_context : context -> prop. | |
is_type : context -> term -> prop. | |
is_elem : context -> term -> term -> prop. | |
% is_subst : context -> subst -> context -> prop. | |
is_equal_type : context -> term -> term -> prop. | |
is_equal_elem : context -> term -> term -> term -> prop. | |
% is_equal_subst : context -> subst -> subst -> context -> prop. | |
% Contexts | |
is_context empty. | |
is_context (extend Context Type) :- | |
is_context Context, | |
is_type Context Type. | |
% Reflexivity | |
is_equal_type Context Type Type :- | |
is_type Context Type. | |
is_equal_elem Context Term Term Type :- | |
is_type Context Type. | |
% Symmetry | |
is_equal_type Context Type1 Type2 :- | |
is_equal_type Context Type2 Type1. | |
is_equal_elem Context Term1 Term2 Type :- | |
is_equal_elem Context Term2 Term1 Type. | |
% Transitivity | |
is_equal_type Context Type1 Type3 :- | |
is_equal_type Context Type1 Type2, | |
is_equal_type Context Type2 Type3. | |
is_equal_elem Context Term1 Term3 Type :- | |
is_equal_elem Context Term1 Term2 Type, | |
is_equal_elem Context Term1 Term3 Type. | |
% Type Equality | |
is_elem Context Term Type2 :- | |
is_elem Context Term Type1, | |
is_equal_type Context Type1 Type2. | |
is_equal_elem Context Term1 Term2 Type2 :- | |
is_equal_elem Context Term1 Term2 Type1, | |
is_equal_type Context Type1 Type2. | |
% Variables | |
is_type (extend Context Type) (local 0) :- | |
is_type Context Type. | |
is_type (extend Context _) (local Index) :- | |
plus PrevIndex 1 Index, | |
is_type Context (local PrevIndex). | |
is_elem (extend Context Type') (local 0) Type :- | |
is_elem Context Type' Type. | |
is_elem (extend Context _) (local Index) Type :- | |
plus PrevIndex 1 Index, | |
is_elem Context (local PrevIndex) Type. | |
% Universes | |
is_type Context universe :- | |
is_context Context. | |
% Void | |
is_type Context void_type :- | |
is_context Context. | |
is_elem Context void_type universe :- | |
is_context Context. | |
% Unit | |
is_type Context unit_type :- | |
is_context Context. | |
is_elem Context unit_type universe :- | |
is_context Context. | |
is_elem Context unit_intro unit_type :- | |
is_context Context. | |
% Functions | |
is_type Context (function_type InputType OutputType) :- | |
is_type Context InputType, | |
is_type (extend Context InputType) OutputType. | |
is_elem Context (function_type InputType OutputType) universe :- | |
is_type Context InputType, | |
is_type (extend Context InputType) OutputType. | |
is_elem Context (function_intro OutputTerm) (function_type InputType OutputType) :- | |
is_type Context InputType, | |
is_elem (extend Context InputType) OutputTerm OutputType. | |
% is_elem Context (function_elim (function_intro OutputTerm) InputTerm) OutputType :- TODO. | |
% is_equal_elem Context (function_elim (function_intro OutputTerm) InputTerm) Term OutputType :- TODO. | |
% Pairs | |
is_type Context (pair_type FirstType SecondType) :- | |
is_elem Context FirstType universe, | |
is_elem (extend Context FirstType) SecondType universe. | |
is_elem Context (pair_type FirstType SecondType) universe :- | |
is_elem Context FirstType universe, | |
is_elem (extend Context FirstType) SecondType universe. | |
% is_elem Context (pair_intro FirstTerm SecondTerm) (pair_type FirstType SecondType) :- TODO. | |
% is_elem Context (pair_elim_first (pair_intro FirstTerm SecondTerm)) FirstType :- TODO. | |
% is_elem Context (pair_elim_second (pair_intro FirstTerm SecondTerm)) SecondType :- TODO. | |
% is_equal_elem Context (pair_elim_first (pair_intro FirstTerm SecondTerm)) Term FirstType :- TODO. | |
% is_equal_elem Context (pair_elim_second (pair_intro FirstTerm SecondTerm)) Term SecondType :- TODO. | |
% Booleans | |
is_type Context bool_type :- | |
is_context Context. | |
is_elem Context bool_type universe :- | |
is_context Context. | |
is_elem Context (bool_intro _) bool_type :- | |
is_context Context. | |
is_elem Context (bool_elim BoolTerm TrueTerm FalseTerm) Type :- | |
is_elem Context BoolTerm bool_type, | |
is_type Context Type, | |
is_elem Context TrueTerm Type, | |
is_elem Context FalseTerm Type. | |
is_equal_elem Context (bool_elim (bool_intro true) TrueTerm FalseTerm) TrueTerm Type :- | |
is_type Context Type, | |
is_elem Context TrueTerm Type, | |
is_elem Context FalseTerm Type. | |
is_equal_elem Context (bool_elim (bool_intro false) TrueTerm FalseTerm) FalseTerm Type :- | |
is_type Context Type, | |
is_elem Context TrueTerm Type, | |
is_elem Context FalseTerm Type. | |
% Integers | |
is_type Context int_type :- | |
is_context Context. | |
is_elem Context int_type universe :- | |
is_context Context. | |
is_elem Context (int_intro _) int_type :- | |
is_context Context. | |
% Arrays | |
is_type Context (array_type ElemType LenTerm) :- | |
is_elem Context ElemType universe, | |
is_elem Context LenTerm int_type. | |
is_elem Context (array_type ElemType LenTerm) universe :- | |
is_elem Context ElemType universe, | |
is_elem Context LenTerm int_type. | |
is_elem Context (array_intro ElemTerms) (array_type ElemType LenTerm) :- | |
is_equal_elem Context (int_intro Len) LenTerm int_type, | |
length ElemTerms Len, | |
map (fun elem_term => is_elem Context elem_term ElemType) ElemTerms. | |
is_equal_elem Context (array_elim (array_intro ElemTerms) IndexTerm) ElemTerm ElemType :- | |
% FIXME: ensure `IndexTerm` is in array bounds, possibly with refinement types? | |
is_equal_elem Context (int_intro Index) IndexTerm int_type, | |
map (fun elem_term => is_elem Context elem_term ElemType) ElemTerms, | |
list.nth ElemTerms Index ElemTerm. | |
% Binary format descriptions | |
is_type Context format_type :- | |
is_context Context. | |
is_elem Context format_intro_void format_type :- | |
is_context Context. | |
is_elem Context format_intro_unit format_type :- | |
is_context Context. | |
is_elem Context format_intro_u8 format_type :- | |
is_context Context. | |
is_elem Context format_intro_u16le format_type :- | |
is_context Context. | |
is_elem Context format_intro_u16be format_type :- | |
is_context Context. | |
is_elem Context format_intro_u32le format_type :- | |
is_context Context. | |
is_elem Context format_intro_u32be format_type :- | |
is_context Context. | |
is_elem Context format_intro_u64le format_type :- | |
is_context Context. | |
is_elem Context format_intro_u64be format_type :- | |
is_context Context. | |
is_elem Context format_intro_s8 format_type :- | |
is_context Context. | |
is_elem Context format_intro_s16le format_type :- | |
is_context Context. | |
is_elem Context format_intro_s16be format_type :- | |
is_context Context. | |
is_elem Context format_intro_s32le format_type :- | |
is_context Context. | |
is_elem Context format_intro_s32be format_type :- | |
is_context Context. | |
is_elem Context format_intro_s64le format_type :- | |
is_context Context. | |
is_elem Context format_intro_s64be format_type :- | |
is_context Context. | |
is_elem Context (format_intro_array ElemType LenTerm) format_type :- | |
is_elem Context ElemType format_type, | |
is_elem Context LenTerm int_type. | |
is_elem Context (format_intro_pair FirstType SecondType) format_type :- | |
is_elem Context FirstType format_type, | |
is_elem (extend Context (format_elim FirstType)) SecondType format_type. | |
is_equal_elem Context (format_elim format_intro_void) void_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_unit) unit_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_u8) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_u16le) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_u16be) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_u32le) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_u32be) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_u64le) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_u64be) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_s8) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_s16le) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_s16be) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_s32le) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_s32be) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_s64le) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim format_intro_s64be) int_type universe :- | |
is_context Context. | |
is_equal_elem Context (format_elim (format_intro_array ElemType LenTerm)) (array_type ElemType' LenTerm) format_type :- | |
is_equal_elem Context (format_elim ElemType) ElemType' universe. | |
% TODO: format_intro_pair | |
%end. | |
%end. | |
% Semantics | |
% | |
% This section defines an operational semantics for language, using | |
% normalization-by-evaluation for performance reasons. | |
%extend semantics. | |
% The result of evaluating a term. | |
value : type. | |
% Neutral values are computations that are currently 'stuck' on some | |
% as-yet unknown computation. We build up a 'spine' of eliminations | |
% that cannot yet reduce in preperation for if they become 'unstuck'. | |
neutral : type. | |
% Closures are terms from the core syntax that have yet to be evaluated. | |
% They capture an environment of values to be used later, when they are | |
% finally evaluated. | |
closure : type. | |
% Neutral values | |
neutral : neutral -> value. | |
% Universes | |
universe : value. | |
% Void | |
void_type : value. | |
% Unit | |
unit_type : value. | |
unit_intro : value. | |
% Functions | |
function_type : value -> closure -> value. % Also known as: Pi type, Dependent product type | |
function_intro : closure -> value. % Also known as: Lambda abstraction, anonymous function | |
% Pairs | |
pair_type : value -> closure -> value. % Also known as: Sigma type, Dependent sum type | |
pair_intro : value -> value -> value. % Also known as: Pair constructor | |
% Refinements | |
% refine_type : value -> closure -> value. | |
% refine_intro : value -> (* some proof from a solver here? *) -> value. | |
% Staging | |
% stage_type : value -> value. | |
% stage_intro : value -> value. | |
% Booleans | |
bool_type : value. | |
bool_intro : bool -> value. | |
% Integers | |
int_type : value. | |
int_intro : int -> value. | |
% Arrays | |
array_type : value -> value -> value. | |
array_intro : list value -> value. | |
% Binary format descriptions | |
format_type : value. | |
format_intro_void : value. | |
format_intro_unit : value. | |
format_intro_u8 : value. | |
format_intro_u16le : value. | |
format_intro_u16be : value. | |
format_intro_u32le : value. | |
format_intro_u32be : value. | |
format_intro_u64le : value. | |
format_intro_u64be : value. | |
format_intro_s8 : value. | |
format_intro_s16le : value. | |
format_intro_s16be : value. | |
format_intro_s32le : value. | |
format_intro_s32be : value. | |
format_intro_s64le : value. | |
format_intro_s64be : value. | |
format_intro_array : value -> value -> value. | |
format_intro_pair : value -> closure -> value. | |
% Variables | |
local : int -> neutral. % Local variables (using De Bruijn levels) | |
% Suspended eliminations | |
function_elim : neutral -> value -> neutral. | |
pair_elim_first : neutral -> neutral. | |
pair_elim_second : neutral -> neutral. | |
% stage_elim : neutral -> neutral. | |
% bool_elim : neutral -> value -> value -> neutral. | |
% array_elim : neutral -> value -> neutral. | |
format_elim : neutral -> neutral. | |
closure : list value -> term -> closure. | |
% Evaluation of terms into values | |
eval : list value -> term -> value -> prop. | |
apply : closure -> value -> value -> prop. | |
apply_param : closure -> int -> value -> prop. | |
function_elim : value -> value -> value -> prop. | |
pair_elim_first : value -> value -> prop. | |
pair_elim_second : value -> value -> prop. | |
% stage_elim : value -> value -> prop. | |
% bool_elim : value -> value -> value -> value -> prop. | |
% array_elim : value -> value -> value -> prop. | |
format_elim : value -> value -> prop. | |
eval Values (local Index) Value :- | |
list.nth Values Index Value. | |
eval Values (ann Term _) Value :- | |
eval Values Term Value. | |
eval Values universe universe. | |
eval Values void_type void_type. | |
eval Values unit_type unit_type. | |
eval Values unit_intro unit_intro. | |
eval Values (function_type InputType OutputType) (function_type InputType' (closure Values OutputType)) :- | |
eval Values InputType InputType'. | |
eval Values (function_intro OutputTerm) (function_intro (closure Values OutputTerm)). | |
eval Values (function_elim Term InputTerm) Value' :- | |
eval Values Term Value, | |
eval Values InputTerm InputValue, | |
function_elim Value InputValue Value'. | |
eval Values (pair_type FirstType SecondType) (pair_type FirstType' (closure Values SecondType)) :- | |
eval Values FirstType FirstType'. | |
eval Values (pair_intro FirstTerm SecondTerm) (pair_intro FirstValue SecondValue) :- | |
eval Values FirstTerm FirstValue, | |
eval Values SecondTerm SecondValue. | |
eval Values (pair_elim_first PairTerm) FirstValue :- | |
eval Values PairTerm PairValue, | |
pair_elim_first PairValue FirstValue. | |
eval Values (pair_elim_second PairTerm) SecondValue :- | |
eval Values PairTerm PairValue, | |
pair_elim_second PairValue SecondValue. | |
eval Values bool_type bool_type. | |
eval Values (bool_intro Bool) (bool_intro Bool). | |
% FIXME: This breaks for neutral terms! We should use `bool_elim` here. | |
eval Values (bool_elim BoolTerm TrueTerm _) Value :- | |
eval Values BoolTerm (bool_intro true), | |
eval Values TrueTerm Value. | |
eval Values (bool_elim BoolTerm _ False1Term) Value :- | |
eval Values BoolTerm (bool_intro false), | |
eval Values FalseTerm Value. | |
eval Values int_type int_type. | |
eval Values (int_intro Int) (int_intro Int). | |
eval Values (array_type ElemType LenTerm) (array_type ElemType' LenValue) :- | |
eval Values ElemType ElemType', | |
eval Values LenTerm LenValue. | |
eval Values (array_intro ElemTerms) (array_intro ElemValues) :- | |
map (fun term value => eval Values term value) ElemTerms ElemValues. | |
% FIXME: This breaks for neutral terms! We should use `array_elim` here. | |
eval Values (array_elim ArrayTerm IndexTerm) ElemValue :- | |
eval Values ArrayTerm (array_intro ElemValues), | |
eval Values IndexTerm (int_intro Index), | |
list.nth ElemValues Index ElemValue. | |
eval Values format_type format_type. | |
eval Values format_intro_void format_intro_void. | |
eval Values format_intro_unit format_intro_unit. | |
eval Values format_intro_u8 format_intro_u8. | |
eval Values format_intro_u16le format_intro_u16le. | |
eval Values format_intro_u16be format_intro_u16be. | |
eval Values format_intro_u32le format_intro_u32le. | |
eval Values format_intro_u32be format_intro_u32be. | |
eval Values format_intro_u64le format_intro_u64le. | |
eval Values format_intro_u64be format_intro_u64be. | |
eval Values format_intro_s8 format_intro_s8. | |
eval Values format_intro_s16le format_intro_s16le. | |
eval Values format_intro_s16be format_intro_s16be. | |
eval Values format_intro_s32le format_intro_s32le. | |
eval Values format_intro_s32be format_intro_s32be. | |
eval Values format_intro_s64le format_intro_s64le. | |
eval Values format_intro_s64be format_intro_s64be. | |
eval Values (format_intro_array ElemType LenTerm) (format_intro_array ElemType' LenValue) :- | |
eval Values ElemType ElemType', | |
eval Values LenTerm LenValue. | |
eval Values (format_intro_pair FirstType SecondType) (format_intro_pair FirstType' (closure Values SecondType)) :- | |
eval Values FirstType FirstType'. | |
eval Values (format_elim Term) Value' :- | |
eval Values Term Value, | |
format_elim Value Value'. | |
% Closure operations | |
apply (closure Values Term) InputValue Value :- | |
eval (InputValue :: Values) Term Value. | |
apply_param Closure Length Value :- | |
apply Closure (neutral (local Length)) Value. | |
% Eliminations | |
function_elim (neutral Neutral) InputValue (neutral (function_elim Neutral InputValue)). | |
function_elim (function_intro Closure) InputValue OutputValue :- | |
apply Closure InputValue OutputValue. | |
pair_elim_first (neutral Neutral) (neutral (pair_elim_first Neutral)). | |
pair_elim_first (pair_intro FirstValue _) FirstValue. | |
pair_elim_second (neutral Neutral) (neutral (pair_elim_second Neutral)). | |
pair_elim_second (pair_intro _ SecondValue) SecondValue. | |
% TODO: stage_elim | |
% bool_elim (neutral Neutral) TrueValue FalseValue (neutral (bool_elim Neutral TrueValue FalseValue)). | |
% bool_elim (bool_intro true) TrueValue _ TrueValue. | |
% bool_elim (bool_intro false) _ FalseValue FalseValue. | |
% TODO: array_elim | |
format_elim (neutral Neutral) (neutral (format_elim Neutral)). | |
format_elim format_intro_void void_type. | |
format_elim format_intro_unit unit_type. | |
format_elim format_intro_u8 int_type. | |
format_elim format_intro_u16le int_type. | |
format_elim format_intro_u16be int_type. | |
format_elim format_intro_u32le int_type. | |
format_elim format_intro_u32be int_type. | |
format_elim format_intro_u64le int_type. | |
format_elim format_intro_u64be int_type. | |
format_elim format_intro_s8 int_type. | |
format_elim format_intro_s16le int_type. | |
format_elim format_intro_s16be int_type. | |
format_elim format_intro_s32le int_type. | |
format_elim format_intro_s32be int_type. | |
format_elim format_intro_s64le int_type. | |
format_elim format_intro_s64be int_type. | |
format_elim (format_intro_array Elem Len) (array_type Elem' Len) :- | |
format_elim Elem Elem'. | |
format_elim (format_intro_pair First (closure Values Term)) (pair_type First' (closure Values (format_elim Term))) :- | |
format_elim First First'. | |
% Readback of values into terms in normal form | |
readback : int -> neutral -> term -> prop. | |
readback : int -> value -> term -> prop. | |
% FIXME: Makam's type unification breaks hear for some reason - it | |
% thinks that we want to definine `int -> value -> term -> prop.` | |
readback Length (local Level : neutral) (local Index) :- | |
% Convert De Bruijn levels to De Bruijn indices using the following | |
% arithmetic (this is a bit awkward to express in Makam): | |
% | |
% ``` | |
% Index = Length - (Level + 1) | |
% ``` | |
plus 1 Level Level1, | |
plus Level1 Index Length. | |
readback Length (function_elim Neutral InputValue : neutral) (function_elim Term InputTerm) :- | |
readback Length Neutral Term, | |
readback Length InputValue InputTerm. | |
readback Length (pair_elim_first Neutral : neutral) (pair_elim_first Term) :- | |
readback Length Neutral Term. | |
readback Length (pair_elim_second Neutral : neutral) (pair_elim_second Term) :- | |
readback Length Neutral Term. | |
readback Length (format_elim Neutral : neutral) (format_elim Term) :- | |
readback Length Neutral Term. | |
readback Length (neutral Neutral) Term :- | |
readback Length Neutral Term. | |
readback Length universe universe. | |
readback Length void_type void_type. | |
readback Length unit_type unit_type. | |
readback Length unit_intro unit_intro. | |
readback Length (function_type InputType Closure) (function_type InputType' OutputType') :- | |
readback Length InputType InputType', | |
apply_param Closure Length OutputType, | |
plus Length 1 Length1, | |
readback Length1 OutputType OutputType'. | |
readback Length (function_intro Closure) (function_intro OutputTerm') :- | |
apply_param Closure Length OutputTerm, | |
plus Length 1 Length1, | |
readback Length1 OutputTerm OutputTerm'. | |
readback Length (pair_type FirstType Closure) (pair_type FirstType' SecondType') :- | |
readback Length FirstType FirstType', | |
apply_param Closure Length SecondType, | |
plus Length 1 Length1, | |
readback Length1 SecondType SecondType'. | |
readback Values (pair_intro FirstValue SecondValue) (pair_intro FirstTerm SecondTerm) :- | |
readback Values FirstValue FirstType, | |
readback Values SecondValue SecondType. | |
readback Length bool_type bool_type. | |
readback Length (bool_intro Bool) (bool_intro Bool). | |
readback Length int_type int_type. | |
readback Length (int_intro Int) (int_intro Int). | |
readback Length (array_type ElemValue LenValue) (array_type ElemType LenTerm) :- | |
readback Length ElemValue ElemType, | |
readback Length LenValue LenTerm. | |
readback Length (array_intro ElemValues) (array_intro ElemTerms) :- | |
map (fun value term => readback Length value term) ElemValues ElemTerms. | |
readback Length format_type format_type. | |
readback Length format_intro_void format_intro_void. | |
readback Length format_intro_unit format_intro_unit. | |
readback Length format_intro_u8 format_intro_u8. | |
readback Length format_intro_u16le format_intro_u16le. | |
readback Length format_intro_u16be format_intro_u16be. | |
readback Length format_intro_u32le format_intro_u32le. | |
readback Length format_intro_u32be format_intro_u32be. | |
readback Length format_intro_u64le format_intro_u64le. | |
readback Length format_intro_u64be format_intro_u64be. | |
readback Length format_intro_s8 format_intro_s8. | |
readback Length format_intro_s16le format_intro_s16le. | |
readback Length format_intro_s16be format_intro_s16be. | |
readback Length format_intro_s32le format_intro_s32le. | |
readback Length format_intro_s32be format_intro_s32be. | |
readback Length format_intro_s64le format_intro_s64le. | |
readback Length format_intro_s64be format_intro_s64be. | |
readback Length (format_intro_array ElemValue LenValue) (format_intro_array ElemType LenTerm) :- | |
readback Length ElemValue ElemType, | |
readback Length LenValue LenTerm. | |
readback Length (format_intro_pair FirstType Closure) (format_intro_pair FirstType' SecondType') :- | |
readback Length FirstType FirstType', | |
apply_param Closure Length SecondType, | |
plus Length 1 Length1, | |
readback Length1 SecondType SecondType'. | |
% Normalization-by-evaluation | |
normalize : list value -> term -> term -> prop. | |
normalize Values Term Term' :- | |
eval Values Term Value, | |
length Values Length, | |
readback Length Value Term'. | |
normalize : term -> term -> prop. | |
normalize Term Term' :- | |
normalize [] Term Term'. | |
% Equality of values | |
is_equal : int -> neutral -> neutral -> prop. | |
is_equal : int -> value -> value -> prop. | |
% FIXME: Makam's type unification breaks hear for some reason - it | |
% thinks that we want to definine `int -> value -> term -> prop.` | |
is_equal Length (local Level : neutral) (local Level). | |
is_equal Length (function_elim Neutral1 InputValue1 : neutral) (function_elim Neutral2 InputValue2) :- | |
is_equal Length Neutral1 Neutral2, | |
is_equal Length InputValue1 InputValue2. | |
is_equal Length (pair_elim_first Neutral1 : neutral) (pair_elim_first Neutral2) :- | |
is_equal Length Neutral1 Neutral2. | |
is_equal Length (pair_elim_second Neutral1 : neutral) (pair_elim_second Neutral2) :- | |
is_equal Length Neutral1 Neutral2. | |
is_equal Length (format_elim Neutral1 : neutral) (format_elim Neutral2) :- | |
is_equal Length Neutral1 Neutral2. | |
is_equal Length (neutral Neutral1) (neutral Neutral2) :- | |
is_equal Length Neutral1 Neutral2. | |
is_equal Length universe universe. | |
is_equal Length void_type void_type. | |
is_equal Length unit_type unit_type. | |
is_equal Length unit_intro unit_intro. | |
is_equal Length (function_type InputType1 Closure1) (function_type InputType2 Closure2) :- | |
is_equal Length InputType1 InputType2, | |
apply_param Closure1 Length OutputType1, | |
apply_param Closure2 Length OutputType2, | |
plus Length 1 Length1, | |
is_equal Length1 OutputType1 OutputType2. | |
is_equal Length (function_intro Closure1) (function_intro Closure2) :- | |
apply_param Closure1 Length OutputValue1, | |
apply_param Closure2 Length OutputValue2, | |
plus Length 1 Length1, | |
is_equal Length1 OutputValue1 OutputValue2. | |
is_equal Length (pair_type FirstType1 Closure1) (pair_type FirstType2 Closure2) :- | |
is_equal Length FirstType1 FirstType2, | |
apply_param Closure1 Length SecondType1, | |
apply_param Closure2 Length SecondType2, | |
plus Length 1 Length1, | |
is_equal Length1 SecondType1 SecondType2. | |
is_equal Length (pair_intro FirstTerm1 SecondTerm1) (pair_intro FirstTerm2 SecondTerm2) :- | |
is_equal Length FirstTerm1 FirstTerm2, | |
is_equal Length SecondTerm1 SecondTerm2. | |
is_equal Length bool_type bool_type. | |
is_equal Length (bool_intro Bool) (bool_intro Bool). | |
is_equal Length int_type int_type. | |
is_equal Length (int_intro Bool) (int_intro Bool). | |
is_equal Length (array_type ElemType1 LenTerm1) (array_type ElemType2 LenTerm2) :- | |
is_equal Length ElemType1 ElemType2, | |
is_equal Length LenTerm1 LenTerm2. | |
is_equal Length (array_intro ElemValues1) (array_intro ElemValues2) :- | |
map (fun value1 value2 => is_equal Length value1 value2) ElemValues1 ElemType2. | |
is_equal Length format_type format_type. | |
is_equal Length format_intro_void format_intro_void. | |
is_equal Length format_intro_unit format_intro_unit. | |
is_equal Length format_intro_u8 format_intro_u8. | |
is_equal Length format_intro_u16le format_intro_u16le. | |
is_equal Length format_intro_u16be format_intro_u16be. | |
is_equal Length format_intro_u32le format_intro_u32le. | |
is_equal Length format_intro_u32be format_intro_u32be. | |
is_equal Length format_intro_u64le format_intro_u64le. | |
is_equal Length format_intro_u64be format_intro_u64be. | |
is_equal Length format_intro_s8 format_intro_s8. | |
is_equal Length format_intro_s16le format_intro_s16le. | |
is_equal Length format_intro_s16be format_intro_s16be. | |
is_equal Length format_intro_s32le format_intro_s32le. | |
is_equal Length format_intro_s32be format_intro_s32be. | |
is_equal Length format_intro_s64le format_intro_s64le. | |
is_equal Length format_intro_s64be format_intro_s64be. | |
is_equal Length (format_intro_array ElemType1 LenTerm1) (format_intro_array ElemType2 LenTerm2) :- | |
is_equal Length ElemType1 ElemType2, | |
is_equal Length LenTerm1 LenTerm2. | |
is_equal Length (format_intro_pair FirstType1 Closure1) (format_intro_pair FirstType2 Closure2) :- | |
is_equal Length FirstType1 FirstType2, | |
apply_param Closure1 Length SecondType1, | |
apply_param Closure2 Length SecondType2, | |
plus Length 1 Length1, | |
is_equal Length1 SecondType1 SecondType2. | |
% Tests | |
tests : testsuite. | |
%testsuite tests. | |
% FIXME: there seems to be a bug with indenting tests here - see https://github.com/astampoulis/makam/issues/94 | |
>> function_elim (neutral Neutral) InputValue Value ? | |
>> Yes: | |
>> Value := neutral (function_elim Neutral InputValue). | |
>> function_elim (function_intro (closure [] (local 0))) InputValue Value ? | |
>> Yes: | |
>> Value := InputValue. | |
>> pair_elim_first (neutral Neutral) Value ? | |
>> Yes: | |
>> Value := neutral (pair_elim_first Neutral). | |
>> pair_elim_first (pair_intro FirstValue _) Value ? | |
>> Yes: | |
>> Value := FirstValue. | |
>> pair_elim_second (neutral Neutral) Value ? | |
>> Yes: | |
>> Value := neutral (pair_elim_second Neutral). | |
>> pair_elim_second (pair_intro _ SecondValue) Value ? | |
>> Yes: | |
>> Value := SecondValue. | |
>> format_elim (neutral Neutral) Term ? | |
>> Yes: | |
>> Term := neutral (format_elim Neutral). | |
>> format_elim format_intro_u8 Term ? | |
>> Yes: | |
>> Term := int_type. | |
>> normalize [format_intro_u8] (local 0) Term ? | |
>> Yes: | |
>> Term := format_intro_u8. | |
>> normalize (ann format_intro_u8 _) Term ? | |
>> Yes: | |
>> Term := format_intro_u8. | |
>> normalize void_type Term ? | |
>> Yes: | |
>> Term := void_type. | |
>> normalize unit_type Term ? | |
>> Yes: | |
>> Term := unit_type. | |
>> normalize unit_intro Term ? | |
>> Yes: | |
>> Term := unit_intro. | |
>> normalize (function_type universe (function_type (local 0) (local 1))) Term ? | |
>> Yes: | |
>> Term := function_type universe (function_type (local 0) (local 1)). | |
>> normalize (function_intro (function_intro (local 0))) Term ? | |
>> Yes: | |
>> Term := function_intro (function_intro (local 0)). | |
>> normalize (function_elim (function_intro (local 0)) (int_intro 1)) Term ? | |
>> Yes: | |
>> Term := int_intro 1. | |
>> normalize (pair_type int_type (array_type int_type (local 0))) Term ? | |
>> Yes: | |
>> Term := pair_type int_type (array_type int_type (local 0)). | |
>> normalize (pair_elim_first (pair_intro (int_intro 0) (array_intro []))) Term ? | |
>> Yes: | |
>> Term := int_intro 0. | |
>> normalize (pair_elim_first (ann (pair_intro (int_intro 0) (array_intro [])) _)) Term ? | |
>> Yes: | |
>> Term := int_intro 0. | |
>> normalize (pair_elim_second (pair_intro (int_intro 0) (array_intro []))) Term ? | |
>> Yes: | |
>> Term := array_intro []. | |
>> normalize (pair_elim_second (ann (pair_intro (int_intro 0) (array_intro [])) _)) Term ? | |
>> Yes: | |
>> Term := array_intro []. | |
>> normalize (format_elim format_intro_u8) Term ? | |
>> Yes: | |
>> Term := int_type. | |
>> normalize (format_elim (format_intro_array format_intro_u8 (int_intro 3))) Term ? | |
>> Yes: | |
>> Term := array_type int_type (int_intro 3). | |
>> normalize (format_intro_pair format_intro_u16be (format_intro_array format_intro_u8 (local 0))) Term ? | |
>> Yes: | |
>> Term := format_intro_pair format_intro_u16be (format_intro_array format_intro_u8 (local 0)). | |
%end. | |
%extend typing. | |
% Bidirectional Typing | |
% | |
% This section provides an operational semantics for the declarative | |
% typing rules in `core.typing.declarative`, and thus is intended to be | |
% a _refinement_ of these rules. This means that some terms that are | |
% well-formed with respect to the declarative typing rules may _not_ be | |
% well-formed in the bidirectional typing rules, requiring additional | |
% type annotations in order to be considered valid. | |
%extend bidirectional. | |
% FIXME: somehow import `semantics.(value, neutral, closure)` in | |
% order to make this module a bit less verbose. See this comment for | |
% more information: https://github.com/astampoulis/makam/issues/88#issuecomment-620318340 | |
% Bidirectional typing context. | |
% | |
% This stores the values and types of the bindings we have currently | |
% traversed over, allowing us to evaluate terms and synthesize the | |
% types of variables when we encounter them, and evaluate term. | |
context : type. | |
context : list (semantics.value * semantics.value) -> context. | |
%extend context. | |
values : context -> list semantics.value -> prop. | |
values (context Entries) Values :- | |
map tuple.fst Entries Values. | |
lookup_type : context -> int -> semantics.value -> prop. | |
lookup_type (context Entries) Index Type :- | |
list.nth Entries Index ( _, Type ). | |
next_local : context -> semantics.value -> prop. | |
next_local (context Entries) (semantics.neutral (semantics.local Level)) :- | |
length Entries Level. | |
add_local : context -> semantics.value -> semantics.value -> context -> prop. | |
add_local (context Entries) Value Type (context (( Value, Type ) :: Entries)). | |
add_param : context -> semantics.value -> context -> prop. | |
add_param Context Type Context' :- | |
next_local Context LocalTerm, | |
add_local Context LocalTerm Type Context'. | |
eval : context -> term -> semantics.value -> prop. | |
eval Context Term Value :- | |
values Context Values, | |
semantics.eval Values Term Value. | |
is_equal : context -> semantics.value -> semantics.value -> prop. | |
is_equal (context Entries) Value1 Value2 :- | |
length Entries Length, | |
semantics.is_equal Length Value1 Value2. | |
%end. | |
% Typing rules | |
% Check that a term is a type in the current context. | |
is_type : context -> term -> prop. | |
% Check that a term is an element of the given type in the current context. | |
check_type : context -> term -> semantics.value -> prop. | |
% Synthesize the type of a given term in the current context. | |
synth_type : context -> term -> semantics.value -> prop. | |
% A note on modes | |
% | |
% Makam does not support mode declarations (like in Mercury), but if it did | |
% we'd assign the following mode declarations to the above predicates: | |
% | |
% ``` | |
% is_type : in -> in -> semidet. | |
% check_type : in -> in -> int -> semidet. | |
% synth_type : in -> in -> out -> semidet. | |
% ``` | |
% Conversion | |
check_type Context Term Type :- | |
synth_type Context Term Type', | |
context.is_equal Context Type Type'. | |
% Variables | |
synth_type Context (local Index) Type :- | |
context.lookup_type Context Index Type. | |
% Annotated terms | |
% FIXME: is_type? | |
synth_type Context (ann Term Type) Type' :- | |
is_type Context Type, | |
context.eval Context Type Type', | |
check_type Context Term Type'. | |
% Universes | |
is_type Context universe. | |
% Unit | |
is_type Context unit_type. | |
synth_type Context unit_type semantics.universe. | |
synth_type Context unit_intro semantics.unit_type. | |
% Functions | |
is_type Context (function_type InputType OutputType) :- | |
is_type Context InputType, | |
context.eval Context InputType InputType', | |
context.add_param Context InputType' Context', | |
is_type Context' OutputType. | |
synth_type Context (function_type InputType OutputType) semantics.universe :- | |
is_type Context InputType, | |
context.eval Context InputType InputType', | |
context.add_param Context InputType' Context'. | |
is_type Context' OutputType. | |
check_type Context (function_intro OutputTerm) (semantics.function_type InputType Closure) :- | |
context.next_local Context LocalTerm, | |
semantics.apply Closure LocalTerm OutputType, | |
context.add_param Context InputType Context', | |
check_type Context' OutputTerm OutputType. | |
synth_type Context (function_elim Term InputTerm) OutputType :- | |
synth_type Context Term (semantics.function_type InputType Closure), | |
check_type Context InputTerm InputType, | |
context.eval Context InputTerm InputValue, | |
semantics.apply Closure InputValue OutputType. | |
% Pairs | |
is_type Context (pair_type FirstType SecondType) :- | |
check_type Context FirstType semantics.universe, | |
context.eval Context FirstType FirstType', | |
context.add_param Context FirstType' Context', | |
check_type Context' SecondType semantics.universe. | |
synth_type Context (pair_type FirstType SecondType) semantics.universe :- | |
check_type Context FirstType semantics.universe, | |
context.eval Context FirstType FirstType', | |
context.add_param Context FirstType' Context', | |
check_type Context' SecondType semantics.universe. | |
check_type Context (pair_intro FirstTerm SecondTerm) (semantics.pair_type FirstType Closure) :- | |
check_type Context FirstTerm FirstType, | |
context.eval Context FirstTerm FirstValue, | |
context.add_local Context FirstValue FirstType Context', | |
semantics.apply Closure FirstValue SecondType, | |
check_type Context' SecondTerm SecondType. | |
synth_type Context (pair_elim_first PairTerm) FirstType :- | |
synth_type Context PairTerm (semantics.pair_type FirstType _). | |
synth_type Context (pair_elim_second PairTerm) SecondType :- | |
synth_type Context PairTerm (semantics.pair_type _ Closure), | |
context.eval Context (pair_elim_first PairTerm) FirstValue, | |
semantics.apply Closure FirstValue SecondType. | |
% Booleans | |
is_type Context bool_type. | |
synth_type Context bool_type semantics.universe. | |
synth_type Context (bool_intro _) semantics.bool_type. | |
check_type Context (bool_elim BoolTerm TrueTerm FalseTerm) Type :- | |
check_type Context BoolTerm semantics.bool_type, | |
check_type Context TrueTerm Type, | |
check_type Context FalseTerm Type. | |
% Integers | |
is_type Context int_type. | |
synth_type Context int_type semantics.universe. | |
synth_type Context (int_intro _) semantics.int_type. | |
% Arrays | |
is_type Context (array_type ElemType LenTerm) :- | |
check_type Context ElemType semantics.universe, | |
check_type Context LenTerm semantics.int_type. | |
synth_type Context (array_type ElemType LenTerm) semantics.universe :- | |
check_type Context ElemType semantics.universe, | |
check_type Context LenTerm semantics.int_type. | |
check_type Context (array_intro ElemTerms) (semantics.array_type ElemType (semantics.int_intro Len)) :- | |
length ElemTerms Len, | |
map (fun elem_term => check_type Context elem_term ElemType) ElemTerms. | |
synth_type Context (array_elim ArrayTerm IndexTerm) ElemType :- | |
% FIXME: ensure `IndexTerm` is in array bounds, possibly with refinement types? | |
synth_type Context ArrayTerm (semantics.array_type ElemType _), | |
check_type Context IndexTerm semantics.int_type. | |
% Binary format descriptions | |
is_type Context format_type. | |
synth_type Context format_intro_unit semantics.format_type. | |
synth_type Context format_intro_u8 semantics.format_type. | |
synth_type Context format_intro_u16le semantics.format_type. | |
synth_type Context format_intro_u16be semantics.format_type. | |
synth_type Context format_intro_u32le semantics.format_type. | |
synth_type Context format_intro_u32be semantics.format_type. | |
synth_type Context format_intro_u64le semantics.format_type. | |
synth_type Context format_intro_u64be semantics.format_type. | |
synth_type Context format_intro_s8 semantics.format_type. | |
synth_type Context format_intro_s16le semantics.format_type. | |
synth_type Context format_intro_s16be semantics.format_type. | |
synth_type Context format_intro_s32le semantics.format_type. | |
synth_type Context format_intro_s32be semantics.format_type. | |
synth_type Context format_intro_s64le semantics.format_type. | |
synth_type Context format_intro_s64be semantics.format_type. | |
synth_type Context (format_intro_array ElemType LenTerm) semantics.format_type :- | |
check_type Context ElemType semantics.format_type, | |
check_type Context LenTerm semantics.int_type. | |
synth_type Context (format_intro_pair FirstType SecondType) semantics.format_type :- | |
check_type Context FirstType semantics.format_type, | |
context.eval Context (format_elim FirstType) FirstType', | |
context.add_param Context FirstType' Context', | |
check_type Context' SecondType semantics.format_type. | |
is_type Context (format_elim Type) :- | |
check_type Context Type semantics.format_type. | |
synth_type Context (format_elim Type) semantics.universe :- | |
check_type Context Type semantics.format_type. | |
% Convenience predicates | |
is_type : term -> prop. | |
is_type Term :- | |
is_type (context []) Term. | |
synth_type : term -> semantics.value -> prop. | |
synth_type Term Type :- | |
synth_type (context []) Term Type. | |
check_type : term -> semantics.value -> prop. | |
check_type Term Type :- | |
check_type (context []) Term Type. | |
% Tests | |
tests : testsuite. | |
%testsuite tests. | |
% FIXME: there seems to be a bug with indenting tests here - see https://github.com/astampoulis/makam/issues/94 | |
>> synth_type (context [ ( semantics.format_intro_u8, semantics.format_type ) ]) (local 0) Type ? | |
>> Yes: | |
>> Type := semantics.format_type. | |
>> synth_type (ann format_intro_u8 format_type) Type ? | |
>> Yes: | |
>> Type := semantics.format_type. | |
>> check_type (ann format_intro_u8 format_type) semantics.universe ? | |
>> Impossible. | |
>> synth_type (ann int_type universe) Type ? | |
>> Yes: | |
>> Type := semantics.universe. | |
>> check_type (ann int_type universe) semantics.format_type ? | |
>> Impossible. | |
>> synth_type (function_type universe (function_type (local 0) (local 1))) Type ? | |
>> Yes: | |
>> Type := semantics.universe. | |
>> check_type (function_intro (function_intro (local 0))) (semantics.function_type semantics.universe (semantics.closure [] (function_type (local 0) (local 1)))) ? | |
>> Yes. | |
>> synth_type (function_type universe (function_type (local 0) (local 1))) Type ? | |
>> Yes: | |
>> Type := semantics.universe. | |
>> synth_type (function_elim (ann (function_intro (function_intro (local 0))) (function_type universe (function_type (local 0) (local 1)))) int_type) Type ? | |
>> Yes: | |
>> Type := semantics.function_type semantics.int_type (semantics.closure [ semantics.int_type ] (local 1)). | |
>> check_type (pair_intro (int_intro 1) (array_intro [ int_intro 42 ])) (semantics.pair_type semantics.int_type (semantics.closure [] (array_type int_type (local 0)))) ? | |
>> Yes. | |
>> synth_type (pair_elim_first (ann (pair_intro (int_intro 0) (array_intro [])) (pair_type int_type (array_type int_type (local 0))))) Type ? | |
>> Yes: | |
>> Type := semantics.int_type. | |
>> synth_type (pair_elim_second (ann (pair_intro (int_intro 0) (array_intro [])) (pair_type int_type (array_type int_type (local 0))))) Type ? | |
>> Yes: | |
>> Type := semantics.array_type semantics.int_type (semantics.int_intro 0). | |
>> check_type (array_intro []) (semantics.array_type semantics.int_type (semantics.int_intro 0)) ? | |
>> Yes. | |
>> check_type (array_intro [ int_intro 1, int_intro 2, int_intro 3 ]) (semantics.array_type semantics.int_type (semantics.int_intro 3)) ? | |
>> Yes. | |
>> check_type (format_intro_pair format_intro_u16be (format_intro_array format_intro_u8 (local 0))) semantics.format_type ? | |
>> Yes. | |
>> synth_type (format_elim (format_intro_array format_intro_u8 (int_intro 3))) Type ? | |
>> Yes: | |
>> Type := semantics.universe. | |
%end. | |
%end. | |
%end. | |
% Binary decoding/encoding | |
%extend binary. | |
byte : type. | |
% Decoding byte sequences into terms, guided by a format description | |
decode : list core.semantics.value -> list byte -> core.semantics.value -> core.semantics.value -> prop. | |
decode Values Bytes core.semantics.format_intro_unit core.semantics.unit_intro. | |
% decode Values Bytes core.semantics.format_intro_u8 (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_u16le (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_u16be (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_u32le (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_u32be (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_u64le (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_u64be (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_s8 (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_s16le (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_s16be (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_s32le (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_s32be (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_s64le (core.semantics.intro_int TODO). | |
% decode Values Bytes core.semantics.format_intro_s64be (core.semantics.intro_int TODO). | |
% decode Values Bytes (core.semantics.format_intro_array ElemFormat Len) TODO. | |
% decode Values Bytes (core.semantics.format_intro_pair FirstFormat Closure) TODO. | |
%end. | |
% Lexical syntax | |
%extend lexical. | |
token : type. | |
% TODO | |
%end. | |
% Surface language | |
% | |
% This language is what we expect users of the language interact with directly. | |
% It includes convenience features such as implicit parameters and pattern | |
% matching to make binary data formats easier to describe. | |
%extend surface. | |
% Surface syntax | |
% Terms | |
term : type. | |
%extend term. | |
name : string -> term. | |
% TODO | |
%end. | |
%end. | |
% Stratified language | |
% | |
% As a stepping-stone to generating Rust code (or other languages like Haskell, | |
% SML, or, OCaml), we first compile the core language into a language where the | |
% distinction between expressions, types, and kinds are made explicit. | |
% | |
% This seems to be something like [System Fω], with lifted expressions and types. | |
% | |
% We need to be careful with lifted expressions and types - this might involve | |
% embedding 'runtime' relevant variables being used in types, which is where | |
% multistage programming might ultimately help us gain more control. | |
% | |
% [System Fω]: https://en.wikipedia.org/wiki/System_F#System_F.CF.89 | |
%extend stratified. | |
% Terms | |
kind : type. | |
typ : type. | |
expr : type. | |
% Variables | |
local : int -> typ. | |
local : int -> expr. | |
% Annotated terms | |
ann : typ -> kind -> typ. | |
ann : expr -> typ -> expr. | |
% 'Lifted' terms | |
lift : typ -> kind. | |
lift : expr -> typ. | |
% Universes | |
universe : kind. | |
% Void | |
void_type : typ. | |
% Unit | |
unit_type : typ. | |
unit_intro : expr. | |
% Functions | |
function_type : kind -> kind -> kind. | |
function_type : typ -> typ. | |
function_intro : typ -> typ. | |
function_intro : expr -> expr. % for terms or types | |
function_elim : typ -> typ -> expr. | |
function_elim : expr -> expr -> expr. | |
function_elim : expr -> typ -> expr. | |
% Pairs | |
pair_type : typ -> typ -> typ. | |
pair_intro : expr -> expr -> expr. | |
pair_elim_first : expr -> expr. | |
pair_elim_second : expr -> expr. | |
% Booleans | |
bool_type : typ. | |
bool_intro : bool -> expr. | |
bool_elim : expr -> expr -> expr -> expr. | |
% Integers | |
int_type : typ. | |
int_intro : int -> expr. | |
% Arrays | |
array_type : typ -> expr -> typ. | |
array_intro : list expr -> expr. | |
array_elim : expr -> expr -> expr. | |
% Binary format descriptions | |
format_type : kind. | |
format_intro_void : typ. | |
format_intro_unit : typ. | |
format_intro_u8 : typ. | |
format_intro_u16le : typ. % TODO: make this a computed format? | |
format_intro_u16be : typ. % TODO: make this a computed format? | |
format_intro_u32le : typ. % TODO: make this a computed format? | |
format_intro_u32be : typ. % TODO: make this a computed format? | |
format_intro_u64le : typ. % TODO: make this a computed format? | |
format_intro_u64be : typ. % TODO: make this a computed format? | |
format_intro_s8 : typ. % TODO: make this a computed format? | |
format_intro_s16le : typ. % TODO: make this a computed format? | |
format_intro_s16be : typ. % TODO: make this a computed format? | |
format_intro_s32le : typ. % TODO: make this a computed format? | |
format_intro_s32be : typ. % TODO: make this a computed format? | |
format_intro_s64le : typ. % TODO: make this a computed format? | |
format_intro_s64be : typ. % TODO: make this a computed format? | |
format_intro_array : typ -> expr -> typ. | |
format_intro_pair : typ -> typ -> typ. | |
format_elim : typ -> typ. | |
%extend semantics. | |
% Values | |
kind_value : type. | |
typ_value : type. | |
expr_value : type. | |
% Universes | |
universe : kind_value. | |
% Unit | |
unit_type : typ_value. | |
unit_intro : expr_value. | |
% Booleans | |
bool_type : typ_value. | |
bool_intro : bool -> expr_value. | |
% Integers | |
int_type : typ_value. | |
int_intro : int -> expr_value. | |
% Arrays | |
array_intro : list expr_value -> expr_value. | |
array_type : typ_value -> expr_value -> typ_value. | |
% Binary format descriptions | |
format_type : kind_value. | |
%end. | |
%end. | |
% Kind-erased language | |
% | |
% We take this route if our target language does not have a kind system, for | |
% example a language like Rust or OCaml. | |
%extend unkinded. | |
% TODO | |
%end. | |
% Uncurried language | |
% | |
% In this language functions are _uncurried_. | |
%extend uncurried. | |
% TODO | |
%end. | |
%extend rust. | |
typ : type. | |
bool : typ. | |
u8 : typ. | |
u16 : typ. | |
u32 : typ. | |
u64 : typ. | |
i8 : typ. | |
i16 : typ. | |
i32 : typ. | |
i64 : typ. | |
f32 : typ. | |
f64 : typ. | |
expr : type. | |
bool : bool -> expr. | |
int : int -> expr. | |
struct : string -> list (string * expr) -> expr. | |
ifte : expr -> expr -> expr -> expr. | |
item : type. | |
alias : string -> list string -> typ -> item. | |
struct : string -> list string -> list (string * typ) -> item. | |
enum : string -> list string -> list (string * typ) -> item. | |
function : string -> list string -> list (string * typ) -> typ -> expr -> item. | |
const : string -> typ -> expr -> item. | |
%end. | |
% Projections between intermediate languages. | |
% | |
% It would be fun to prototype compiling to Rust here. | |
% | |
% This course has a bunch of helpful information (in particular, Lecture 2: C | |
% representation): http://www.cse.chalmers.se/edu/year/2011/course/CompFun/ | |
% | |
% Some challenges involve: | |
% | |
% - stratifying source terms into runtime vs compile time | |
% - stratifying source terms into terms and types in the target language | |
% - uncurrying functions | |
% - translating functions on types into parameterised types | |
% - defunctionalization/monomorphization of more complicated type functions | |
% - erasure of dependencies in pair types and term level functions | |
%extend projections. | |
% Bidirectional elaboration of the surface syntax into core terms | |
% | |
% Here we describe how we elaborate the surface language into the core | |
% language. This involves doing a number of things, including: | |
% | |
% - desugaring | |
% - unification | |
% - pattern compilation | |
% - etc. | |
%extend surface_to_core. | |
context : type. | |
% Elaboration rules | |
% Check that a term is a type and elaborate it to a core term. | |
is_type : context -> surface.term -> core.term -> prop. | |
% Check that a term is an element of the given type and elaborate it to a core term. | |
check_type : context -> surface.term -> core.semantics.value -> core.term -> prop. | |
% Synthesize the type of a given term and elaborate it to a core term. | |
synth_type : context -> surface.term -> core.semantics.value -> core.term -> prop. | |
% A note on modes | |
% | |
% Makam does not support mode declarations (like in Mercury), but if it did | |
% we'd assign the following mode declarations to the above predicates: | |
% | |
% ``` | |
% is_type : in -> in -> out -> semidet. | |
% check_type : in -> in -> in -> out -> semidet. | |
% synth_type : in -> in -> out -> out -> semidet. | |
% ``` | |
% TODO | |
% Conversion | |
% Variables | |
% Annotated terms | |
% Universes | |
% Void | |
% Unit | |
% Functions | |
% Pairs | |
% Booleans | |
% Integers | |
% Arrays | |
% Binary format descriptions | |
%end. | |
% Delaboration back into the surface language | |
%extend core_to_surface. | |
context : type. | |
% TODO | |
%end. | |
% Bidirectional stratification of the core language. | |
%extend core_to_stratified. | |
% Stratified terms | |
stratified_term : type. | |
kind : stratified.kind -> stratified_term. | |
typ : stratified.typ -> stratified_term. | |
expr : stratified.expr -> stratified_term. | |
% Stratified values | |
stratified_value : type. | |
kind : stratified.semantics.kind_value -> stratified_value. | |
typ : stratified.semantics.typ_value -> stratified_value. | |
expr : stratified.semantics.expr_value -> stratified_value. | |
context : type. | |
% Check that a term is a type and lower it to a stratified term. | |
is_type : context -> core.term -> stratified_term -> prop. | |
% Check that a term is an element of the given type and lower it to a stratified term. | |
check_type : context -> core.term -> stratified_value -> stratified_term -> prop. | |
% Synthesize the type of a given term and lower it to a stratified term. | |
synth_type : context -> core.term -> stratified_value -> stratified_term -> prop. | |
% A note on modes | |
% | |
% Makam does not support mode declarations (like in Mercury), but if it did | |
% we'd assign the following mode declarations to the above predicates: | |
% | |
% ``` | |
% is_type : in -> in -> out -> semidet. | |
% check_type : in -> in -> in -> out -> semidet. | |
% synth_type : in -> in -> out -> out -> semidet. | |
% ``` | |
% Conversion | |
% Variables | |
% Annotated terms | |
% Universes | |
is_type Context core.universe (kind stratified.universe). | |
% Void | |
is_type Context core.void_type (typ stratified.void_type). | |
synth_type Context core.void_type (kind stratified.semantics.universe) (typ stratified.void_type). | |
% Unit | |
is_type Context core.unit_type (typ stratified.unit_type). | |
synth_type Context core.unit_type (kind stratified.semantics.universe) (typ stratified.unit_type). | |
synth_type Context core.unit_intro (typ stratified.semantics.unit_type) (expr stratified.unit_intro). | |
% Functions | |
% Pairs | |
% Booleans | |
is_type Context core.bool_type (typ stratified.bool_type). | |
synth_type Context core.bool_type (kind stratified.semantics.universe) (typ stratified.bool_type). | |
synth_type Context (core.bool_intro Bool) (typ stratified.semantics.bool_type) (expr (stratified.bool_intro Bool)). | |
% Integers | |
is_type Context core.int_type (typ stratified.int_type). | |
synth_type Context core.int_type (kind stratified.semantics.universe) (typ stratified.int_type). | |
synth_type Context (core.int_intro Int) (typ stratified.semantics.int_type) (expr (stratified.int_intro Int)). | |
% Arrays | |
is_type Context (core.array_type ElemType LenTerm) (typ (stratified.array_type ElemTerm' LenTerm')) :- | |
check_type Context ElemType (kind stratified.semantics.universe) (typ ElemTerm'), | |
check_type Context LenTerm (typ stratified.semantics.int_type) (expr LenTerm'). | |
check_type Context (core.array_type ElemType LenTerm) (kind stratified.semantics.universe) (typ (stratified.array_type ElemTerm' LenTerm')) :- | |
check_type Context ElemType (kind stratified.semantics.universe) (typ ElemTerm'), | |
check_type Context LenTerm (typ stratified.semantics.int_type) (expr LenTerm'). | |
check_type Context (core.array_intro ElemTerms) (typ (stratified.semantics.array_type ElemType (stratified.semantics.int_intro Len))) (expr (stratified.array_intro ElemTerms')) :- | |
length ElemTerms Len, | |
map (fun elem_term elem_term' => check_type Context elem_term (typ ElemType) (expr elem_term')) ElemTerms ElemTerms'. | |
synth_type Context (core.array_elim ArrayTerm IndexTerm) (typ ElemType) (expr (stratified.array_elim ArrayTerm' IndexTerm')) :- | |
% FIXME: ensure `IndexTerm` is in array bounds, possibly with refinement types? | |
synth_type Context ArrayTerm (typ (stratified.semantics.array_type ElemType _)) (expr ArrayTerm'), | |
check_type Context IndexTerm (typ stratified.semantics.int_type) (expr IndexTerm'). | |
% Binary format descriptions | |
is_type Context core.format_type (kind stratified.format_type). | |
synth_type Context core.format_intro_unit (kind stratified.semantics.format_type) (typ stratified.format_intro_unit). | |
synth_type Context core.format_intro_u8 (kind stratified.semantics.format_type) (typ stratified.format_intro_u8). | |
synth_type Context core.format_intro_u16le (kind stratified.semantics.format_type) (typ stratified.format_intro_u16le). | |
synth_type Context core.format_intro_u16be (kind stratified.semantics.format_type) (typ stratified.format_intro_u16be). | |
synth_type Context core.format_intro_u32le (kind stratified.semantics.format_type) (typ stratified.format_intro_u32le). | |
synth_type Context core.format_intro_u32be (kind stratified.semantics.format_type) (typ stratified.format_intro_u32be). | |
synth_type Context core.format_intro_u64le (kind stratified.semantics.format_type) (typ stratified.format_intro_u64le). | |
synth_type Context core.format_intro_u64be (kind stratified.semantics.format_type) (typ stratified.format_intro_u64be). | |
synth_type Context core.format_intro_s8 (kind stratified.semantics.format_type) (typ stratified.format_intro_s8). | |
synth_type Context core.format_intro_s16le (kind stratified.semantics.format_type) (typ stratified.format_intro_s16le). | |
synth_type Context core.format_intro_s16be (kind stratified.semantics.format_type) (typ stratified.format_intro_s16be). | |
synth_type Context core.format_intro_s32le (kind stratified.semantics.format_type) (typ stratified.format_intro_s32le). | |
synth_type Context core.format_intro_s32be (kind stratified.semantics.format_type) (typ stratified.format_intro_s32be). | |
synth_type Context core.format_intro_s64le (kind stratified.semantics.format_type) (typ stratified.format_intro_s64le). | |
synth_type Context core.format_intro_s64be (kind stratified.semantics.format_type) (typ stratified.format_intro_s64be). | |
% TODO: core.format_intro_array | |
% TODO: core.format_intro_pair | |
% TODO: core.format_elim | |
%end. | |
% Erasure of kinds | |
%extend stratified_to_unkinded. | |
% TODO | |
%end. | |
%extend unkinded_to_uncurried. | |
% TODO | |
%end. | |
%extend uncurried_to_rust. | |
% TODO | |
%end. | |
%end. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment