Compare commits

...

21 Commits
master ... dev

Author SHA1 Message Date
Georges Dupéron
7496fd2637 Try with existentials and GADT 2018-08-15 12:06:16 +02:00
Georges Dupéron
9c1c2a82d7 Drop current approach for now, will try with GADTs. 2018-08-15 12:06:04 +02:00
Georges Dupéron
ca47c0b5a5 Non-working attempt at solving the 'a * 'a issue without an extra constructor. Realized that the fast-forward pointers (stack) must jump to some arbitrary level of 'a * 'a nesting. 2018-08-15 11:54:52 +02:00
Georges Dupéron
1bac86494b Forgot to have 'a * 'a in child deques, but this requires having a different constructor in cases that were unified 2018-08-15 11:54:50 +02:00
Georges Dupéron
fa3ed3b3da Generate syntax-highlighted source with embedded quotes from the article 2018-08-12 16:34:50 +02:00
Georges Dupéron
cba1d3f867 WIP 2018-08-12 00:26:45 +02:00
Georges Dupéron
8bb879dc16 Left type-level programming aside for now 2018-08-11 12:27:32 +02:00
Georges Dupéron
5888eff68b Tried to manage free variables, but the result is way too complex (and doesn't work for now). 2018-08-11 12:08:45 +02:00
Georges Dupéron
0149738fd8 cleanup 2018-08-10 09:11:10 +02:00
Georges Dupéron
4071de59f7 circumvented unbound variable bug 2018-08-09 23:31:46 +02:00
Georges Dupéron
2ddc601a3d unbound variable bug 2018-08-09 09:43:53 +02:00
Georges Dupéron
a22715b749 tmp 2018-08-08 22:49:00 +02:00
Georges Dupéron
1bd3cf00cd Type-level function DSL with a nicer syntax 2018-08-08 09:18:20 +02:00
Georges Dupéron
ce9e429eeb First attempt at a type-level function DSL 2018-08-07 23:43:23 +02:00
Georges Dupéron
77c37cf5ac Stack and substack, separated from the pairs of buffers. 2018-08-07 22:22:22 +02:00
Georges Dupéron
6658bdcaa6 Remove older attempts 2018-08-06 00:49:30 +02:00
Georges Dupéron
3aa74ea869 WIP: buffer and deque colors 2018-08-06 00:45:50 +02:00
Georges Dupéron
9fdde72b51 WIP 2018-08-04 22:21:56 +02:00
Georges Dupéron
0ba3a253ac Use polymorphic variants; define color ordering and color of a deque 2018-08-02 01:13:56 +02:00
Georges Dupéron
2ff9f777cf Added types for buffers (0..5 elements), colors (green, yellow, red) and deques made out of those 2018-08-01 01:05:01 +02:00
Georges Dupéron
bac59a6495 Makefile rule for cropping the PDF to extract small parts of the article 2018-08-01 01:05:01 +02:00
6 changed files with 380 additions and 6 deletions

9
.gitignore vendored
View File

@ -2,3 +2,12 @@
/deques.cmi
/deques.cmo
/deques.mli
/jacm-final.pdf
/jacm-final-page*.pdf
/jacm-final-crop-*-*-*-*-page*.pdf
/jacm-final-crop-*-*-*-*-page*.png
/deques.html
/doc
/deques.d
/deques.color.html
/deques.html

View File

@ -1,9 +1,13 @@
sudo: false
language: c
addons:
apt:
packages:
- ocaml-interp
- ocaml
- ocaml-findlib
- caml2html
- libpodofo-utils
script:
- make print-tool-versions

View File

@ -1,12 +1,70 @@
.PHONY: all
all: deques deques.mli Makefile
.SECONDEXPANSION:
deques: deques.ml Makefile
.PHONY: all
all: deques deques.mli doc deques.html Makefile
deques: deques.ml deques.cmi Makefile
ocamlc $< -o $@
deques.mli: deques.ml Makefile
ocamlc -i $< > $@
deques.cmi: deques.mli Makefile
ocamlc $< -o $@
re=\( *\)(\*\* jacm-final.pdf p.\([0-9]\+\) \(([0-9]\+)\) \(§[.0-9]\+\) media \([0-9]\+\) \([0-9]\+\) \([0-9]\+\) \([0-9]\+\) \*)
deques.d: deques.ml Makefile
(printf 'deques.html: '; sed -ne 's~^$(re)$$~jacm-final-crop-\5-\6-\7-\8-page\2.png~p' $< | tr '\n' ' ') > $@
-include deques.d
deques.color.html: deques.ml Makefile
caml2html -charset utf-8 $< -t -o $@
# TODO: put this in a <style>…</style> tag
style=style="width:63em; margin: 1.5em 0em; display: block; padding: 0.5em 0em 0.5em 1em; border-left: thick solid \#ccc;"
deques.html: deques.color.html Makefile
# (echo '<!DOCTYPE html><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>$(<)</title><pre>'; \
# sed -e 's~[&]~\&amp;~' -e 's~<~\&gt;~' -e 's~>~\&lt;~' -e 's~"~\&quot;~' -e "s~'~\&#039;~" deques.ml \
# | sed -e 's~^$(re)$$~<img style="width:63em;" src="jacm-final-crop-\5-\6-\7-\8-page\2.png" alt="jacm-final.pdf page \2 \3 \4" />~'; \
# echo '</pre>') > $@
sed -e 's~$(re)~<img $(style) src="jacm-final-crop-\5-\6-\7-\8-page\2.png" alt="jacm-final.pdf page \2 \3 \4" />~g' $< > $@
.PHONY: print-tool-versions
print-tool-versions:
print-tool-versions: Makefile
ocamlc -version
jacm-final.pdf: Makefile
wget http://www.math.tau.ac.il/~haimk/adv-ds-2000/jacm-final.pdf -O$@ && touch $@
#sudo apt-get install libpodofo-utils to get podofobox
jacm-final-page%.pdf: jacm-final.pdf Makefile
pdftk P=$< cat P$* output $@
# jacm-final-crop-LEFT-TOP-WIDTH-HEIGHT-pagePAGE.pdf
# Original page width: 488, original page height: 721.
# podofobox expects LEFT BOTTOM WIDTH HEIGHT, multiplied by 100.
jacm-final-crop-%.pdf: $$(shell echo '%.pdf' | sed -e 's/^[-0-9]*-page/jacm-final-page/')
f () { \
podofobox $< $@ \
media $$(( ($$1) * 100 )) \
$$(( ( 720 - ($$2) - ($$4) ) * 100 )) \
$$(( ($$3) * 100 )) \
$$(( ($$4) * 100 )); \
}; \
f $$(echo '$*' | sed -e 's/page[0-9]*$$//' -e 's/-/ /g')
jacm-final-crop-%.png: jacm-final-crop-%.pdf Makefile
convert -density 300 $< $@
doc: deques.ml Makefile
git clean -dfx doc
mkdir doc
ocamlfind ocamldoc -html -all-params -colorize-code -charset utf-8 $< -d $@
touch doc
.PHONY: clean
clean: Makefile
rm -- jacm-final-page*.pdf jacm-final-crop-*-page*.pdf jacm-final-crop-*-page*.png deques.html
rm -r -- doc

133
deques-old.ml Normal file
View File

@ -0,0 +1,133 @@
(** An implementation of purely functional deques as described by Kaplan and
Tarjan. *)
(** jacm-final.pdf p.8 (584) §4.1 media 60 380 368 40 *)
module Buffers = struct
type buffer0 = [`Buffer0]
type 'a buffer1 = [`Buffer1 of 'a]
type 'a buffer2 = [`Buffer2 of 'a * 'a]
type 'a buffer3 = [`Buffer3 of 'a * 'a * 'a]
type 'a buffer4 = [`Buffer4 of 'a * 'a * 'a * 'a]
type 'a buffer5 = [`Buffer5 of 'a * 'a * 'a * 'a * 'a]
end
open Buffers
(** jacm-final.pdf p.9 (585) §4.1 media 60 158 368 24 *)
module Colors = struct
type 'a green = ['a buffer2 | 'a buffer3]
type 'a yellow = ['a buffer1 | 'a buffer4]
type 'a red = [ buffer0 | 'a buffer5]
(* In addition to the colors defined by Kaplan and Tarjan, we define the
shorhand "empty" for buffers of size zero (which are used later on). *)
type empty = buffer0
end
open Colors
(** jacm-final.pdf p.9 (585) §4.1 media 60 206 368 12 *)
module ColorOrder = struct
type nonrec 'a green = [`Green of 'a green]
type nonrec 'a yellow = [`Yellow of 'a yellow]
type nonrec 'a red = [`Red of 'a red]
type nonrec empty = [`Red of empty]
type 'a leGreen = [ | 'a green | 'a yellow | 'a red]
type 'a leYellow = [ | 'a yellow | 'a red]
type 'a leRed = [ | 'a red]
type 'a geGreen = [ | 'a green ]
type 'a geYellow = [ | 'a green | 'a yellow ]
type 'a geRed = [ | 'a green | 'a yellow | 'a red]
end
open ColorOrder
(** jacm-final.pdf p.9 (585) §4.1 media 60 146 368 24 *)
module BufferColors = struct
type 'a buffer = ['a green | 'a yellow | 'a red]
end
open BufferColors
(** jacm-final.pdf p.8 (584) §4.1 media 60 408 368 48 *)
module Deques = struct
(* We use polymorphic variants instead of the usual 't option so that it is
possible later to indicate in which contexts a deque must or must not
have a non-empty child. *)
type ('prefix, 'substack, 'suffix) deque = {
prefix: 'prefix;
substack: 'substack;
suffix: 'suffix}
type 'a child = 'a * 'a
end
open Deques
module DequesColorsStack = struct
(** jacm-final.pdf p.9 (585) §4.1 media 60 230 368 48 *)
(* TODO: this is ambiguous: when the colors are the same, or for the empty
cases, several constructors could be used for the same pair of
buffers. *)
type ('color, 'geColor, 'substack, 'b_last) min = 'result
constraint 'b_last = ([ `LeftMin of ('color, 'substack, 'geColor) deque
| `RightMin of ('geColor, 'substack, 'color) deque]
*[ `LeftMin of ('color, 'substack, 'geColor) deque
| `RightMin of ('geColor, 'substack, 'color) deque
| `LeftOnly of ('color, [`Nil], empty) deque
| `RightOnly of ( empty, [`Nil], 'color) deque]
*'result)
(* type ('color, 'geColor, 'substack) lastMin = [
* ('color, 'geColor, 'substack) min
* | `LeftOnly of ('color, [`Nil], empty) deque
* | `RightOnly of ( empty, [`Nil], 'color) deque] *)
type ('a, 'b_last) minTail = Deque of ('a yellow, 'a geYellow, ('a child, 'b_last1) minTail, 'b_last2) min
constraint 'b_last = (('t1 * 'f1 * 't1) * ('t1 * 'f1 * 't1))
*(('t1 * 'f1 * 'f1) * ('t1 * 'f1 * 'f1))
*('b_last1 * 'b_last2)
(* type 'a lastMinTail = Deque of ('a yellow, 'a geYellow, 'a child lastMinTail) lastMin *)
type ('a, 'color, 'geColor, 'b_last1, 'b_last2) min' = ('color, 'geColor, ('a child, 'b_last1) minTail, 'b_last2) min
(* type ('a, 'color, 'geColor) lastMin' = ('color, 'geColor, 'a child lastMinTail) lastMin *)
(** jacm-final.pdf p.9 (585) §4.1 media 60 290 368 60 *)
type ('a, 'color, 'geColor, 'b_last1, 'b_last2) substack = ('a, 'color, 'geColor, 'b_last1, 'b_last2) min'
type ('a, 'b_last1, 'b_last2) greenSubstack = ('a, 'a green, 'a geGreen, 'b_last1, 'b_last2) substack
(* A yellow substack can only appear as the topmost substack in a stack. *)
type ('a, 'b_last1, 'b_last2) yellowSubstack = ('a, 'a yellow, 'a geYellow, 'b_last1, 'b_last2) substack
type ('a, 'b_last1, 'b_last2) redSubstack = ('a, 'a red, 'a geRed, 'b_last1, 'b_last2) substack
(** jacm-final.pdf p.9 (585) §4.1 media 60 290 368 60 *)
(* In order to simplify the description of the types, we have separated the
outer stack from the substacks. *)
type 'a gStackLast = [ `GreenStackLast of ('a, 't1 * 'f1 * 't1, 't2 * 'f2 * 't2) greenSubstack * [`Null]]
type 'a yStackLast = [ `YellowStackLast of ('a, 't1 * 'f1 * 't1, 't2 * 'f2 * 't2) yellowSubstack * [`Null]]
type 'a rStackLast = [ `RedStackLast of ('a, 't1 * 'f1 * 't1, 't2 * 'f2 * 't2) redSubstack * [`Null]]
type ('a, 'b) _gStack = [ 'a gStackLast
| `GreenStack of ('a, 't1 * 'f1 * 'f1, 't2 * 'f2 * 'f2) greenSubstack * 'b]
type ('a, 'b) _yStack = [ 'a yStackLast
| `YellowStack of ('a, 't1 * 'f1 * 'f1, 't2 * 'f2 * 'f2) yellowSubstack * 'b]
type ('a, 'b) _rStack = [ 'a rStackLast
| `RedStack of ('a, 't1 * 'f1 * 'f1, 't2 * 'f2 * 'f2) redSubstack * 'b]
type ('a, 'b, 'c) _grStack = [('a, 'b) _gStack | ('a, 'c) _rStack]
type 'a greenStack = ('a, 'a greenOrRedStack) _gStack
and 'a yellowGStack = ('a, 'a greenStack) _yStack
and 'a yellowGRStack = ('a, 'a greenOrRedStack) _yStack
and 'a redStack = ('a, 'a redStack) _rStack
and 'a greenOrRedStack = ('a, 'a greenOrRedStack, 'a redStack) _grStack
(* Contrarily to substacks, the tail of a stack may start with different
colors: green is allways possible, but some stack elements may be
followed by a red stack element. We therefore need to introduce
polymorphic constructors in order to make a union of the two cases. In
practice, these cases are already disjoint types, but performing their
union is more readily done by defining a variant at this level. *)
type 'a semiregular = ['a greenStack | 'a yellowGRStack | 'a redStack]
(** jacm-final.pdf p.9 (585) §4.1 media 60 338 368 24 *)
type 'a regular = ['a greenStack | 'a yellowGStack | 'a redStack]
end
open DequesColorsStack
(** jacm-final.pdf p.8 (584) §4.1 media 60 480 368 36 *)
(* let rec child i d =
if i = 0 then d
else child (i - 1) d.child *)

View File

@ -0,0 +1,21 @@
module Buffers = struct
type ('a, _) buffer =
| Buffer0 : ('a, [`Red]) buffer
| Buffer1 : 'a -> ('a, [`Yellow]) buffer
| Buffer2 : 'a * 'a -> ('a, [`Green]) buffer
| Buffer3 : 'a * 'a * 'a -> ('a, [`Green]) buffer
| Buffer4 : 'a * 'a * 'a * 'a -> ('a, [`Yellow]) buffer
| Buffer5 : 'a * 'a * 'a * 'a * 'a -> ('a, [`Red]) buffer
end
open Buffers
type 'a somebuffer =
| Buffer : ('a, 'x) buffer -> 'a somebuffer
type z = int somebuffer
(* let f b = match b with
* Buffer0 -> 42
* | Buffer1 x -> 42
* | Buffer2 (x, y) -> 42
* | Buffer3 (x, y, z) -> 42
* | Buffer4 (x, y, z, t) -> 42
* | Buffer5 (x, y, z, t, u) -> 42 *)

View File

@ -0,0 +1,149 @@
(* Unification in the HM type system, along with OCaml's constraint keyword,
allows us to describe relations between types. The type-level functions
below are using this in a way that is reminiscent of Prolog's
predicates. We try to put the results on the left-hand side of the equals
sign, even though a use of the constraint keyword establishes an unordered
relation between two types. This explains why it is possible to write
constraint 'x = ('hd, 'tl) push to indicate that 'x is the result, and the
equivalent constraint ('hd, 'tl) push = 'x to indicate that 'hd and 'tl are
expected to be extracted from a known 'x. *)
module T = struct
(* TODO: bundle together the stack and an on-demand infinite stack of free variables *)
(* This should not be exported in the sig. *)
module Private = struct
(* stack of type-level operands *)
type ('tl, 'hd, 'fv) _stack = Stack of 'tl * 'hd * 'fv
type ('stack, 'freevars) _state = State of 'stack * 'freevars (* constraint 'tail = ('a,'b) state *)
type __start = ()
type 'freevars _start = (__start, 'freevars) _state
(* internal: quote a type and place it on the stack *)
type 't _typ = Typ of 't
type 't _polytyp = PolyTyp of 't
(* Push a new type-level value onto the stack *)
(* 'fv denotes the free variables in 'v, which will be bound to a dummy
type if the value 'v is dropped from the stack. *)
type ('state, 'v, 'fv) _push = (('stack, 'v, 'fv) _stack, 'freevars) _state
constraint ('stack, 'freevars) _state = 'state
(* fetch the value on top of the the stack and its free variables *)
type 'state _peekv = 'v
constraint (('stack, 'v, 'fv) _stack, 'freevars) _state = 'state
type 'state _peekfv = 'fv
constraint (('stack, 'v, 'fv) _stack, 'freevars) _state = 'state
(* drop the value on top of the the stack *)
(* type closed_freevar = [`FreeVar of (closed_freevar * closed_freevar)] *)
type closed_freevar1 = [`FreeVar of unit * unit]
(* 'x serves as a handled. If is is not unified with anything, it does not
cause any harm. If it is unified with ('u * 'u * 'v * 'v * 'w * 'w), it
causes three pairs of types to unify, thereby closing a local type
variable and propagating that close order down to the two children. *)
type 'dummy close_freevars = ('u * 'u * 'v * 'v * 'w * 'w) constraint ('u * 'v * 'w) = 'dummy
type ('a, 'x) _fv = [`FreeVar of 'a * 'x]
constraint ( 'a * closed_freevar1
* unit * unit (* ignored *)
* unit * unit (* ignored *)) = 'x
type ('a, 'b, 'x) _fvs = [`FreeVar of ('a * 'b) * 'x]
constraint ( unit * unit (* ignored *)
* 'a * [`FreeVar of 'one * 'dummy1 close_freevars]
* 'b * [`FreeVar of 'two * 'dummy2 close_freevars]) = 'x
(*TODO: possibly need to bind: 'one 'two 'dummy1 'dummy2 *)
type no_freevar = closed_freevar1
type 'state _pop = ('tail, 'freevars) _state
constraint (('tail, 'v, 'fv) _stack, 'freevars) _state = 'state
type 'state _discard = ('tail, 'freevars) _state
constraint (('tail, 'v, 'fv) _stack, 'freevars) _state = 'state
constraint 'fv = [`FreeVar of 'fv_ * 'dummy close_freevars]
end
open Private
(* Instantiate a new free variable. *)
type ('state, 'freevar) _freevar = ('stack, 'new_freevars) _state
constraint ('stack, 'freevars) _state = 'state
constraint 'new_freevars * 'freevar = 'freevars
(* Unwrap the single element on the stack. *)
type 'state return = 'returned
constraint 'state = ((__start, 'returned _typ, 'fvs) _stack, closed_freevar1) _state
constraint 'fvs = [`FreeVar of 'fvs_ * 'dummy close_freevars]
(* Quote a type and place it on the stack. *)
type ('state, 't) typ = (('stack, 't _typ, no_freevar) _stack, 'freevars) _state
constraint ('stack, 'freevars) _state = 'state
(* Quote a polymorphic type and place it on the stack. *)
(* 'x should be a free variable on the caller's site,
'xt should be 'x t where t is the polymorphic type to quote. *)
type ('state, 'x, 'xt) polytyp = (('stack, ('xt * 'x) _polytyp, ('x, 'fv) _fv) _stack, 'freevars) _state
constraint ('stack, 'freevars) _state = ('state, 'x * 'fv) _freevar
(* type-level booleans *)
type 'state tru = ('state2, ('a * 'b * 'a * 'b), (('a, 'fva) _fv, ('b, 'fvb) _fv, 'fvab) _fvs) _push
constraint 'state2 = ('state, 'a * 'b * 'fva * 'fvb * 'fvab) _freevar
type 'state fals = ('state2, ('a * 'b * 'b * 'a), (('a, 'fva) _fv, ('b, 'fvb) _fv, 'fvab) _fvs) _push
constraint 'state2 = ('state, 'a * 'b * 'fva * 'fvb * 'fvab) _freevar
type ('x, 'y) _cons = Cons of 'x * 'y
type 'state cons = ('state2 _pop _pop,
('state2 _pop _peekv, 'state2 _peekv) _cons,
('state2 _pop _peekfv, 'state2 _peekfv, 'fv) _fvs) _push
constraint 'state2 = ('state, 'fv) _freevar
type 'state uncons = (('state _pop, 'x, 'fvx) _push, 'y, 'fvy) _push
constraint ('x, 'y) _cons = 'state _peekv
constraint ('fvx, 'fvy, 'fvxy) _fvs = 'state _peekfv
constraint 'fvxy = ( unit * unit (* ignored *)
* 'a * [`FreeVar of 'one * 'dummy1 close_freevars]
* 'b * [`FreeVar of 'two * 'dummy2 close_freevars])
(* type-level conditional *)
type 'state ifelse = (('tail, 'tresult, 'fvr) _stack, 'freevars) _state
constraint 'state = (((('tail, 'tcondition, 'fvc) _stack, 'tthen, 'fvt) _stack, 'telse, 'fve) _stack, 'freevars) _state
constraint 'tcondition = ([`v_fv of 'tthen * 'fvt])
* ([`v_fv of 'telse * 'fve])
* ([`v_fv of 'tresult * 'fvr])
* ([`v_fv of 'tdiscard * 'fvd])
(* Since the discarded value may contain some free variables, we need to
bind them to some dummy value. *)
constraint 'fvd = [`FreeVar of 'fvd_ * 'dummy close_freevars]
constraint 'fvc = [`FreeVar of 'fvab * 'x]
constraint 'x = unit (* release the 'x of 'fvc, since the condition was used *)
(* type-level duplication of a boolean
We prefer not to allow duplication of a quoted type, as there would be no
way to avoid using the same polymorphic variables in both occurrences. *)
type 'state dup = 'state tru tru cons fals fals cons ifelse uncons
type 'state exch = (('state _pop _pop, 'state _peekv, 'state _peekfv) _push, 'state _pop _peekv, 'state _pop _peekfv) _push
type 'state pop = 'state _discard
(* apply a single-argument polymorphic type to an argument *)
type 'state polyapp = 'result
(* left-hand-side of product type is output, right-hand-side is input *)
constraint ('result * ('state _pop)) _polytyp = 'state _peekv
(* type 'x push = 'a * 'b constraint 'x = 'a * 'b *)
(* type ('tcondition, 'tthen, 'telse) ifelse = 'tresult constraint 'tcondition = 'tthen * 'telse * 'tresult *)
type 'state typ_string = ('state, string) typ
type 'state typ_int = ('state, int) typ
type 'state typ_unit = ('state, unit) typ
end
module TypeLevelFunctionsExamples = struct
open T
type 'state s = 'state typ_string typ_int ifelse return
type s1 = 't tru s (* push true on the stack, call s => string *)
type s2 = 't fals s (* push false on the stack, call s => int *)
type 'state f = 'state tru typ_string
type 'state t = 'state polyapp typ_int ifelse return
type 'state push_f = ('state, 'x, 'x f) polytyp
type t1 = 't push_f t (* => string *)
type 'state u = 'state dup typ_int typ_string ifelse typ_unit exch ifelse return
type u1 = 't tru u
type u2 = 't fals u
end