Skip to content

Commit

Permalink
WIP Add derived form for datatypes
Browse files Browse the repository at this point in the history
  • Loading branch information
polytypic committed Jul 12, 2020
1 parent 4621baf commit cb545cc
Show file tree
Hide file tree
Showing 11 changed files with 431 additions and 72 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

NAME = 1ml
MODULES = \
lib source prim syntax parser lexer \
fomega types iL env erase trace sub import elab \
lib source prim fomega types env syntax \
parser lexer iL erase trace sub import elab \
lambda compile \
main
NOMLI = syntax iL main import
Expand Down
4 changes: 4 additions & 0 deletions elab.ml
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ Trace.debug (lazy ("[RecT] t = " ^ string_of_norm_typ t));
ExT([], t), Pure, lift_warn exp.at t env (zs1 @ zs2 @ zs3),
IL.LetE(e, "_", materialize_typ t)
)

| EL.ImportE(path) ->
(match Import.resolve (Source.at_file path) path.it with
| None -> Source.error path.at ("\""^path.it^"\" does not resolve to a file")
Expand All @@ -593,6 +594,9 @@ Trace.debug (lazy ("[RecT] t = " ^ string_of_norm_typ t));
appE(FunE(x'@@t.at, t, VarE(x'@@t.at)@@t.at, Expl@@t.at)@@span[e.at; t.at], e)@@exp.at in
elab_exp env exp l

| EL.WithEnvE (toExp) ->
elab_exp env (toExp env) l

(*
rec (X : (b : type) => {type t; type u a}) fun (b : type) => {type t = (X int.u b, X bool.t); type u a = (a, X b.t)}
s1 = ?Xt:*->*, Xu:*->*->*. !b:*. [= b] -> {t : [= Xt b], u : !a:*. [= a] => [= Xu b a]}
Expand Down
25 changes: 5 additions & 20 deletions examples/fc.1ml
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,14 @@ local import "prelude"
;; clarity.

GADTs = {
Exp = {
local
type I (type t _) = {
type case _
Zero : case int
Succ : t int ~> case int
Pair 'a 'b : t a ~> t b ~> case (a, b)
}
type T (type t _) a = (m: I t) ~> m.case a
...rec {type t _} => {type t a = wrap T t a}
T = T t
I = I t
mk (fn: T _) = fn :# wrap T _ :@ t _
t
case (m: I) (e :# wrap T _ :@ t _) = e m
Zero : t _ = mk fun (m: I) => m.Zero
Succ x : t _ = mk fun (m: I) => m.Succ x
Pair l r : t _ = mk fun (m: I) => m.Pair l r
Exp = data case t _ :> {
Zero : case int
Succ : t int ~> case int
Pair 'a 'b : t a ~> t b ~> case (a, b)
}

eval = rec (eval 'a: Exp.t a ~> a) =>
Exp.case {
type case x = x
Exp.case (type fun x => x) {
Zero = 0
Succ x = eval x + 1
Pair l r = (eval l, eval r)
Expand Down
37 changes: 7 additions & 30 deletions examples/hoas.1ml
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,13 @@ local import "prelude"
;;
;; https://github.com/palladin/idris-snippets/blob/master/src/HOAS.idr

let
type I (type case _) (type t _) = {
Val 'x : x ~> case x
Bin 'x 'y 'z : (x ~> y ~> z) ~> t x ~> t y ~> case z
If 'x : t Bool.t ~> t x ~> t x ~> case x
App 'x 'y : t (x ~> y) ~> t x ~> case y
Lam 'x 'y : (t x ~> t y) ~> case (x ~> y)
Fix 'x 'y : t ((x ~> y) ~> x ~> y) ~> case (x ~> y)
}
type J (type t _) = {type case _, ...I case t}
type T (type t _) x = (c: J t) ~> c.case x
...{
...rec {type t _} => {type t x = wrap T t x}
case 'x (type case _) (cs: I case t) (e :# wrap T t x :@ t _) =
e {case, ...cs}
mk 'x (fn: T t x) = fn :# wrap T t x :@ t _
} :> {
type t _
case 'x: (type case _) -> I case t -> t x ~> case x
mk 'x: T t x -> t x
}
J = J t
in {
t, case
Val 'x (v: x) = mk fun (e: J) => e.Val v
Bin 'x 'y 'z (f: x ~> y ~> z) (l: t x) (r: t y) = mk fun (e: J) => e.Bin f l r
If 'x (b: t Bool.t) (c: t x) (a: t x) = mk fun (e: J) => e.If b c a
App 'x 'y (f: t (x ~> y)) (a: t x) = mk fun (e: J) => e.App f a
Lam 'x 'y (f: t x ~> t y) = mk fun (e: J) => e.Lam f
Fix 'x 'y (f: t ((x ~> y) ~> x ~> y)) = mk fun (e: J) => e.Fix f
data case t _ :> {
Val 'x : x ~> case x
Bin 'x 'y 'z : (x ~> y ~> z) ~> t x ~> t y ~> case z
If 'x : t Bool.t ~> t x ~> t x ~> case x
App 'x 'y : t (x ~> y) ~> t x ~> case y
Lam 'x 'y : (t x ~> t y) ~> case (x ~> y)
Fix 'x 'y : t ((x ~> y) ~> x ~> y) ~> case (x ~> y)
}

Fact = Fix <| Lam fun f => Lam fun x =>
Expand Down
116 changes: 116 additions & 0 deletions examples/tiv.1ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
local import "prelude"

;; As 1ML is powerful enough to encode GADTs we can define a value independent
;; type representation or a deep embedding of type constructors.

type iso a b = {to: a ~> b, from: b ~> a}

Rep = {
data case t _ :> {
bool: case bool
char: case char
int : case int
text: case text
unit: case unit

alt 'x 'y: t x ~> t y ~> case (alt x y)
(~~>) 'x 'y: t x ~> t y ~> case (x ~> y)
pair 'x 'y: t x ~> t y ~> case (x, y)

iso 'x 'y: iso x y ~> t y ~> case x

lazy 'x: ({} ~> t x) ~> case x
}

defaults (type t _) (default 'a: t a) = {
bool = default
char = default
int = default
unit = default
text = default

alt _ _ = default
_ ~~> _ = default
pair _ _ = default

iso _ _ = default

lazy _ = default
}

local i = {to = Opt.case {none = inl {}, some = inr}
from = Alt.case {inl {} = none, inr = some}}
opt a = iso i (alt unit a)

local i = {to = List.case {nil = inl {}, (::) x xs = inr (x, xs)}
from = Alt.case {inl {} = nil, inr (x, xs) = x::xs}}
list v = rec vs => lazy fun {} => iso i (alt unit (pair v vs))
}

;; Generic toText

ToText = {type t x = x ~> text}

toText = rec (toText 'x: Rep.t x ~> ToText.t x) => Rep.case ToText.t {
bool = Bool.toText
char c = "'" ++ Text.fromChar c ++ "'"
int = Int.toText
text t = "\"" ++ t ++ "\""
unit {} = "{}"

alt aT bT = Alt.case {
inl a = "(inl " ++ toText aT a ++ ")"
inr b = "(inr " ++ toText bT b ++ ")"
}

(_ ~~> _) _ = "<fun>"

pair aT bT (a, b) = "(" ++ toText aT a ++ ", " ++ toText bT b ++ ")"

iso ab bT = ab.to >> toText bT

lazy th = toText (th {})
}

println rep x = print (toText rep x ++ "\n")

do let ...Rep
println int 101
println (pair bool text) (true, "that")
println (opt bool) (some false)
println (iso {to i = i <> 0, from b = if b then 1 else 0} bool) 1
println (list int) (3 :: (1 :: (4 :: nil)))

;; Generic eq

Eq = {type t x = x ~> x ~> bool}

eq = rec (eq 'x: Rep.t x ~> Eq.t x) => Rep.case Eq.t {
bool = Bool.==
char = Char.==
int = Int.==
text = Text.==
unit _ _ = true

alt aT bT l r = l |> Alt.case {
inl l = r |> Alt.case {inl = eq aT l, inr _ = false}
inr l = r |> Alt.case {inl _ = false, inr = eq bT l}
}

(_ ~~> _) _ _ = false

pair aT bT (l1, l2) (r1, r2) = eq aT l1 r1 && eq bT l2 r2

iso ab bT l r = eq bT (ab.to l) (ab.to r)

lazy th l r = eq (th {}) l r
}

do let ...Rep
test t l r = print ("eq " ++ toText t l ++
" " ++ toText t r ++
" = " ++ toText bool (eq t l r) ++ "\n")
test int 101 42
test (pair int bool) (1, true) (1, true)
test (list int) (3 :: (1 :: nil)) (4 :: (1 :: nil))
test (list int) (4 :: (2 :: nil)) (4 :: (2 :: nil))
26 changes: 6 additions & 20 deletions examples/trie.1ml
Original file line number Diff line number Diff line change
@@ -1,28 +1,14 @@
local import "prelude"

FunctionalTrie = {
local
type I (type t _ _) = {
type case _ _
unit 'v : opt v ~> case {} v
alt 'v 'k1 'k2 : t k1 v ~> t k2 v ~> case (alt k1 k2) v
pair 'v 'k1 'k2 : t k1 (t k2 v) ~> case (k1, k2) v
}
type T (type t _ _) k v = (m: I t) ~> m.case k v
...rec {type t _ _} => {type t k v = wrap T t k v}
T = T t
I = I t
mk (fn: T _ _) = fn :# wrap T _ _ :@ t _ _

t
case (m: I) (e :# wrap T _ _ :@ t _ _) = e m
unit vO : t _ _ = mk fun (m: I) => m.unit vO
alt l r : t _ _ = mk fun (m: I) => m.alt l r
pair lr : t _ _ = mk fun (m: I) => m.pair lr
data case t _ _ :> {
unit 'v : opt v ~> case {} v
alt 'v 'k1 'k2 : t k1 v ~> t k2 v ~> case (alt k1 k2) v
pair 'v 'k1 'k2 : t k1 (t k2 v) ~> case (k1, k2) v
}

lookup = rec (lookup 'k 'v: t k v ~> k ~> opt v) =>
case {
type case k v = k ~> opt v
case (type fun k v => k ~> opt v) {
unit m {} = m
alt ta tb = Alt.case {inl = lookup ta, inr = lookup tb}
pair ta (a, b) = lookup ta a |> Opt.case {none, some tb = lookup tb b}
Expand Down
1 change: 1 addition & 0 deletions lexer.mll
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ rule token = parse
| "_" { HOLE }
| "&&" { LOGICAL_AND }
| "as" { AS }
| "data" { DATA }
| "do" { DO }
| "else" { ELSE }
| "type_error" { TYPE_ERROR }
Expand Down
5 changes: 5 additions & 0 deletions parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ let parse_error s = raise (Source.Error (Source.nowhere_region, s))
%token IMPORT
%token WRAP_OP UNWRAP_OP
%token ROLL_OP UNROLL_OP
%token DATA

%token EOF

Expand Down Expand Up @@ -373,6 +374,8 @@ annexp :
{ $2($1, $3)@@at() }
;
exp :
| DATA name name typparamlist annexp_op typ
{ dataE($2, $3, $4, $5, $6, at())@@at() }
| LET bind IN exp
{ letE($2, $4)@@at() }
| IF exp THEN exp ELSE exp
Expand Down Expand Up @@ -453,6 +456,8 @@ atbind :
{ InclB(letE($2, $4)@@at())@@at() }
| IMPORT TEXT
{ InclB(ImportE($2@@ati 2)@@at())@@at() }
| DATA name name typparamlist annexp_op typ
{ InclB(dataE($2, $3, $4, $5, $6, at())@@at())@@at() }
/*
| LPAR bind RPAR
{ $2 }
Expand Down
5 changes: 5 additions & 0 deletions prelude/index.1mls
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ Text: {
print: t ~> {}
}

Unit: {
type t = {}
}

Zero: {
type t
}
Expand All @@ -111,6 +115,7 @@ type int = Int.t
type list a = List.t a
type opt a = Opt.t a
type text = Text.t
type unit = Unit.t
type zero = Zero.t

(%): int -> int -> int
Expand Down
Loading

0 comments on commit cb545cc

Please sign in to comment.