├── Talk.pdf ├── ats-screenshot.png ├── possible_bug.dats ├── factorial_array.dats ├── factorial_array_extends.dats ├── .gitignore ├── array_allocate.dats ├── unsafe_swap.dats ├── for_loop.dats ├── README.org ├── list.dats ├── factorial_list.dats ├── factorial.dats ├── Makefile ├── stream.dats └── Talk.org /Talk.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deech/ATS-Strange-Loop-Talk/HEAD/Talk.pdf -------------------------------------------------------------------------------- /ats-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deech/ATS-Strange-Loop-Talk/HEAD/ats-screenshot.png -------------------------------------------------------------------------------- /possible_bug.dats: -------------------------------------------------------------------------------- 1 | #include "share/atspre_define.hats" 2 | #include "share/atspre_staload.hats" 3 | #include "prelude/DATS/pointer.dats" 4 | 5 | implement main0 () = 6 | let 7 | val (_, _ | p) = malloc_gc (sizeof) 8 | in 9 | () 10 | end 11 | -------------------------------------------------------------------------------- /factorial_array.dats: -------------------------------------------------------------------------------- 1 | #include "share/atspre_define.hats" 2 | #include "share/atspre_staload.hats" 3 | 4 | fun factorial_array 5 | {n:int|n > 1} 6 | (i : int n): 7 | [l:addr][x:int|x == n - 1] (array_v(double?,l,x), mfree_gc_v(l) | ptr l) = 8 | let 9 | var x = array_ptr_alloc(i2sz(i - 1)) 10 | in 11 | x 12 | end 13 | 14 | implement main0() = () -------------------------------------------------------------------------------- /factorial_array_extends.dats: -------------------------------------------------------------------------------- 1 | #include "share/atspre_define.hats" 2 | #include "share/atspre_staload.hats" 3 | 4 | fun factorial_array_extend 5 | {n:int|n > 1} 6 | (i : int n): 7 | [l:addr][x:int|x == n - 1] (array_v(double,l,x), mfree_gc_v(l) | ptr l) = 8 | let 9 | var x = array_ptr_alloc(i2sz(1)) 10 | fun loop 11 | {n:int|n > 1} 12 | (i : int n): 13 | in 14 | x 15 | end 16 | 17 | implement main0() = () -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /Talk.tex 2 | /array_allocate 3 | /array_allocate_dats.c 4 | /ecss0400.log 5 | /factorial 6 | /factorial_dats.c 7 | /list 8 | /list_dats.c 9 | /missfont.log 10 | /safe_swap 11 | /safe_swap.dats 12 | /safe_swap_dats.c 13 | /stream 14 | /stream_dats.c 15 | /swap_from_ats 16 | /swap_from_ats.dats 17 | /swap_from_ats_dats.c 18 | /unsafe_swap 19 | /unsafe_swap_dats.c 20 | /possible_bug 21 | /possible_bug_dats.c 22 | /*.c 23 | /factorial_array 24 | /factorial_list 25 | /for_loop 26 | -------------------------------------------------------------------------------- /array_allocate.dats: -------------------------------------------------------------------------------- 1 | #include "share/atspre_staload.hats" 2 | extern praxi array_v_uncons:{a:vt0p}{l:addr}{n:int | n > 0} array_v (INV(a), l, n) - (a @ l, array_v (a, l+sizeof(a), n-1)) 3 | 4 | implement main0 () = 5 | let 6 | var N = 10000 7 | stadef T = List1_vt(int) 8 | val sa : T = $list_vt{int}(1,2,3) 9 | val (pfat, pfgc | p) = array_ptr_alloc(g1i2u(N)) 10 | val _ = array_initize_elt(!p, g1i2u(N), 0) 11 | in 12 | begin 13 | free sa; 14 | array_ptr_free(pfat, pfgc | p); 15 | end 16 | end -------------------------------------------------------------------------------- /unsafe_swap.dats: -------------------------------------------------------------------------------- 1 | #include "share/atspre_define.hats" 2 | #include "share/atspre_staload.hats" 3 | staload UN = "prelude/SATS/unsafe.sats" 4 | 5 | 6 | %{ 7 | #include 8 | #include 9 | 10 | void swap (void* p1, void* p2, size_t size) { 11 | char* buffer = (char*)malloc(sizeof(char)*size); 12 | memcpy(buffer, p1, size); 13 | memcpy(p1, p2, size); 14 | memcpy(p2, buffer, size); 15 | free(buffer); 16 | } 17 | %} 18 | 19 | extern fun swap (i:ptr, j:ptr, s: size_t) : void = "mac#swap" 20 | extern fun malloc(s:size_t):ptr = "mac#malloc" 21 | 22 | implement main0 () = 23 | let 24 | val i = malloc(sizeof) 25 | val j = malloc(sizeof) 26 | val _ = swap(i,j,sizeof) 27 | in 28 | () 29 | end 30 | -------------------------------------------------------------------------------- /for_loop.dats: -------------------------------------------------------------------------------- 1 | #include "share/atspre_staload.hats" 2 | 3 | extern fun 4 | {env:t@ype} 5 | worker 6 | ( 7 | count: int, 8 | env: &env >> _ 9 | ): void 10 | 11 | fun {env:t@ype} 12 | for_loop 13 | ( 14 | count: int, 15 | limit: int, 16 | env: &env >> _ 17 | ) : void = 18 | if count < limit 19 | then 20 | begin 21 | worker(count, env); 22 | for_loop(count+1, limit, env) 23 | end 24 | else () 25 | 26 | fun 27 | tally 28 | ( 29 | n: int 30 | ) : int = 31 | let 32 | var res: int = 0 33 | implement worker (i, res) = res := res + i 34 | in 35 | for_loop (0, n, res); res 36 | end 37 | 38 | implement main0() = 39 | let 40 | val N = 100 41 | in 42 | println! ("tally(", N, ") = ", tally(N)) 43 | end 44 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * A (Not So Gentle) Introduction To Systems Programming In ATS 2 | Included in this repo are these are the code examples to support my [[https://www.youtube.com/watch?v=zt0OQb1DBko][ATS talk]] at [[https://www.thestrangeloop.com/][Strange Loop 2017]] and the slides: ~Talk.org~ and ~Talk.pdf~. 3 | 4 | In order to build the examples you'll need to install ATS using the instructions on the [[http://www.ats-lang.org/Downloads.html][ATS' main website]]. Once you've done that simply running ~make~ should compile all the executables. 5 | 6 | I admit the example code is a mess and there's a few files that literally don't do anything except compile. It's unlikely I'll clean it up unless you open an issue for some particular example. 7 | 8 | Also feel free to use issues to ask questions about how something works. 9 | 10 | Enjoy! 11 | -------------------------------------------------------------------------------- /list.dats: -------------------------------------------------------------------------------- 1 | 2 | extern fun {a:t0p} list_append2_vt {i,j:int} (xs: NSH(list(INV(a), i)), ys: list_vt(a, j)) : list_vt(a, i+j) 3 | 4 | implement 5 | {a}(*tmp*) 6 | list_append2_vt 7 | {m,n} (xs, ys) = let 8 | // 9 | prval() = lemma_list_param (xs) 10 | prval() = lemma_list_vt_param (ys) 11 | // 12 | fun 13 | loop 14 | {m:nat} .. 15 | ( 16 | xs: list(a, m) 17 | , ys: list_vt(a, n) 18 | , res: &ptr? >> list_vt(a, m+n) 19 | ) : void = 20 | case+ xs of 21 | | list_nil 22 | () => (res := ys) 23 | // list_nil 24 | | list_cons 25 | (x, xs) => let 26 | val () = res := 27 | list_vt_cons{a}{0}(x, _(*?*)) 28 | val+list_vt_cons 29 | (_, res1) = res // res1 = res.1 30 | val () = loop(xs, ys, res1) 31 | prval ((*folded*)) = fold@ (res) 32 | in 33 | // nothing 34 | end // end of [list_cons] 35 | // end of [loop] 36 | var res: ptr // uninitialized 37 | val () = loop(xs, ys, res) 38 | // 39 | in 40 | res 41 | end // end of [list_append2_vt] 42 | 43 | implement main0 () = {} -------------------------------------------------------------------------------- /factorial_list.dats: -------------------------------------------------------------------------------- 1 | #include "share/atspre_define.hats" 2 | #include "share/atspre_staload.hats" 3 | 4 | fun factorial 5 | {n:int | n >= 2} 6 | (i:int n): list_vt(double, n-1) = 7 | let 8 | var res : ptr 9 | fun loop 10 | {n1:int | n1 >= 0 && n1 <= n-2} 11 | .. 12 | ( 13 | seed: double, 14 | next: int n1, 15 | res: &ptr? >> list_vt(double, n1+1) 16 | ) : void = 17 | case- next of 18 | | 0 => res := list_vt_cons(seed, list_vt_nil()) 19 | | next when next > 0 => 20 | let 21 | val () = res := list_vt_cons{..}{n1+1}(seed, _) 22 | val+list_vt_cons(_,hole) = res 23 | val curr = seed * g0i2f(next) 24 | val () = loop(curr, next-1, hole) 25 | prval () = fold@(res) 26 | in 27 | end 28 | val initial = g0i2f(i) * g0i2f(i-1) 29 | val () = loop(initial,i-2,res) 30 | in 31 | res 32 | end 33 | 34 | 35 | implement main0() = 36 | let 37 | val x = factorial(10) 38 | in 39 | println! "hello world"; 40 | println! x; 41 | list_vt_freex; 42 | end 43 | -------------------------------------------------------------------------------- /factorial.dats: -------------------------------------------------------------------------------- 1 | #include "share/atspre_staload.hats" 2 | 3 | fun factorial { n : int | n >= 1 } (i : int n) : double = 4 | let 5 | fun loop { n : int | n >= 1 } .. (acc : double, i : int (n)) : double = 6 | case- i of 7 | | 1 => acc 8 | | i when i > 1 => loop(acc * i, i - 1) 9 | in 10 | loop(1.0, i) 11 | end 12 | 13 | sortdef even = { i:int | i mod 2 == 0 } 14 | sortdef agz = {l:addr | l > null} 15 | viewtypedef ptrResource (a:t@ype) = [l:agz] (a @ l | ptr l) 16 | 17 | fn {a:t@ype} 18 | swap1 {l1,l2:addr} 19 | (pf1: !a@l1, pf2: !a@l2 | p1: ptr (l1), p2: ptr (l2)) : void = 20 | let 21 | val tmp = !p1 22 | in !p1 := !p2; !p2 := tmp 23 | end 24 | 25 | fn fact{n:nat} 26 | (n: int (n)): double = let 27 | fun loop{n:nat}{l:addr} .. 28 | (pf: !double @ l | n: int n, res: ptr l): void = 29 | case n of 30 | | 0 => () 31 | | n => 32 | ( 33 | if (n > 0) then 34 | begin 35 | !res := n * !res; 36 | loop (pf | n-1, res); 37 | end 38 | ) 39 | var res with pfres = 1.0 40 | in 41 | loop (pfres | n, addr@res); 42 | res 43 | end 44 | 45 | implement main0 () = 46 | let 47 | (* val odd : [n : even] int(n) = 2 *) 48 | val x = list_vt_cons(1, list_vt_cons(2, list_vt_nil())) : list_vt(int,2) 49 | val a = factorial(100) 50 | val c = fact(100000) 51 | (* val x = arrayptr $arrpsz(0,1,2,3,4) *) 52 | (* val b = fact(10) *) 53 | (* val p : int = aptr_getfree_elt(b) *) 54 | in 55 | println! "hello world"; 56 | println! (sizeof); 57 | println! a; 58 | println! c; 59 | free x; 60 | (* free x; *) 61 | end 62 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PATSHOMEQ="$(PATSHOME)" 2 | 3 | PATSCC=$(PATSHOMEQ)/bin/patscc 4 | PATSOPT=$(PATSHOMEQ)/bin/patsopt 5 | PATSCCFLAGS = -g 6 | 7 | ###### 8 | 9 | all: possible_bug unsafe_swap swap_from_ats safe_swap stream list array_allocate factorial factorial_array factorial_list for_loop 10 | for_loop: for_loop.dats; \ 11 | $(PATSCC) $(PATSCCFLAGS) -D_GNU_SOURCE -DATS_MEMALLOC_LIBC -g -I${PATSHOME}/contrib -o $@ $< -latslib 12 | factorial_list: factorial_list.dats; \ 13 | $(PATSCC) $(PATSCCFLAGS) -D_GNU_SOURCE -DATS_MEMALLOC_LIBC -g -I${PATSHOME}/contrib -o $@ $< -latslib 14 | factorial_array: factorial_array.dats; \ 15 | $(PATSCC) $(PATSCCFLAGS) -D_GNU_SOURCE -DATS_MEMALLOC_LIBC -g -I${PATSHOME}/contrib -o $@ $< -latslib 16 | possible_bug: possible_bug.dats; \ 17 | $(PATSCC) $(PATSCCFLAGS) -D_GNU_SOURCE -DATS_MEMALLOC_LIBC -g -I${PATSHOME}/contrib -o $@ $< -latslib 18 | unsafe_swap: unsafe_swap.dats; \ 19 | $(PATSCC) $(PATSCCFLAGS) -D_GNU_SOURCE -DATS_MEMALLOC_LIBC -g -I${PATSHOME}/contrib -o $@ $< -latslib 20 | swap_from_ats: swap_from_ats.dats; \ 21 | $(PATSCC) $(PATSCCFLAGS) -D_GNU_SOURCE -DATS_MEMALLOC_LIBC -g -I${PATSHOME}/contrib -o $@ $< -latslib 22 | safe_swap: safe_swap.dats; \ 23 | $(PATSCC) $(PATSCCFLAGS) -D_GNU_SOURCE -DATS_MEMALLOC_LIBC -g -I${PATSHOME}/contrib -o $@ $< -latslib 24 | array_allocate: array_allocate.dats; \ 25 | $(PATSCC) $(PATSCCFLAGS) -D_GNU_SOURCE -DATS_MEMALLOC_LIBC -g -I${PATSHOME}/contrib -o $@ $< -latslib 26 | factorial: factorial.dats; \ 27 | $(PATSCC) $(PATSCCFLAGS) -D_GNU_SOURCE -DATS_MEMALLOC_LIBC -g -I${PATSHOME}/contrib -o $@ $< -latslib 28 | stream: stream.dats; \ 29 | $(PATSCC) $(PATSCCFLAGS) -D_GNU_SOURCE -DATS_MEMALLOC_LIBC -g -I${PATSHOME}/contrib -o $@ $< -latslib 30 | list: list.dats; \ 31 | $(PATSCC) $(PATSCCFLAGS) -D_GNU_SOURCE -DATS_MEMALLOC_LIBC -g -I${PATSHOME}/contrib -o $@ $< -latslib 32 | cleanall:: ; $(RMF) array_allocate factorial stream 33 | 34 | RMF=rm -f 35 | 36 | ###### 37 | 38 | clean:: ; $(RMF) *~ 39 | clean:: ; $(RMF) *.o 40 | clean:: ; $(RMF) *.c 41 | clean:: ; $(RMF) array_allocate 42 | clean:: ; $(RMF) factorial 43 | clean:: ; $(RMF) stream 44 | clean:: ; $(RMF) list 45 | clean:: ; $(RMF) safe_swap 46 | clean:: ; $(RMF) swap_from_ats 47 | clean:: ; $(RMF) swap 48 | clean:: ; $(RMF) unsafe_swap 49 | clean:: ; $(RMF) possible_bug 50 | clean:: ; $(RMF) factorial_array 51 | clean:: ; $(RMF) factorial_array_extend 52 | clean:: ; $(RMF) factorial_array 53 | clean:: ; $(RMF) factorial_list 54 | clean:: ; $(RMF) for_loop 55 | 56 | cleanall:: clean 57 | -------------------------------------------------------------------------------- /stream.dats: -------------------------------------------------------------------------------- 1 | (* 2 | ** For ATS2TUTORIAL 3 | *) 4 | 5 | (* ****** ****** *) 6 | #include "share/atspre_staload.hats" 7 | #include "prelude/DATS/pointer.dats" 8 | #include "prelude/DATS/list.dats" 9 | #include "prelude/DATS/list.dats" 10 | (* ****** ****** *) 11 | 12 | fun from(n: int): stream_vt(int) = $ldelay(stream_vt_cons(n, from(n+1))) 13 | 14 | fun sieve (ns: stream_vt(int)) : stream_vt(int) = 15 | $ldelay 16 | ( 17 | let val ns_con = !ns 18 | val- @stream_vt_cons(n0, ns1) = ns_con 19 | val n0_val = n0 20 | val ns1_val = ns1 21 | val ((*void*)) = (ns1 := sieve(stream_vt_filter_cloptr(ns1_val, lam x => x mod n0_val > 0))) 22 | prval () = fold@(ns_con) 23 | in ns_con 24 | end 25 | , 26 | ~ns // [ns] is freed 27 | ) 28 | 29 | val thePrimes = sieve(from(2)) 30 | 31 | (* ****** ****** *) 32 | val p10000 = (stream_vt_drop_exn(thePrimes, 10000)).head() 33 | (* ****** ****** *) 34 | 35 | val () = println! ("p10000 = ", p10000) 36 | 37 | extern fun{env:t@ype} for_loop3blah(count: int, env: &env >> _): void 38 | 39 | fun{env:t@ype} for_loop3 (count: int, limit: int, env: &env >> _) : void = 40 | ( 41 | if count < limit 42 | then ( 43 | for_loop3blah(count, env); for_loop3(count+1, limit, env) 44 | ) 45 | else () 46 | ) 47 | 48 | fun tally4 (n: int) : int = 49 | let var res: int = 0 50 | implement for_loop3blah (i, res) = res := res + i 51 | in 52 | for_loop3 (0, n, res); res 53 | end 54 | 55 | val N = 100 56 | val () = println! ("tally4(", N, ") = ", tally4(N)) 57 | 58 | datatype list0 (a:t@ype) = 59 | | list0_nil (a) of () 60 | | list0_cons (a) of (a, list0 a) 61 | 62 | datatype option0 (a:t@ype) = 63 | | option0_none (a) of () 64 | | option0_some (a) of a 65 | 66 | fun{a:t@ype} list0_last (xs: list0 a) : option0 (a) = 67 | let fun loop (x: a, xs: list0 a): a = 68 | ( 69 | case+ xs of 70 | | list0_nil () => x 71 | | list0_cons (x, xs) => loop (x, xs) 72 | ) 73 | in 74 | case+ xs of 75 | | list0_nil () => option0_none((*void*)) 76 | | list0_cons (x, xs) => option0_some(loop (x, xs)) 77 | end 78 | 79 | extern fun {a:t0p} my_list_append2_vt {i,j:nat} (xs: list(a, i), ys: list_vt(a, j)) : list_vt(a, i+j) 80 | 81 | implement 82 | {a} 83 | my_list_append2_vt 84 | {m,n} (xs, ys) = let 85 | prval _ = lemma_list_vt_param (ys) 86 | fun loop {m:nat} .. ( 87 | xs: list(a, m) 88 | , ys: list_vt(a, n) 89 | , res: &ptr? >> list_vt(a, m+n) 90 | ) : void = 91 | case+ xs of 92 | | list_nil () => (res := ys) 93 | | list_cons (x, xs) => 94 | let 95 | val () = res := 96 | list_vt_cons{a}{0}(x, _(*?*)) 97 | val+list_vt_cons 98 | (_, res1) = res // res1 = res.1 99 | val () = loop(xs, ys, res1) 100 | prval _ = fold@ (res) 101 | in 102 | end 103 | var res: ptr 104 | val () = loop(xs, ys, res) 105 | in 106 | res 107 | end 108 | 109 | fun{a:t0ype} list_append (l1 : list0 a, l2 : list0 a) : list0 a = 110 | case+ (l1, l2) of 111 | | (list0_cons (x,xs) , l2) => list0_cons(x, list_append(xs, l2)) 112 | | (list0_nil , l2) => l2 113 | 114 | val l1 = list0_cons(3, list0_cons(4, list0_nil)) 115 | 116 | val l2 = list0_cons(1, list0_cons(2, list0_nil)) 117 | 118 | fun {a : t0ype} print_option(o : option0 (a)) : void = 119 | case+ o of 120 | | option0_some (a) => fprint! (a) 121 | | option0_none => fprint! ("none") 122 | 123 | vtypedef cloptr(a:t@ype, b:t@ype, l:addr) = 124 | [env:t@ype] (((&env, a) -> b, env) @ l | ptr l) 125 | 126 | fun 127 | {a:t@ype}{b:t@ype}{l:addr} 128 | cloptr_app (pclo: !cloptr (a, b, l), x: a) : b = 129 | let 130 | val p = pclo.1 131 | val res = !p.0 (!p.1, x) 132 | in 133 | res 134 | end 135 | 136 | 137 | fun bar(): List0 double (* (g0float_t0ype (double_kind)) *) = 138 | let 139 | val l1 = list_nil () 140 | val l2 = list_cons (1.0,l1) 141 | val l3 = list_cons (5.0,l2) 142 | in l3 end 143 | 144 | (* ****** ****** *) 145 | implement main0 () = {} 146 | (* ****** ****** *) 147 | -------------------------------------------------------------------------------- /Talk.org: -------------------------------------------------------------------------------- 1 | #+TITLE: A (Not So Gentle) Introduction To Systems Programming In ATS 2 | #+AUTHOR: Aditya Siram 3 | #+OPTIONS: H:1 toc:f 4 | #+OPTIONS: ^:nil 5 | #+LATEX_CLASS: beamer 6 | #+LATEX_listingsCLASS_OPTIONS: [presentation] 7 | #+BEAMER_THEME: Madrid 8 | #+EPRESENT_FRAME_LEVEL: 1 9 | * ATS 10 | - Is an ML (not standard) 11 | - ADTS, pattern-matching etc. 12 | - FP fully supported (TCO) 13 | - Exactly the same performance/memory predictability 14 | - Decompiles to C 15 | - No optimizations (except TCO) 16 | - GCC does the rest 17 | - Exactly the same control of C 18 | - Pointer arithmetic 19 | - malloc/free 20 | - stack allocation 21 | - Completely verified at compile time 22 | - type system has zero overhead 23 | * ATS 24 | - Top of The Benchmarks Game 25 | - Now taken down in 2015 26 | - No idea why! 27 | * ATS 28 | - Linear logic to manage resources 29 | - Prove it exists, consume proof, repeat 30 | - file handles, sockets, anything 31 | * ATS 32 | #+BEGIN_EXAMPLE 33 | fun bar 34 | ... 35 | = 36 | let 37 | val (awesome_proof | fd) = open_file("some_file.txt") 38 | ^^^^^^^^^^^^^ 39 | val contents = read_file (awesome_proof | fd) 40 | ^^^^^^^^^^^^^ 41 | ... 42 | in 43 | ... 44 | end 45 | #+END_EXAMPLE 46 | * ATS 47 | - Especially memory 48 | - Prove pointer is initialized, dereference, repeat 49 | - Type checked pointer arithmetic 50 | * ATS 51 | - Refinement types 52 | #+BEGIN_EXAMPLE 53 | fun foo 54 | { } 55 | (i : int ) ... 56 | #+END_EXAMPLE 57 | * ATS 58 | - Refinement types 59 | #+BEGIN_EXAMPLE 60 | fun foo 61 | { } 62 | (i : int n) ... 63 | #+END_EXAMPLE 64 | * ATS 65 | - Refinement types 66 | #+BEGIN_EXAMPLE 67 | fun foo 68 | {n:int } 69 | (i : int n) ... 70 | #+END_EXAMPLE 71 | * ATS 72 | - Refinement types 73 | #+BEGIN_EXAMPLE 74 | fun foo 75 | {n:int | n > 0 } 76 | (i : int n) ... 77 | #+END_EXAMPLE 78 | * ATS 79 | - Refinement types 80 | #+BEGIN_EXAMPLE 81 | fun foo 82 | {n:int | n > 0 && n < 10} 83 | (i : int n) ... 84 | #+END_EXAMPLE 85 | * ATS 86 | - Very Difficult 87 | - Intersects 88 | - refinement types 89 | - linear logic 90 | - proofs 91 | - C 92 | - Research! 93 | - Funded by the NSF 94 | - No easy story, or newcomer "onboarding" 95 | - Tiny community 96 | - Sparse docs 97 | * Swap 98 | - Easiest way to get started is C interop 99 | - A generic swap in C 100 | - Yes, I realize 'size_t' is bad! 101 | #+BEGIN_SRC 102 | void swap (void* p1, void* p2, size_t size) { 103 | char* buffer = (char*)malloc(sizeof(char)*size); 104 | memcpy(buffer, p1, size); 105 | memcpy(p1, p2, size); 106 | memcpy(p2, buffer, size); 107 | free(buffer); 108 | } 109 | #+END_SRC 110 | * Swap 111 | - A slightly non-standard swap 112 | #+BEGIN_SRC 113 | %{ 114 | #include 115 | #include 116 | void swap(void *i, void *j, size_t size) { 117 | ... 118 | } 119 | %} 120 | 121 | 122 | #+END_SRC 123 | * Swap 124 | - A slightly non-standard swap 125 | #+BEGIN_SRC 126 | %{ 127 | #include 128 | #include 129 | void swap(void *i, void *j, size_t size) { 130 | ... 131 | } 132 | %} 133 | extern fun swap (i:ptr, j:ptr, s:size_t): void = "ext#swap" 134 | 135 | #+END_SRC 136 | 137 | * Swap 138 | - A slightly non-standard swap 139 | #+BEGIN_SRC 140 | %{ 141 | #include 142 | #include 143 | void swap(void *i, void *j, size_t size) { 144 | ... 145 | } 146 | %} 147 | extern fun swap (i:ptr, j:ptr, s:size_t) : void = "ext#swap" 148 | extern fun malloc(s:size_t):ptr = "ext#malloc" 149 | #+END_SRC 150 | * Swap 151 | - Runner 152 | #+BEGIN_SRC 153 | implement main0 () = 154 | let 155 | val i = malloc(sizeof) 156 | val j = malloc(sizeof) 157 | val _ = swap(i,j,sizeof) 158 | in 159 | () 160 | end 161 | #+END_SRC 162 | * Swap 163 | - Runner 164 | #+BEGIN_SRC 165 | implement main0 () = 166 | let 167 | val i = malloc(sizeof) // all good 168 | 169 | 170 | in 171 | 172 | end 173 | #+END_SRC 174 | * Swap 175 | - Runner 176 | #+BEGIN_SRC 177 | implement main0 () = 178 | let 179 | val i = malloc(sizeof) 180 | val j = malloc(sizeof) // uh oh! 181 | 182 | in 183 | 184 | end 185 | #+END_SRC 186 | * Swap 187 | - Runner 188 | #+BEGIN_SRC 189 | implement main0 () = 190 | let 191 | val i = malloc(sizeof) 192 | val j = malloc(sizeof) 193 | val _ = swap(i,j,sizeof) // oh noes! 194 | in 195 | 196 | end 197 | #+END_SRC 198 | * Swap 199 | - Runner 200 | #+BEGIN_SRC 201 | implement main0 () = 202 | let 203 | val i = malloc(sizeof) 204 | val j = malloc(sizeof) 205 | val _ = swap(i,j,sizeof) 206 | in 207 | () // free as in leak 208 | end 209 | #+END_SRC 210 | * Swap 211 | - Can totally mimic C 212 | - Including the bugs 213 | - Gradual migration 214 | * Swap 215 | - Safe swap 216 | #+BEGIN_SRC 217 | extern fun swap (i:ptr, j:ptr, s:size_t) : void = "ext#swap" 218 | #+END_SRC 219 | 220 | * Swap 221 | - Safe swap 222 | #+BEGIN_SRC 223 | extern fun swap : void = "ext#swap" 224 | #+END_SRC 225 | * Swap 226 | - Safe swap 227 | #+BEGIN_SRC 228 | extern fun swap : = "ext#swap" 229 | #+END_SRC 230 | * Swap 231 | - Safe swap 232 | #+BEGIN_SRC 233 | extern fun swap 234 | 235 | 236 | 237 | 238 | = "ext#swap" 239 | #+END_SRC 240 | 241 | * Swap 242 | - Safe swap 243 | #+BEGIN_SRC 244 | extern fun swap 245 | {a : t@ype} 246 | 247 | 248 | 249 | = "ext#swap" 250 | #+END_SRC 251 | * Swap 252 | - Safe swap 253 | #+BEGIN_SRC 254 | extern fun swap 255 | {a : t@ype} 256 | {l1: addr | } 257 | 258 | 259 | = "ext#swap" 260 | #+END_SRC 261 | * Swap 262 | - Safe swap 263 | #+BEGIN_SRC 264 | extern fun swap 265 | {a : t@ype} 266 | {l1: addr | l1 > null} 267 | 268 | 269 | = "ext#swap" 270 | #+END_SRC 271 | * Swap 272 | - Safe swap 273 | #+BEGIN_SRC 274 | extern fun swap 275 | {a : t@ype} 276 | {l1: addr | l1 > null} 277 | {l2: addr | l2 > null} 278 | 279 | = "ext#swap" 280 | #+END_SRC 281 | * Swap 282 | - Safe swap 283 | #+BEGIN_SRC 284 | extern fun swap 285 | {a : t@ype} 286 | {l1: addr | l1 > null} 287 | {l2: addr | l2 > null} 288 | ( i : ptr l1 ): 289 | = "ext#swap" 290 | #+END_SRC 291 | * Swap 292 | - Safe swap 293 | #+BEGIN_SRC 294 | extern fun swap 295 | {a : t@ype} 296 | {l1: addr | l1 > null} 297 | {l2: addr | l2 > null} 298 | ( i : ptr l1, j : ptr l2 ): 299 | = "ext#swap" 300 | #+END_SRC 301 | * Swap 302 | - Safe swap 303 | #+BEGIN_SRC 304 | extern fun swap 305 | {a : t@ype} 306 | {l1: addr | l1 > null} 307 | {l2: addr | l2 > null} 308 | ( i : ptr l1, j : ptr l2, s: sizeof_t a): 309 | = "ext#swap" 310 | #+END_SRC 311 | * Swap 312 | - Safe swap 313 | #+BEGIN_SRC 314 | extern fun swap 315 | {a : t@ype} 316 | {l1: addr | l1 > null} 317 | {l2: addr | l2 > null} 318 | ( | i : ptr l1, j : ptr l2, s: sizeof_t a): 319 | = "ext#swap" 320 | #+END_SRC 321 | * Swap 322 | - Safe swap 323 | #+BEGIN_SRC 324 | extern fun swap 325 | {a : t@ype} 326 | {l1: addr | l1 > null} 327 | {l2: addr | l2 > null} 328 | (a @ l1 | i : ptr l1, j : ptr l2, s: sizeof_t a): 329 | = "ext#swap" 330 | #+END_SRC 331 | * Swap 332 | - Safe swap 333 | #+BEGIN_SRC 334 | extern fun swap 335 | {a : t@ype} 336 | {l1: addr | l1 > null} 337 | {l2: addr | l2 > null} 338 | (a @ l1 , a @ l2 | i : ptr l1, j : ptr l2, s: sizeof_t a): 339 | = "ext#swap" 340 | #+END_SRC 341 | * Swap 342 | - Safe swap 343 | #+BEGIN_SRC 344 | extern fun swap 345 | {a : t@ype} 346 | {l1: addr | l1 > null} 347 | {l2: addr | l2 > null} 348 | (a @ l1 , a @ l2 | i : ptr l1, j : ptr l2, s: sizeof_t a): 349 | ( ) = "ext#swap" 350 | #+END_SRC 351 | * Swap 352 | - Safe swap 353 | #+BEGIN_SRC 354 | extern fun swap 355 | {a : t@ype} 356 | {l1: addr | l1 > null} 357 | {l2: addr | l2 > null} 358 | (a @ l1 , a @ l2 | i : ptr l1, j : ptr l2, s: sizeof_t a): 359 | ( void) = "ext#swap" 360 | #+END_SRC 361 | * Swap 362 | - Safe swap 363 | #+BEGIN_SRC 364 | extern fun swap 365 | {a : t@ype} 366 | {l1: addr | l1 > null} 367 | {l2: addr | l2 > null} 368 | (a @ l1 , a @ l2 | i : ptr l1, j : ptr l2, s: sizeof_t a): 369 | ( | void) = "ext#swap" 370 | #+END_SRC 371 | * Swap 372 | - Safe swap 373 | #+BEGIN_SRC 374 | extern fun swap 375 | {a : t@ype} 376 | {l1: addr | l1 > null} 377 | {l2: addr | l2 > null} 378 | (a @ l1 , a @ l2 | i : ptr l1, j : ptr l2, s: sizeof_t a): 379 | (a @ l1 | void) = "ext#swap" 380 | #+END_SRC 381 | * Swap 382 | - Safe swap 383 | #+BEGIN_SRC 384 | extern fun swap 385 | {a : t@ype} 386 | {l1: addr | l1 > null} 387 | {l2: addr | l2 > null} 388 | (a @ l1 , a @ l2 | i : ptr l1, j : ptr l2, s: sizeof_t a): 389 | (a @ l1, a @ l2 | void) = "ext#swap" 390 | #+END_SRC 391 | * Swap 392 | - Safe swap 393 | #+BEGIN_SRC 394 | extern fun malloc(s:size_t):ptr = "ext#malloc" 395 | #+END_SRC 396 | * Swap 397 | - Safe swap 398 | #+BEGIN_SRC 399 | extern fun malloc 400 | 401 | 402 | 403 | = "ext#malloc" 404 | #+END_SRC 405 | * Swap 406 | - Safe swap 407 | #+BEGIN_SRC 408 | extern fun malloc 409 | {a:t@ype} 410 | 411 | 412 | = "ext#malloc" 413 | #+END_SRC 414 | * Swap 415 | - Safe swap 416 | #+BEGIN_SRC 417 | extern fun malloc 418 | {a:t@ype} 419 | (s:sizeof_t a): 420 | 421 | = "ext#malloc" 422 | #+END_SRC 423 | * Swap 424 | - Safe swap 425 | #+BEGIN_SRC 426 | extern fun malloc 427 | {a:t@ype} 428 | (s:sizeof_t a): 429 | ( ptr l) 430 | = "ext#malloc" 431 | #+END_SRC 432 | * Swap 433 | - Safe swap 434 | #+BEGIN_SRC 435 | extern fun malloc 436 | {a:t@ype} 437 | (s:sizeof_t a): 438 | (a? @ l | ptr l) 439 | = "ext#malloc" 440 | #+END_SRC 441 | * Swap 442 | - Safe swap 443 | #+BEGIN_SRC 444 | extern fun malloc 445 | {a:t@ype} 446 | (s:sizeof_t a): 447 | [ ] (a? @ l | ptr l) 448 | = "ext#malloc" 449 | #+END_SRC 450 | * Swap 451 | - Safe swap 452 | #+BEGIN_SRC 453 | extern fun malloc 454 | {a:t@ype} 455 | (s:sizeof_t a): 456 | [l:addr ] (a? @ l | ptr l) 457 | = "ext#malloc" 458 | #+END_SRC 459 | * Swap 460 | - Safe swap 461 | #+BEGIN_SRC 462 | extern fun malloc 463 | {a:t@ype} 464 | (s:sizeof_t a): 465 | [l:addr | l > null] (a? @ l | ptr l) 466 | = "ext#malloc" 467 | #+END_SRC 468 | * Swap 469 | - Safe swap 470 | #+BEGIN_SRC 471 | implement main0 () = let 472 | val ( i) = malloc (sizeof) 473 | 474 | 475 | 476 | 477 | in 478 | 479 | 480 | end 481 | #+END_SRC 482 | * Swap 483 | - Safe swap 484 | #+BEGIN_SRC 485 | implement main0 () = let 486 | val ( | i) = malloc (sizeof) 487 | 488 | 489 | 490 | 491 | in 492 | 493 | 494 | end 495 | #+END_SRC 496 | * Swap 497 | - Safe swap 498 | #+BEGIN_SRC 499 | implement main0 () = let 500 | val (pfi | i) = malloc (sizeof) 501 | 502 | 503 | 504 | 505 | in 506 | 507 | 508 | end 509 | #+END_SRC 510 | * Swap 511 | - Safe swap 512 | #+BEGIN_SRC 513 | implement main0 () = let 514 | val (pfi | i) = malloc (sizeof) 515 | val (pfj | j) = malloc (sizeof) 516 | 517 | 518 | 519 | in 520 | 521 | 522 | end 523 | #+END_SRC 524 | * Swap 525 | - Safe swap 526 | #+BEGIN_SRC 527 | implement main0 () = let 528 | val (pfi | i) = malloc (sizeof) 529 | val (pfj | j) = malloc (sizeof) 530 | val = ptr_set( i, 1) 531 | 532 | 533 | in 534 | 535 | 536 | end 537 | #+END_SRC 538 | * Swap 539 | - Safe swap 540 | #+BEGIN_SRC 541 | implement main0 () = let 542 | val (pfi | i) = malloc (sizeof) 543 | val (pfj | j) = malloc (sizeof) 544 | val = ptr_set(pfi | i, 1) 545 | 546 | 547 | in 548 | 549 | 550 | end 551 | #+END_SRC 552 | * Swap 553 | - Safe swap 554 | #+BEGIN_SRC 555 | implement main0 () = let 556 | val (pfi | i) = malloc (sizeof) 557 | val (pfj | j) = malloc (sizeof) 558 | val ( ()) = ptr_set(pfi | i, 1) 559 | 560 | 561 | in 562 | 563 | 564 | end 565 | #+END_SRC 566 | * Swap 567 | - Safe swap 568 | #+BEGIN_SRC 569 | implement main0 () = let 570 | val (pfi | i) = malloc (sizeof) 571 | val (pfj | j) = malloc (sizeof) 572 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 573 | 574 | 575 | in 576 | 577 | 578 | end 579 | #+END_SRC 580 | * Swap 581 | - Safe swap 582 | #+BEGIN_SRC 583 | implement main0 () = let 584 | val (pfi | i) = malloc (sizeof) 585 | val (pfj | j) = malloc (sizeof) 586 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 587 | val (pfj1 | ()) = ptr_set(pfj | j, 2) 588 | 589 | in 590 | 591 | 592 | end 593 | #+END_SRC 594 | * Swap 595 | - Safe swap 596 | #+BEGIN_SRC 597 | implement main0 () = let 598 | val (pfi | i) = malloc (sizeof) 599 | val (pfj | j) = malloc (sizeof) 600 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 601 | val (pfj1 | ()) = ptr_set(pfj | j, 2) 602 | val = swap( i, j, sizeof) 603 | in 604 | 605 | 606 | end 607 | #+END_SRC 608 | * Swap 609 | - Safe swap 610 | #+BEGIN_SRC 611 | implement main0 () = let 612 | val (pfi | i) = malloc (sizeof) 613 | val (pfj | j) = malloc (sizeof) 614 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 615 | val (pfj1 | ()) = ptr_set(pfj | j, 2) 616 | val = swap( | i, j, sizeof) 617 | in 618 | 619 | 620 | end 621 | #+END_SRC 622 | * Swap 623 | - Safe swap 624 | #+BEGIN_SRC 625 | implement main0 () = let 626 | val (pfi | i) = malloc (sizeof) 627 | val (pfj | j) = malloc (sizeof) 628 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 629 | val (pfj1 | ()) = ptr_set(pfj | j, 2) 630 | val = swap(pfi1 | i, j, sizeof) 631 | in 632 | 633 | 634 | end 635 | #+END_SRC 636 | * Swap 637 | - Safe swap 638 | #+BEGIN_SRC 639 | implement main0 () = let 640 | val (pfi | i) = malloc (sizeof) 641 | val (pfj | j) = malloc (sizeof) 642 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 643 | val (pfj1 | ()) = ptr_set(pfj | j, 2) 644 | val = swap(pfi1, pfj2 | i, j, sizeof) 645 | in 646 | 647 | 648 | end 649 | #+END_SRC 650 | * Swap 651 | - Safe swap 652 | #+BEGIN_SRC 653 | implement main0 () = let 654 | val (pfi | i) = malloc (sizeof) 655 | val (pfj | j) = malloc (sizeof) 656 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 657 | val (pfj1 | ()) = ptr_set(pfj | j, 2) 658 | val ( ()) = swap(pfi1, pfj2 | i, j, sizeof) 659 | in 660 | 661 | 662 | end 663 | #+END_SRC 664 | * Swap 665 | - Safe swap 666 | #+BEGIN_SRC 667 | implement main0 () = let 668 | val (pfi | i) = malloc (sizeof) 669 | val (pfj | j) = malloc (sizeof) 670 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 671 | val (pfj1 | ()) = ptr_set(pfj | j, 2) 672 | val (pfi2 | ()) = swap(pfi1, pfj1 | i, j, sizeof) 673 | in 674 | 675 | 676 | end 677 | #+END_SRC 678 | * Swap 679 | - Safe swap 680 | #+BEGIN_SRC 681 | implement main0 () = let 682 | val (pfi | i) = malloc (sizeof) 683 | val (pfj | j) = malloc (sizeof) 684 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 685 | val (pfj1 | ()) = ptr_set(pfj | j, 2) 686 | val (pfi2,pfj2| ()) = swap(pfi1, pfj1 | i, j, sizeof) 687 | in 688 | 689 | 690 | end 691 | #+END_SRC 692 | * Swap 693 | - Safe swap 694 | #+BEGIN_SRC 695 | implement main0 () = let 696 | val (pfi | i) = malloc (sizeof) 697 | val (pfj | j) = malloc (sizeof) 698 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 699 | val (pfj1 | ()) = ptr_set(pfj | j, 2) 700 | val (pfi2,pfj2| ()) = swap(pfi1, pfj2 | i, j, sizeof) 701 | in 702 | free(pfi2 | i); 703 | 704 | end 705 | #+END_SRC 706 | * Swap 707 | - Safe swap 708 | #+BEGIN_EXAMPLE 709 | implement main0 () = let 710 | val (pfi | i) = malloc (sizeof) 711 | val (pfj | j) = malloc (sizeof) 712 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 713 | val (pfj2 | ()) = ptr_set(pfj | j, 2) 714 | val (pfi2,pfj2| ()) = swap(pfi1, pfj1 | i, j, sizeof) 715 | in 716 | free(pfi2 | i); 717 | free(pfj2 | j); 718 | end 719 | #+END_EXAMPLE 720 | * Swap 721 | - Safe swap 722 | #+BEGIN_EXAMPLE 723 | implement main0 () = let 724 | val (pfi | i) = malloc (sizeof) 725 | val (pfj | j) = malloc (sizeof) 726 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 727 | val (pfj2 | ()) = ptr_set(pfj | j, 2) 728 | val (pfi2,pfj2| ()) = swap(pfi1, pfj1 | i, j, sizeof) 729 | in 730 | free(pfi2 | i); 731 | free(pfj2 | j); 732 | ^^^^^^^^^^^^^^ 733 | end 734 | #+END_EXAMPLE 735 | * Swap 736 | - Safe swap 737 | #+BEGIN_EXAMPLE 738 | implement main0 () = let 739 | val (pfi | i) = malloc (sizeof) 740 | val (pfj | j) = malloc (sizeof) 741 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 742 | val (pfj2 | ()) = ptr_set(pfj | j, 2) 743 | val (pfi2,pfj2| ()) = swap(pfi1, pfj1 | i, j, sizeof) 744 | in 745 | free(pfi2 | i); 746 | ^^^^^^^^^^^^^^ 747 | free(pfj2 | j); 748 | end 749 | #+END_EXAMPLE 750 | * Swap 751 | - Safe swap 752 | #+BEGIN_EXAMPLE 753 | implement main0 () = let 754 | val (pfi | i) = malloc (sizeof) 755 | val (pfj | j) = malloc (sizeof) 756 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 757 | val (pfj2 | ()) = ptr_set(pfj | j, 2) 758 | val (pfi2,pfj2| ()) = swap(pfi1, pfj1 | i, j, sizeof) 759 | in ^^^^^^^^^^^ 760 | free(pfi2 | i); 761 | free(pfj2 | j); 762 | end 763 | #+END_EXAMPLE 764 | * Swap 765 | - Safe swap 766 | #+BEGIN_EXAMPLE 767 | implement main0 () = let 768 | val (pfi | i) = malloc (sizeof) 769 | val (pfj | j) = malloc (sizeof) 770 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 771 | ^^^^^^^^^^^^^^^^^^^ 772 | val (pfj2 | ()) = ptr_set(pfj | j, 2) 773 | val (pfi2,pfj2| ()) = swap(pfi1, pfj1 | i, j, sizeof) 774 | in 775 | free(pfi2 | i); 776 | free(pfj2 | j); 777 | end 778 | #+END_EXAMPLE 779 | * Swap 780 | - Safe swap 781 | #+BEGIN_EXAMPLE 782 | implement main0 () = let 783 | val (pfi | i) = malloc (sizeof) 784 | val (pfj | j) = malloc (sizeof) 785 | val (pfi1 | ()) = ptr_set(pfi | i, 1) 786 | val (pfj2 | ()) = ptr_set(pfj | j, 2) 787 | val (pfi2,pfj2| ()) = swap(pfi1, pfj1 | i, j, sizeof) 788 | in 789 | free(pfi2 | i); 790 | free(pfj2 | j); 791 | end 792 | #+END_EXAMPLE 793 | * Swap 794 | - Safe swap 795 | #+BEGIN_EXAMPLE 796 | implement main0 () = let 797 | (pfi ) = 798 | (pfj ) = 799 | (pfi1 ) = (pfi ) 800 | (pfj2 ) = (pfj ) 801 | (pfi2,pfj2 ) = (pfi1, pfj1 ) 802 | in 803 | (pfi2 ); 804 | (pfj2 ); 805 | end 806 | #+END_EXAMPLE 807 | * Swap 808 | - Idiomatic swap 809 | #+BEGIN_EXAMPLE 810 | fun {...} 811 | swap 812 | {...} 813 | (...) : void = 814 | let 815 | val tmp = !p1 816 | in 817 | !p1 := !p2; 818 | !p2 := tmp 819 | end 820 | #+END_EXAMPLE 821 | * Step back 822 | - Step back. 823 | - Overwhelmed? 824 | - I am! 825 | - Breathe ... 826 | * Factorial 827 | - Recursion 828 | - First class support! 829 | - Allows typechecker to prove by induction! 830 | * Factorial 831 | - Factorial 832 | #+BEGIN_EXAMPLE 833 | fun factorial 834 | { n : int | n >= 1 } 835 | (i : int n) : double = 836 | let 837 | fun loop 838 | { n : int | n >= 1 } 839 | .. 840 | (acc : double, i : int (n)) : double = 841 | case- i of 842 | | 1 => acc 843 | | i when i > 1 => loop(acc * i, i - 1) 844 | 845 | in 846 | loop(1.0, i) 847 | end 848 | #+END_EXAMPLE 849 | * Factorial 850 | - Factorial 851 | #+BEGIN_EXAMPLE 852 | fun factorial 853 | 854 | 855 | let 856 | fun loop 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | in 865 | loop(1.0, i) 866 | end 867 | #+END_EXAMPLE 868 | * Factorial 869 | - Factorial 870 | #+BEGIN_EXAMPLE 871 | fun factorial 872 | 873 | (i : int ) : = 874 | let 875 | fun loop 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | in 884 | loop(1.0, i) 885 | end 886 | #+END_EXAMPLE 887 | * Factorial 888 | - Factorial 889 | #+BEGIN_EXAMPLE 890 | fun factorial 891 | 892 | (i : int ) : double = 893 | let 894 | fun loop 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | in 903 | loop(1.0, i) 904 | end 905 | #+END_EXAMPLE 906 | * Factorial 907 | - Factorial 908 | #+BEGIN_EXAMPLE 909 | fun factorial 910 | 911 | (i : int n) : double = 912 | let 913 | fun loop 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | in 922 | loop(1.0, i) 923 | end 924 | #+END_EXAMPLE 925 | * Factorial 926 | - Factorial 927 | #+BEGIN_EXAMPLE 928 | fun factorial 929 | { n : int | n >= 1 } 930 | (i : int n) : double = 931 | let 932 | fun loop 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | in 941 | loop(1.0, i) 942 | end 943 | #+END_EXAMPLE 944 | * Factorial 945 | - Factorial 946 | #+BEGIN_EXAMPLE 947 | fun factorial 948 | { n : int | n >= 1 } 949 | (i : int n) : double = 950 | let 951 | fun loop 952 | { n : int | n >= 1 } 953 | 954 | 955 | 956 | 957 | 958 | 959 | in 960 | loop(1.0, i) 961 | end 962 | #+END_EXAMPLE 963 | * Factorial 964 | - Factorial 965 | #+BEGIN_EXAMPLE 966 | fun factorial 967 | { n : int | n >= 1 } 968 | (i : int n) : double = 969 | let 970 | fun loop 971 | { n : int | n >= 1 } 972 | 973 | (acc : double, i : int (n)) : double = 974 | 975 | 976 | 977 | 978 | in 979 | loop(1.0, i) 980 | end 981 | #+END_EXAMPLE 982 | * Factorial 983 | - Factorial 984 | #+BEGIN_EXAMPLE 985 | fun factorial 986 | { n : int | n >= 1 } 987 | (i : int n) : double = 988 | let 989 | fun loop 990 | { n : int | n >= 1 } 991 | .. 992 | (acc : double, i : int (n)) : double = 993 | 994 | 995 | 996 | 997 | in 998 | loop(1.0, i) 999 | end 1000 | #+END_EXAMPLE 1001 | * Factorial 1002 | - Factorial 1003 | #+BEGIN_EXAMPLE 1004 | fun factorial 1005 | { n : int | n >= 1 } 1006 | (i : int n) : double = 1007 | let 1008 | fun loop 1009 | { n : int | n >= 1 } 1010 | .. 1011 | (acc : double, i : int (n)) : double = 1012 | case- i of 1013 | 1014 | 1015 | 1016 | in 1017 | loop(1.0, i) 1018 | end 1019 | #+END_EXAMPLE 1020 | * Factorial 1021 | - Factorial 1022 | #+BEGIN_EXAMPLE 1023 | fun factorial 1024 | { n : int | n >= 1 } 1025 | (i : int n) : double = 1026 | let 1027 | fun loop 1028 | { n : int | n >= 1 } 1029 | .. 1030 | (acc : double, i : int (n)) : double = 1031 | case- i of 1032 | | 1 => acc 1033 | | 1034 | 1035 | in 1036 | loop(1.0, i) 1037 | end 1038 | #+END_EXAMPLE 1039 | * Factorial 1040 | - Factorial 1041 | #+BEGIN_EXAMPLE 1042 | fun factorial 1043 | { n : int | n >= 1 } 1044 | (i : int n) : double = 1045 | let 1046 | fun loop 1047 | { n : int | n >= 1 } 1048 | .. 1049 | (acc : double, i : int (n)) : double = 1050 | case- i of 1051 | | 1 => acc 1052 | | i 1053 | 1054 | in 1055 | loop(1.0, i) 1056 | end 1057 | #+END_EXAMPLE 1058 | * Factorial 1059 | - Factorial 1060 | #+BEGIN_EXAMPLE 1061 | fun factorial 1062 | { n : int | n >= 1 } 1063 | (i : int n) : double = 1064 | let 1065 | fun loop 1066 | { n : int | n >= 1 } 1067 | .. 1068 | (acc : double, i : int (n)) : double = 1069 | case- i of 1070 | | 1 => acc 1071 | | i when i > 1 1072 | 1073 | in 1074 | loop(1.0, i) 1075 | end 1076 | #+END_EXAMPLE 1077 | * Factorial 1078 | - Factorial 1079 | #+BEGIN_EXAMPLE 1080 | fun factorial 1081 | { n : int | n >= 1 } 1082 | (i : int n) : double = 1083 | let 1084 | fun loop 1085 | { n : int | n >= 1 } 1086 | .. 1087 | (acc : double, i : int (n)) : double = 1088 | case- i of 1089 | | 1 => acc 1090 | | i when i > 1 => loop(acc * i, i - 1) 1091 | 1092 | in 1093 | loop(1.0, i) 1094 | end 1095 | #+END_EXAMPLE 1096 | * Factorial 1097 | - Factorial 1098 | #+BEGIN_EXAMPLE 1099 | fun factorial 1100 | 1101 | 1102 | let 1103 | fun loop 1104 | { n : int | n >= 1 } <--- 1105 | 1106 | 1107 | case- i of 1108 | | 1109 | | i when i > 1 => loop(acc * i, i - 1) 1110 | ^^^^^^^^^^ 1111 | in 1112 | loop(1.0, i) 1113 | end 1114 | #+END_EXAMPLE 1115 | * Factorial 1116 | - Factorial 1117 | #+BEGIN_EXAMPLE 1118 | fun factorial 1119 | 1120 | 1121 | let 1122 | fun loop 1123 | { n : int | n >= 1 } <--- 1124 | 1125 | 1126 | case- i of 1127 | | 1128 | | i when i > 1 => loop(acc * i, i - 1) 1129 | ^^^^^ 1130 | in 1131 | loop(1.0, i) 1132 | end 1133 | #+END_EXAMPLE 1134 | * Factorial 1135 | - Factorial 1136 | #+BEGIN_EXAMPLE 1137 | fun factorial 1138 | 1139 | 1140 | let 1141 | fun loop 1142 | 1143 | .. <--- 1144 | 1145 | case- i of 1146 | | 1147 | | i when i > 1 => loop(acc * i, i + 1) 1148 | ^^^^^ 1149 | in 1150 | loop(1.0, i) 1151 | end 1152 | #+END_EXAMPLE 1153 | * Viewtype 1154 | - Viewtype 1155 | - Connects ADTs, linear resources 1156 | * Viewtype 1157 | - Remember 'swap'? 1158 | #+BEGIN_EXAMPLE 1159 | extern fun swap 1160 | {a:t@ype} 1161 | {l1: addr | l1 > null} 1162 | {l2: addr | l2 > null} 1163 | (a @ l1 , a @ l2 | i : ptr l1, j : ptr l2, s: sizeof_t a): 1164 | (a @ l1, a @ l2 | void) = "ext#swap" 1165 | 1166 | 1167 | 1168 | 1169 | #+END_EXAMPLE 1170 | * Viewtype 1171 | - Remember 'swap'? 1172 | #+BEGIN_EXAMPLE 1173 | extern fun swap 1174 | {a:t@ype} 1175 | {l1: addr | l1 > null} 1176 | 1177 | (a @ l1 | i : ptr l1 ): 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | #+END_EXAMPLE 1184 | * Viewtype 1185 | - Remember 'swap'? 1186 | #+BEGIN_EXAMPLE 1187 | extern fun swap 1188 | {a:t@ype} 1189 | {l1: addr | l1 > null} 1190 | 1191 | (a @ l1 | i : ptr l1 ): 1192 | 1193 | sortdef ... 1194 | 1195 | viewtypedef ... 1196 | 1197 | #+END_EXAMPLE 1198 | * Viewtype 1199 | - Remember 'swap'? 1200 | #+BEGIN_EXAMPLE 1201 | extern fun swap 1202 | {a:t@ype} 1203 | {l1: addr | l1 > null} 1204 | ^^^^^^^^^^^^^^^^^^^^^^ 1205 | (a @ l1 | i : ptr l1 ): 1206 | 1207 | sortdef agz = {l:addr | l > null} 1208 | ^^^^^^^^^^^^^^^^^^ 1209 | viewtypedef ... 1210 | 1211 | #+END_EXAMPLE 1212 | * Viewtype 1213 | - Remember 'swap'? 1214 | #+BEGIN_EXAMPLE 1215 | extern fun swap 1216 | {a:t@ype} 1217 | {l1: addr | l1 > null} 1218 | ^^^^^^^^^^^^^^^^^^^^^^ 1219 | (a @ l1 | i : ptr l1 ): 1220 | ^^^^^^ ^^^^^^ 1221 | sortdef agz = {l:addr | l > null} 1222 | ^^^^^^^^^^^^^^^^^^ 1223 | viewtypedef (a @ l | ptr l) 1224 | ^^^^^ ^^^^^ 1225 | #+END_EXAMPLE 1226 | * Viewtype 1227 | - Remember 'swap'? 1228 | #+BEGIN_EXAMPLE 1229 | extern fun swap 1230 | {a:t@ype} 1231 | {l1: addr | l1 > null} 1232 | 1233 | (a @ l1 | i : ptr l1 ): 1234 | 1235 | sortdef agz = {l:addr | l > null} 1236 | ^^^ 1237 | viewtypedef [l:agz] (a @ l | ptr l) 1238 | ^^^^^^^ 1239 | #+END_EXAMPLE 1240 | * Viewtype 1241 | - Remember 'swap'? 1242 | #+BEGIN_EXAMPLE 1243 | extern fun swap 1244 | {a:t@ype} 1245 | {l1: addr | l1 > null} 1246 | 1247 | (a @ l1 | i : ptr l1 ): 1248 | 1249 | sortdef agz = {l:addr | l > null} 1250 | 1251 | viewtypedef safe_ptr(a:t@ype) = [l:agz] (a @ l | ptr l) 1252 | 1253 | #+END_EXAMPLE 1254 | * Viewtype 1255 | - Remember 'swap'? 1256 | #+BEGIN_EXAMPLE 1257 | extern fun swap 1258 | {a:t@ype} 1259 | {l1: addr | l1 > null} 1260 | 1261 | (a @ l1 | i : ptr l1 ): 1262 | 1263 | sortdef agz = {l:addr | l > null} 1264 | ^^^ 1265 | viewtypedef safe_ptr(a:t@ype) = [l:agz] (a @ l | ptr l) 1266 | ^^^^^^^ 1267 | #+END_EXAMPLE 1268 | * Viewtype 1269 | - Remember 'swap'? 1270 | #+BEGIN_EXAMPLE 1271 | extern fun swap 1272 | {a:t@ype} 1273 | {l1: addr | l1 > null} 1274 | 1275 | (a @ l1 | i : ptr l1 ): 1276 | 1277 | 1278 | 1279 | 1280 | 1281 | #+END_EXAMPLE 1282 | * Viewtype 1283 | - Remember 'swap'? 1284 | #+BEGIN_EXAMPLE 1285 | extern fun swap 1286 | {a:t@ype} 1287 | 1288 | 1289 | ( i : safe_ptr a ): 1290 | 1291 | 1292 | 1293 | 1294 | 1295 | #+END_EXAMPLE 1296 | * Viewtypes 1297 | - Viewtypes are the basic building block 1298 | - Can create algebras of linear resources! 1299 | * Algebraic datatypes 1300 | - Linear lists 1301 | #+BEGIN_EXAMPLE 1302 | dataviewtype list_vt 1303 | (a:viewt@ype, int) = 1304 | | list_vt_nil(a, 0) of () 1305 | | {n:int | n > 0} 1306 | list_vt_cons(a, n) of (a, list_vt(a, n-1)) 1307 | #+END_EXAMPLE 1308 | * Algebraic datatypes 1309 | - Linear lists 1310 | #+BEGIN_EXAMPLE 1311 | dataviewtype list_vt 1312 | ( ) = 1313 | | list_vt_nil 1314 | | 1315 | list_vt_cons 1316 | #+END_EXAMPLE 1317 | * Algebraic datatypes 1318 | - Linear lists 1319 | #+BEGIN_EXAMPLE 1320 | dataviewtype list_vt 1321 | (a:viewt@ype ) = 1322 | | list_vt_nil 1323 | | 1324 | list_vt_cons 1325 | #+END_EXAMPLE 1326 | * Algebraic datatypes 1327 | - Linear lists 1328 | #+BEGIN_EXAMPLE 1329 | dataviewtype list_vt 1330 | (a:viewt@ype, int) = 1331 | | list_vt_nil 1332 | | 1333 | list_vt_cons 1334 | #+END_EXAMPLE 1335 | * Algebraic datatypes 1336 | - Linear lists 1337 | #+BEGIN_EXAMPLE 1338 | dataviewtype list_vt 1339 | (a:viewt@ype, int) = 1340 | | list_vt_nil(a, 0) of () 1341 | | 1342 | list_vt_cons 1343 | #+END_EXAMPLE 1344 | * Algebraic datatypes 1345 | - Linear lists 1346 | #+BEGIN_EXAMPLE 1347 | dataviewtype list_vt 1348 | (a:viewt@ype, int) = 1349 | | list_vt_nil(a, 0) of () 1350 | | 1351 | list_vt_cons(a, n) 1352 | #+END_EXAMPLE 1353 | * Algebraic datatypes 1354 | - Linear lists 1355 | #+BEGIN_EXAMPLE 1356 | dataviewtype list_vt 1357 | (a:viewt@ype, int) = 1358 | | list_vt_nil(a, 0) of () 1359 | | 1360 | list_vt_cons(a, n) of (a, list_vt(a, n-1)) 1361 | #+END_EXAMPLE 1362 | * Algebraic datatypes 1363 | - Linear lists 1364 | #+BEGIN_EXAMPLE 1365 | dataviewtype list_vt 1366 | (a:viewt@ype, int) = 1367 | | list_vt_nil(a, 0) of () 1368 | | {n:int | n > 0} 1369 | list_vt_cons(a, n) of (a, list_vt(a, n-1)) 1370 | #+END_EXAMPLE 1371 | * Algebraic datatypes 1372 | - Linear lists 1373 | #+BEGIN_EXAMPLE 1374 | list_vt_cons(1, 1375 | list_vt_cons(2, 1376 | list_vt_nil())) : list_vt(int,2) 1377 | #+END_EXAMPLE 1378 | * Factorial 1379 | - A factorial that preserves intermediate results in a list 1380 | #+BEGIN_EXAMPLE 1381 | factorial(10) 1382 | => [(10 * 9), (10 * 9 * 8), (10 * 9 * 8 * 7) ...] 1383 | #+END_EXAMPLE 1384 | * Factorial 1385 | - Factorial with intermediate results 1386 | #+BEGIN_EXAMPLE 1387 | fun factorial 1388 | {n:int | n >= 2} 1389 | (i:int n): list_vt(double, n-1) = 1390 | let 1391 | var res : ptr 1392 | fun loop 1393 | ... 1394 | val initial = g0i2f(i) * g0i2f(i-1) 1395 | val () = loop(initial,i-2,res) 1396 | in 1397 | res 1398 | end 1399 | #+END_EXAMPLE 1400 | * Factorial 1401 | - Factorial with intermediate results 1402 | #+BEGIN_EXAMPLE 1403 | fun factorial 1404 | 1405 | 1406 | let 1407 | var res : ptr 1408 | fun loop 1409 | ... 1410 | 1411 | 1412 | in 1413 | res 1414 | end 1415 | #+END_EXAMPLE 1416 | * Factorial 1417 | - Factorial with intermediate results 1418 | #+BEGIN_EXAMPLE 1419 | fun factorial 1420 | 1421 | (i:int ): = 1422 | let 1423 | var res : ptr 1424 | fun loop 1425 | ... 1426 | 1427 | 1428 | in 1429 | res 1430 | end 1431 | #+END_EXAMPLE 1432 | * Factorial 1433 | - Factorial with intermediate results 1434 | #+BEGIN_EXAMPLE 1435 | fun factorial 1436 | {n:int | n >= 2} 1437 | (i:int n): = 1438 | let 1439 | var res : ptr 1440 | fun loop 1441 | ... 1442 | 1443 | 1444 | in 1445 | res 1446 | end 1447 | #+END_EXAMPLE 1448 | * Factorial 1449 | - Factorial with intermediate results 1450 | #+BEGIN_EXAMPLE 1451 | fun factorial 1452 | {n:int | n >= 2} 1453 | (i:int n): list_vt(double, n-1) = 1454 | let 1455 | var res : ptr 1456 | fun loop 1457 | ... 1458 | 1459 | 1460 | in 1461 | res 1462 | end 1463 | #+END_EXAMPLE 1464 | * Factorial 1465 | - Factorial with intermediate results 1466 | #+BEGIN_EXAMPLE 1467 | fun factorial 1468 | {n:int | n >= 2} 1469 | (i:int n): list_vt(double, n-1) = 1470 | let 1471 | var res : ptr 1472 | fun loop 1473 | ... 1474 | val initial = g0i2f(i) * g0i2f(i-1) 1475 | 1476 | in 1477 | res 1478 | end 1479 | #+END_EXAMPLE 1480 | * Factorial 1481 | - Factorial with intermediate results 1482 | #+BEGIN_EXAMPLE 1483 | fun factorial 1484 | {n:int | n >= 2} 1485 | (i:int n): list_vt(double, n-1) = 1486 | let 1487 | var res : ptr 1488 | fun loop 1489 | ... 1490 | val initial = g0i2f(i) * g0i2f(i-1) 1491 | val () = loop(initial,i-2,res) 1492 | in 1493 | res 1494 | end 1495 | #+END_EXAMPLE 1496 | * Factorial 1497 | - Factorial with intermediate results 1498 | #+BEGIN_EXAMPLE 1499 | fun factorial 1500 | 1501 | 1502 | let 1503 | var res : ptr 1504 | fun loop 1505 | ... 1506 | val initial = ... 1507 | val () = loop(initial,i-2,res) 1508 | in 1509 | res 1510 | end 1511 | #+END_EXAMPLE 1512 | * Factorial 1513 | - Factorial with intermediate results 1514 | #+BEGIN_EXAMPLE 1515 | fun factorial 1516 | {n:int | n >= 2} 1517 | (i:int n): = 1518 | let 1519 | var res : ptr 1520 | fun loop 1521 | ... 1522 | val initial = ... 1523 | val () = loop(initial,i-2,res) 1524 | in 1525 | res 1526 | end 1527 | #+END_EXAMPLE 1528 | * Factorial 1529 | - Factorial with intermediate results 1530 | #+BEGIN_EXAMPLE 1531 | fun factorial 1532 | {n:int | n >= 2} 1533 | (i:int n): list_vt(double, n-1) = 1534 | let 1535 | var res : ptr 1536 | fun loop 1537 | ... 1538 | val initial = ... 1539 | val () = loop(initial,i-2,res) 1540 | in 1541 | res 1542 | end 1543 | #+END_EXAMPLE 1544 | * Factorial 1545 | - Factorial with intermediate results 1546 | #+BEGIN_EXAMPLE 1547 | fun factorial 1548 | {n:int | n >= 2} 1549 | (i:int n): list_vt(double, n-1) = 1550 | let 1551 | var res : ptr 1552 | fun loop 1553 | ... 1554 | val initial = g0i2f(i) * g0i2f(i-1) 1555 | val () = loop(initial,i-2,res) 1556 | in 1557 | res 1558 | end 1559 | #+END_EXAMPLE 1560 | * Factorial 1561 | - Inner loop 1562 | #+BEGIN_EXAMPLE 1563 | fun loop 1564 | {n1:int | n1 >= 0 && n1 <= n-2} 1565 | .. 1566 | ( 1567 | seed: double, 1568 | next: int n1, 1569 | res: &ptr? >> list_vt(double, n1+1) 1570 | ) : void = ... 1571 | #+END_EXAMPLE 1572 | * Factorial 1573 | - Inner loop 1574 | #+BEGIN_EXAMPLE 1575 | fun loop 1576 | { } 1577 | .< >. 1578 | ( 1579 | 1580 | 1581 | 1582 | ) : void = ... 1583 | #+END_EXAMPLE 1584 | * Factorial 1585 | - Inner loop 1586 | #+BEGIN_EXAMPLE 1587 | fun loop 1588 | { } 1589 | .< >. 1590 | ( 1591 | 1592 | next: int n1, 1593 | 1594 | ) : void = ... 1595 | #+END_EXAMPLE 1596 | * Factorial 1597 | - Inner loop 1598 | #+BEGIN_EXAMPLE 1599 | fun loop 1600 | {n1:int | n1 >= 0 && n1 <= n-2} 1601 | .. 1602 | ( 1603 | 1604 | next: int n1, 1605 | 1606 | ) : void = ... 1607 | #+END_EXAMPLE 1608 | * Factorial 1609 | - Inner loop 1610 | #+BEGIN_EXAMPLE 1611 | fun loop 1612 | {n1:int | n1 >= 0 && n1 <= n-2} 1613 | ^^^^^^^^^ 1614 | 1615 | ... 1616 | fun factorial {n:int | n >= 2} (i:int n) 1617 | ... 1618 | val () = loop(initial,i-2,res) 1619 | #+END_EXAMPLE 1620 | * Factorial 1621 | - Inner loop 1622 | #+BEGIN_EXAMPLE 1623 | fun loop 1624 | {n1:int | n1 >= 0 && n1 <= n-2} 1625 | .. 1626 | ( 1627 | 1628 | next: int n1, 1629 | 1630 | ) : void = ... 1631 | #+END_EXAMPLE 1632 | * Factorial 1633 | - Inner loop 1634 | #+BEGIN_EXAMPLE 1635 | fun loop 1636 | {n1:int | n1 >= 0 && n1 <= n-2} 1637 | .. 1638 | ( 1639 | seed: double, 1640 | next: int n1, 1641 | 1642 | ) : void = ... 1643 | #+END_EXAMPLE 1644 | * Factorial 1645 | - Inner loop 1646 | #+BEGIN_EXAMPLE 1647 | fun loop 1648 | {n1:int | n1 >= 0 && n1 <= n-2} 1649 | .. 1650 | ( 1651 | seed: double, 1652 | next: int n1, 1653 | res: &ptr? 1654 | ) : void = ... 1655 | #+END_EXAMPLE 1656 | * Factorial 1657 | - Inner loop 1658 | #+BEGIN_EXAMPLE 1659 | fun loop 1660 | {n1:int | n1 >= 0 && n1 <= n-2} 1661 | .. 1662 | ( 1663 | seed: double, 1664 | next: int n1, 1665 | res: &ptr? >> list_vt(double, n1+1) 1666 | ) : void = ... 1667 | #+END_EXAMPLE 1668 | * Factorial 1669 | - Inner loop 1670 | #+BEGIN_EXAMPLE 1671 | fun loop 1672 | 1673 | 1674 | = ... 1675 | case- next of 1676 | | 0 => 1677 | | next when next > 0 => 1678 | let 1679 | 1680 | 1681 | 1682 | 1683 | 1684 | in 1685 | end 1686 | #+END_EXAMPLE 1687 | * Factorial 1688 | - Inner loop 1689 | #+BEGIN_EXAMPLE 1690 | fun loop ( seed: double, 1691 | next: int n1, 1692 | res: &ptr? >> list_vt(double, n1+1) 1693 | ) : void = ... 1694 | case- next of 1695 | | 0 => 1696 | | next when next > 0 => 1697 | let 1698 | 1699 | 1700 | 1701 | 1702 | 1703 | in 1704 | end 1705 | #+END_EXAMPLE 1706 | * Factorial 1707 | - Inner loop 1708 | #+BEGIN_EXAMPLE 1709 | fun loop ( seed: double, 1710 | next: int n1, 1711 | res: &ptr? >> list_vt(double, n1+1) 1712 | ) : void = ... 1713 | case- next of 1714 | | 0 => res := list_vt_cons(seed, list_vt_nil()) 1715 | | next when next > 0 => 1716 | let 1717 | 1718 | 1719 | 1720 | 1721 | 1722 | in 1723 | end 1724 | #+END_EXAMPLE 1725 | * Factorial 1726 | - Solve this puzzle in a strict FP language! 1727 | - Fold over a list and copy it! 1728 | - As efficiently as a while/for loop with initial null 1729 | - That's it! 1730 | * Factorial 1731 | - But! 1732 | - No reversing at the end! (1-pass only) 1733 | - No macros! 1734 | - No continuations! 1735 | - No peep holing! 1736 | - No weird optimization pragmas 1737 | * Factorial 1738 | - MLTon reverses 1739 | - OCaml peep holes 1740 | - Rust (uses macros or peep holes) 1741 | * Factorial 1742 | - Until recently these were elegant! 1743 | - Now just dissatisfied! 1744 | - ATS supports "tail allocation" 1745 | - A principled, safe way of passing 1746 | along a "hole" 1747 | * Factorial 1748 | - Inner loop 1749 | #+BEGIN_EXAMPLE 1750 | fun loop ( seed: double, 1751 | next: int n1, 1752 | res: &ptr? >> list_vt(double, n1+1) 1753 | ) : void = ... 1754 | case- next of 1755 | | 0 => res := list_vt_cons(seed, list_vt_nil()) 1756 | | next when next > 0 => 1757 | let 1758 | val () = res := list_vt_cons{..}{n1+1}(seed, _) 1759 | 1760 | 1761 | 1762 | 1763 | in 1764 | end 1765 | #+END_EXAMPLE 1766 | * Factorial 1767 | - Inner loop 1768 | #+BEGIN_EXAMPLE 1769 | fun loop ( seed: double, 1770 | next: int n1, 1771 | res: &ptr? >> list_vt(double, n1+1) 1772 | ) : void = ... 1773 | case- next of 1774 | | 0 => 1775 | | => 1776 | let 1777 | val () = res := list_vt_cons{..}{n1+1}(seed, _) 1778 | 1779 | 1780 | 1781 | 1782 | in 1783 | end 1784 | #+END_EXAMPLE 1785 | * Factorial 1786 | - Inner loop 1787 | #+BEGIN_EXAMPLE 1788 | fun loop ( seed: double, 1789 | next: int n1, 1790 | res: &ptr? >> list_vt(double, n1+1) 1791 | ) : void = ... 1792 | case- next of 1793 | | 0 => 1794 | | => 1795 | let 1796 | val () = res := list_vt_cons{..}{n1+1}(seed, _) 1797 | | 1798 | an uninitialized hole-------+ 1799 | 1800 | 1801 | in 1802 | end 1803 | #+END_EXAMPLE 1804 | * Factorial 1805 | - Inner loop 1806 | #+BEGIN_EXAMPLE 1807 | fun loop ( seed: double, 1808 | next: int n1, 1809 | res: &ptr? >> list_vt(double, n1+1) 1810 | ) : void = ... 1811 | case- next of 1812 | | 0 => 1813 | | => 1814 | let 1815 | val () = res := list_vt_cons{..}{n1+1}(seed, _) 1816 | val+list_vt_cons(_,hole) = res | 1817 | | | 1818 | +-- uninitialized hole --+ 1819 | 1820 | in 1821 | end 1822 | #+END_EXAMPLE 1823 | * Factorial 1824 | - Inner loop 1825 | #+BEGIN_EXAMPLE 1826 | fun loop ( seed: double, 1827 | next: int n1, 1828 | res: &ptr? >> list_vt(double, n1+1) 1829 | ) : void = ... 1830 | case- next of 1831 | | 0 => 1832 | | => 1833 | let 1834 | val () = res := list_vt_cons{..}{n1+1}(seed, _) 1835 | val+list_vt_cons(_,hole) = res 1836 | val curr = seed * g0i2f(next) 1837 | 1838 | 1839 | in 1840 | end 1841 | #+END_EXAMPLE 1842 | * Factorial 1843 | - Inner loop 1844 | #+BEGIN_EXAMPLE 1845 | fun loop ( seed: double, 1846 | next: int n1, 1847 | res: &ptr? >> list_vt(double, n1+1) 1848 | ) : void = ... 1849 | case- next of 1850 | | 0 => 1851 | | => 1852 | let 1853 | val () = res := list_vt_cons{..}{n1+1}(seed, _) 1854 | val+list_vt_cons(_,hole) = res 1855 | val curr = seed * g0i2f(next) 1856 | val () = loop(curr, next-1, hole) 1857 | | 1858 | in to be filled! --+ 1859 | end 1860 | #+END_EXAMPLE 1861 | * Factorial 1862 | - Inner loop 1863 | #+BEGIN_EXAMPLE 1864 | fun loop 1865 | 1866 | 1867 | = ... 1868 | case- next of 1869 | | 1870 | | next +----------------------------------+ 1871 | let | | 1872 | res := list_vt_cons ( , _) 1873 | | | 1874 | +------------------+ | 1875 | loop( , hole) | 1876 | | | 1877 | in +---------------+ 1878 | end 1879 | #+END_EXAMPLE 1880 | * Sum up 1881 | - ATS is rough 1882 | - but contains glimpses of the sys. programming future! 1883 | - Linear logic 1884 | - Great idea! 1885 | - Need 1st class access 1886 | - Refinement types 1887 | - Great idea! 1888 | - Other languages are coming around to it 1889 | * Sum up 1890 | - Smart typechecker/dumb compiler 1891 | - Amazing idea! 1892 | - ATS is a frontend to C 1893 | - Haven't even talked about 1894 | - ATS has a whole proof level language 1895 | - Pattern matching and all! 1896 | * The end 1897 | - Repo for this talk 1898 | - https://github.com/deech/ATS-Strange-Loop-Talk 1899 | - Chris Double's blog 1900 | - It's amazing (read everything!) 1901 | - https://bluishcoder.co.nz/tags/ats/index.html 1902 | - The ATS website 1903 | - http://www.ats-lang.org/ 1904 | - The canonical book 1905 | - http://ats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/HTML/book1.html 1906 | - Google group 1907 | - Very helpful! 1908 | - https://groups.google.com/forum/#!forum/ats-lang-users 1909 | - Thanks! 1910 | --------------------------------------------------------------------------------