├── .gitmodules ├── README.md └── skio.scm /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "miniKanren-with-symbolic-constraints"] 2 | path = miniKanren-with-symbolic-constraints 3 | url = https://www.github.com/jpt4/miniKanren-with-symbolic-constraints 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## A Relational SKI Combinator Calculus Interpreter 2 | 3 | ### Introduction 4 | A naive, purely relational interpreter for the SKI Combinator Calculus, written in miniKanren. 5 | 6 | ### Compatibility 7 | This project is developed on Arch Linux against Chez Scheme v9.4-1, and the copy of Will Byrd's miniKanren-with-symbolic-constraints included in this repository. It has not been tested under any other configuration. 8 | 9 | ### Setup 10 | ``` 11 | $ git clone [this-repository] 12 | 13 | $ cd [repo-directory] 14 | 15 | $ [launch Chez Scheme] 16 | 17 | > (load "skio.scm") 18 | ``` 19 | 20 | ### Contents 21 | `skio` interprets input expressions regardless of parenthesization, converting them to left-associative normal form if necessary, and is best used for forward evaluation. 22 | 23 | `skio-syn` elides the left-associativity preprocessor, thus requiring fully parenthesized input expressions, to allow for greater variety during reverse expression synthesis. 24 | 25 | `laso` converts expressions to their fully left-associative, parenthesized forms. 26 | 27 | `io`, `ko`, and `so` each perform a single step of the eponymous reduction on fully left-associative expressions; useful for checking manual derivations. 28 | 29 | An input expression is a quoted (potentially nested) list of symbols, including the reserved symbols `S`, `K`, and `I`. 30 | 31 | For both `skio` and `skio-syn`, the number of results requested must be included, e.g. `(skio EXP NUM)`. *Because the evaluation order of miniKanren is unspecified, the most reduced answer may not be the first produced, especially for expressions which simulate recursion.* However, if an answer exists, then their exists a `NUM` value large enough such that the result set will include it. 32 | 33 | ### Examples 34 | ``` 35 | > (skio '(S I I a) 1) 36 | 37 | ((a a)) 38 | 39 | > (skio '(S I I (S I I)) 1) 40 | 41 | ((((S I) I) ((S I) I))) 42 | 43 | > (skio '(S (K a) (S I I) b) 1) 44 | 45 | ((a (b b))) 46 | 47 | > (define beta '(S (K a) (S I I))) 48 | 49 | > beta 50 | 51 | (S (K a) (S I I)) 52 | 53 | > (define exp (list 'S 'I 'I beta)) 54 | 55 | > exp 56 | (S I I (S (K a) (S I I))) 57 | 58 | > (skio exp 3) 59 | ((((S I) I) ((S (K a)) ((S I) I))) 60 | (((S I) I) ((S (K a)) ((S I) I))) 61 | (((S (K a)) ((S I) I)) ((S (K a)) ((S I) I)))) 62 | 63 | > (skio-syn 'a 10) 64 | (a 65 | (I a) 66 | ((K a) _.0) 67 | (I (I a)) 68 | (I ((K a) _.0)) 69 | ((K (I a)) _.0) 70 | (I (I (I a))) 71 | ((K ((K a) _.0)) _.1) 72 | (I (I ((K a) _.0))) 73 | (((S K) _.0) a)) 74 | ``` 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /skio.scm: -------------------------------------------------------------------------------- 1 | ;;skio.scm 2 | ;;utc20170530 3 | ;;jpt4 4 | ;;Relational SKI combinator calculus interpreter in miniKanren 5 | ;;Chez Scheme v9.4-1 6 | 7 | (load "miniKanren-with-symbolic-constraints/mk.scm") 8 | 9 | ;;the universe of variables 10 | (define (varo i) 11 | (conde 12 | [(symbolo i) 13 | (=/= 'I i) (=/= 'K i) (=/= 'S i)])) 14 | ;;and combinators 15 | (define (combo i) 16 | (conde 17 | [(== 'I i)] 18 | [(== 'K i)] 19 | [(== 'S i)])) 20 | ;;terms thereof 21 | (define (termo i) 22 | (conde 23 | [(varo i)] 24 | [(combo i)] 25 | [(fresh (a d) 26 | (== `(,a ,d) i) 27 | (termo a) (termo d))])) 28 | 29 | ;;coerce left association in expressions 30 | (define (laso i o) 31 | (conde 32 | [(termo i) (== i o)] 33 | [(fresh (a b resa resb) 34 | (== `(,a ,b) i) 35 | (laso a resa) (laso b resb) (== `(,resa ,resb) o))] 36 | [(fresh (a b c resa resb resc) 37 | (== `(,a ,b ,c) i) 38 | (laso a resa) (laso b resb) (laso c resc) 39 | (== `((,resa ,resb) ,resc) o))] 40 | [(fresh (a b c resa resb resc) 41 | (== `(,a ,b . ,c) i) (=/= '() c) 42 | (laso a resa) (laso b resb) (laso `((,resa ,resb) . ,c) o) 43 | )] 44 | )) 45 | 46 | ;;combinator reductions 47 | (define (io i o) 48 | (fresh (x) 49 | (conde 50 | [(== `(I ,x) i) (== x o)]))) 51 | (define (ko i o) 52 | (fresh (x y) 53 | (conde 54 | [(== `((K ,x) ,y) i) (== x o)]))) 55 | (define (so i o) 56 | (fresh (x y z) 57 | (conde 58 | [(== `(((S ,x) ,y) ,z) i) (== `((,x ,z) (,y ,z)) o)]))) 59 | 60 | ;;core interpreter 61 | (define (skio-core i t o) 62 | (fresh (a b c t0 t1 t2 resa resb rest res diag) 63 | (conde 64 | [(== `(,t1 (,t1 ,t2)) t) (== i t1) (== i o)] 65 | [(== `(,t2 (,t1 ,t0)) t) (=/= t2 t1) 66 | (conde 67 | [(combo i) (== i o)] 68 | [(varo i) (== i o)] 69 | [(io i res) (== `(,res (,t2 ,t1)) rest) (skio-core res rest o)] 70 | [(ko i res) (== `(,res (,t2 ,t1)) rest) (skio-core res rest o)] 71 | [(so i res) (== `(,res (,t2 ,t1)) rest) (skio-core res rest o)] 72 | [(== `(,a ,b) i) 73 | (skio-core a t resa) (skio-core b t resb) 74 | (== `(,resa ,resb) res) (== `(,res (,t2 ,t1)) rest) 75 | (skio-core res rest o)] 76 | )]))) 77 | 78 | ;;interpreter interfaces - note, contaminates mK relational logic with Scheme 79 | ;input evaluation (forward interpretation) 80 | (define (skio exp num) 81 | (let* ([t0 (gensym)] [t1 (gensym)] [t2 (gensym)] 82 | [init (list t2 (list t1 t0))]) 83 | (run num (q) (fresh (i) 84 | (laso exp i) (skio-core i init q))))) 85 | 86 | ;input synthesis (reverse interpretation) - no laso preprocessing 87 | (define (skio-syn exp num) 88 | (let* ([t0 (gensym)] [t1 (gensym)] [t2 (gensym)] 89 | [init (list t2 (list t1 t0))]) 90 | (run num (q) (skio-core q init exp)))) 91 | 92 | ;;Diagnostics instrumented interpreter core 93 | (define (skio-core-diag i t o) 94 | (fresh (a b c t0 t1 t2 resa resb rest res diag) 95 | (conde 96 | [(== `(,t1 (,t1 ,t2)) t) (== i t1) (== i o) 97 | #;(== `(stop i=,i a=,a b=,b t=,t) o)] 98 | [(== `(,t2 (,t1 ,t0)) t) (=/= t2 t1) 99 | #;(== `(go i=,i t=,t t2=,t2 t1=,t1 t0=,t0) o) 100 | (conde 101 | [(combo i) (== i o) 102 | #;(== `(combo i=,i) o)] 103 | [(varo i) (== i o) 104 | #;(== `(varo i=,i) o)] 105 | [(io i res) (== `(,res (,t2 ,t1)) rest) (skio-core-diag res rest o) 106 | #;(skio-core-diag res rest diag) 107 | #;(== `(io i=,i res=,res t=,t rest=,rest diag=,diag) o)] 108 | [(ko i res) (== `(,res (,t2 ,t1)) rest) (skio-core-diag res rest o) 109 | #;(skio-core-diag res rest diag) 110 | #;(== `(ko i=,i res=,res t=,t rest=,rest diag=,diag) o)] 111 | [(so i res) (== `(,res (,t2 ,t1)) rest) (skio-core-diag res rest o) 112 | #;(skio-core-diag res rest diag) 113 | #;(== `(so i=,i res=,res t=,t rest=,rest diag=,diag) o)] 114 | [(== `(,a ,b) i) 115 | (skio-core-diag a t resa) (skio-core-diag b t resb) 116 | (== `(,resa ,resb) res) (== `(,res (,t2 ,t1)) rest) 117 | (skio-core-diag res rest o) 118 | #;(skio-core-diag res rest diag) 119 | #;(== `(pair i=,i a=,a b=,b t=,t resa=,resa resb=,resb res=,res 120 | rest=,rest diag=,diag) o)] 121 | )]))) 122 | 123 | ;;;UNDER CONSTRUCTION FROM THIS POINT ONWARDS 124 | ;;record entire derivation history for a inspection 125 | (define (skio-hist i t tls o) 126 | (fresh (a b c t0 t1 t2 resa resb rest res diag) 127 | (conde 128 | [(== `(,a (,a ,b)) t) (== i a) (== i o) 129 | #;(== `(stop i=,i a=,a b=,b t=,t t=,t) o)] 130 | [(== `(,t2 (,t1 ,t0)) t) (=/= t2 t1) 131 | #;(== `(go i=,i t=,t t2=,t2 t1=,t1 t0=,t0) o) 132 | (conde 133 | [(combo i) (== `(,i ,tls) rest) (skio-hist i rest t o)] 134 | [(varo i) (== `(,i ,t) rest) (skio-hist i rest t o)] 135 | [(strict-io i res) (== `(,res (,t2 ,t1)) rest) (skio-hist res rest t o) 136 | #;(skio-hist res rest t diag) 137 | #;(== `(so i=,i res=,res t=,t rest=,rest t=,t diag=,diag) o)] 138 | [(strict-ko i res) (== `(,res (,t2 ,t1)) rest) #;(skio-hist res rest t o) 139 | (skio-hist res rest t diag) 140 | (== `(so i=,i res=,res t=,t rest=,rest t=,t diag=,diag) o)] 141 | [(strict-so i res) (== `(,res (,t2 ,t1)) rest) (skio-hist res rest t o) 142 | #;(skio-hist res rest t diag) 143 | #;(== `(so i=,i res=,res t=,t rest=,rest t=,t diag=,diag) o)] 144 | [(== `(,a ,b) i) (skio-hist a d t resa) (skio-hist b d t resb) 145 | (== `(,resa ,resb) res) (== `(,res (,t2 ,t1)) rest) #;(skio-hist res rest t o) 146 | #;(skio-hist res rest t diag) 147 | (== `(pair i=,i a=,a b=,b resa=,resa resb=,resb res=,res rest=,rest t=,t t=,t diag=,diag) o)] 148 | #; [(== `((,a ,b) ,c) i) 149 | (skio-hist b res) (skio-hist `((,a ,res) ,c) o)] 150 | #; [(== `(,a (,b ,c)) i) 151 | (skio-hist b res) (skio-hist `(,a (,b ,c)) o)] 152 | )]))) 153 | 154 | ;;alternative interpreter, does better at synthesis than evaluation 155 | (define (skio-alt i o) 156 | (fresh (a b resa resb res) 157 | (conde 158 | [(irredexo i) (== i o)] 159 | [(conde 160 | [(io i res) (skio-alt res o)] 161 | [(ko i res) (skio-alt res o)] 162 | [(so i res) (skio-alt res o)] 163 | [(== `(,a ,b) i) (skio-alt a resa) (skio-alt b resb) 164 | (== `(,resa ,resb) res) (=/= i res) (skio-alt res o)] 165 | [(== `(,a ,b) i) (skio-alt a resa) (skio-alt b resb) 166 | (== `(,resa ,resb) res) (== i res) (== i o)] 167 | )]))) 168 | 169 | ;;irreducible expressions for skio-alt 170 | (define (irredexo i) 171 | (fresh (a b) 172 | (conde 173 | [(varo i)] 174 | [(combo i)] 175 | [(== `(K ,a) i) (irredexo a)] 176 | [(== `(S ,a) i) (irredexo a)] 177 | [(== `((S ,a) ,b) i) (irredexo a) (irredexo b)] 178 | ))) 179 | 180 | 181 | --------------------------------------------------------------------------------