1 ;;;_ Prolog file for Klink implementation of Kernel.
3 ;;;_ , Credits and License
4 ;; Copyright (C) 2011 Tom Breton (Tehom)
6 ;; Author: Tom Breton (Tehom) <tehom@panix.com>
8 ;; This file is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; This file is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GNU Emacs; see the file COPYING. If not, write to
20 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ;; Boston, MA 02111-1307, USA.
23 ;;;_. Preliminary setup
25 (eval 'into module-parameters))
27 ($define! $define-in-gnd!
28 ($vau/3 (definiendum definition) env
29 (eval (list $set! env-into definiendum definition) env)))
31 ($define! null?/1 (wrap null?/o1))
32 ($define! zero?/1 (wrap zero?/o1))
38 ($define-in-gnd! $sequence
41 (cons (listloop listloop-style-sequence args) #inert)
45 ($vau/3 (formals eformal . body) env
47 (list $vau/3 formals eformal
48 (cons $sequence body))
51 ($define-in-gnd! $lambda
52 ($vau/3 (formals . body) env
53 (wrap (eval (list $vau/3 formals #ignore (cons $sequence body))
55 ;;;_ , Loading modules
57 ;;;_ , get-module-from-port
58 ($define-in-gnd! get-module
59 ($lambda (filename . rest)
60 (apply get-module-from-port
62 (open-input-file filename)
66 ($define-in-gnd! caar ($lambda (x) (car (car x))))
67 ($define-in-gnd! cadr ($lambda (x) (car (cdr x))))
68 ($define-in-gnd! cdar ($lambda (x) (cdr (car x))))
69 ($define-in-gnd! cddr ($lambda (x) (cdr (cdr x))))
70 ($define-in-gnd! caaar ($lambda (x) (car (car (car x)))))
71 ($define-in-gnd! caadr ($lambda (x) (car (car (cdr x)))))
72 ($define-in-gnd! cadar ($lambda (x) (car (cdr (car x)))))
73 ($define-in-gnd! caddr ($lambda (x) (car (cdr (cdr x)))))
74 ($define-in-gnd! cdaar ($lambda (x) (cdr (car (car x)))))
75 ($define-in-gnd! cdadr ($lambda (x) (cdr (car (cdr x)))))
76 ($define-in-gnd! cddar ($lambda (x) (cdr (cdr (car x)))))
77 ($define-in-gnd! cdddr ($lambda (x) (cdr (cdr (cdr x)))))
78 ($define-in-gnd! caaaar ($lambda (x) (car (car (car (car x))))))
79 ($define-in-gnd! caaadr ($lambda (x) (car (car (car (cdr x))))))
80 ($define-in-gnd! caadar ($lambda (x) (car (car (cdr (car x))))))
81 ($define-in-gnd! caaddr ($lambda (x) (car (car (cdr (cdr x))))))
82 ($define-in-gnd! cadaar ($lambda (x) (car (cdr (car (car x))))))
83 ($define-in-gnd! cadadr ($lambda (x) (car (cdr (car (cdr x))))))
84 ($define-in-gnd! caddar ($lambda (x) (car (cdr (cdr (car x))))))
85 ($define-in-gnd! cadddr ($lambda (x) (car (cdr (cdr (cdr x))))))
86 ($define-in-gnd! cdaaar ($lambda (x) (cdr (car (car (car x))))))
87 ($define-in-gnd! cdaadr ($lambda (x) (cdr (car (car (cdr x))))))
88 ($define-in-gnd! cdadar ($lambda (x) (cdr (car (cdr (car x))))))
89 ($define-in-gnd! cdaddr ($lambda (x) (cdr (car (cdr (cdr x))))))
90 ($define-in-gnd! cddaar ($lambda (x) (cdr (cdr (car (car x))))))
91 ($define-in-gnd! cddadr ($lambda (x) (cdr (cdr (car (cdr x))))))
92 ($define-in-gnd! cdddar ($lambda (x) (cdr (cdr (cdr (car x))))))
93 ($define-in-gnd! cddddr ($lambda (x) (cdr (cdr (cdr (cdr x))))))
95 ;;$$FIX ME This is just equal?/2, have to use compare-neighbors to
97 ($define-in-gnd! equal?/2
102 (equal?/2 (car x) (car y))
103 (equal?/2 (cdr x) (cdr y))))
107 ;; ($and (vector? y) (vector-equal? x y)))
109 (equal?/2-atom-atom x y)))))
112 ;;;_ , Re-dispatchers
115 ($define-in-gnd! apply
116 ($lambda (appv arg . opt)
117 (eval (cons (unwrap appv) arg)
122 ;;;_ , Multiple application on single list
123 ;;;_ . apply-counted-to-1-list
124 ($define-in-gnd! apply-counted-to-1-list
125 ($lambda (counted-proc proc ls)
126 ;;An unrolled $let. Can't use real $let because $let wants to
128 (($lambda ((num-pairs #ignore #ignore cycle-len))
129 (($lambda (any-infinite?)
131 (error "Infinite lists not yet supported")
133 (list num-pairs 1 proc (list ls)))))
134 (not? (zero?/1 cycle-len))))
135 (get-list-metrics ls))))
138 ;;;_ , counted-every?/4
139 ;;Just initializes the accumulator.
140 ($define-in-gnd! counted-every?/4
141 ($lambda (count len app lol)
142 (counted-every?/5 #t count len (unwrap app) lol)))
145 ($define-in-gnd! and?
152 ;;;_ , counted-some?/4
153 ($define-in-gnd! counted-some?/4
154 ($lambda (count len app lol)
155 (counted-some?/5 #f count len (unwrap app) lol)))
167 ($define-in-gnd! counted-map/4
168 ($lambda (count len app lol)
169 (counted-map/5 '() count len (unwrap app) lol)))
172 ;;$$TRANSITIONAL In ground so we can test it.
173 ;;A case of map, spelled out because the definition of map uses it.
174 ($define-in-gnd! map1
176 (apply-counted-to-1-list counted-map/4 proc ls)))
180 ($define-in-gnd! $let
181 ($vau (bindings . body) env
182 (eval (cons (list* $lambda (map1 car bindings) body)
183 (map1 cadr bindings))
186 ;;$$IMPROVE ME Expand the null cases.
187 ($define-in-gnd! $let*
188 ($vau (bindings . body) env
189 (eval ($if (null?/1 bindings)
190 (list* $let bindings body)
192 (list (car bindings))
193 (list* $let* (cdr bindings) body)))
196 ($define-in-gnd! $letrec
197 ($vau (bindings . body) env
201 (list* list (map1 cadr bindings)))
205 ($define-in-gnd! $letrec*
206 ($vau (bindings . body) env
207 (eval ($if (null?/1 bindings)
208 (list* $letrec bindings body)
210 (list (car bindings))
211 (list* $letrec* (cdr bindings) body)))
214 ($define-in-gnd! $let-redirect
215 ($vau (exp bindings . body) env
216 (eval (list* (eval (list* $lambda (map1 car bindings) body)
219 (map1 cadr bindings))
222 ($define-in-gnd! $let-safe
223 ($vau (bindings . body) env
224 (eval (list* $let-redirect
225 (make-kernel-standard-environment)
231 ($define-in-gnd! $let/cc
232 ($vau (symbol . body) env
233 (eval (list call/cc (list* $lambda (list symbol) body))
236 ($define-in-gnd! $define/cc!
239 ((wrap $set!) e s c))))
241 ($define-in-gnd! $provide!
242 ($vau (symbols . body) env
243 (eval (list $define! symbols
245 (list* $sequence body)
246 (list* list symbols)))
249 ($define-in-gnd! $import!
250 ($vau (exp . symbols) env
257 ($define-in-gnd! $binds?
258 ($vau (exp . sym-list) dynamic
259 ($let ((env (eval exp dynamic)))
260 ;;$$IMPROVE ME Make it donut-safe
264 (list $binds?/2 env sym)
268 ($define-in-gnd! $remote-eval
270 (eval o (eval e d))))
272 ($define-in-gnd! $let-redirect
273 ($vau (exp bindings . body) env
274 (eval (list* (eval (list* $lambda (map1 car bindings) body)
277 (map1 cadr bindings))
280 ($define-in-gnd! $let-safe
281 ($vau (bindings . body) env
282 (eval (list* $let-redirect
283 (make-kernel-standard-environment)
288 ($define-in-gnd! $bindings->environment
290 (eval (list $let-redirect
293 (list get-current-environment))
298 ($define-in-gnd! apply-continuation
300 (apply (continuation->applicative c) o)))
302 ;;NB, root-continuation is not available here in the prolog because
303 ;;loading the prolog has a separate root from the REPL loop.
305 ;;;_ , Type/destructure combiners
308 ;;NOT ready for general use; unsafe because there's a hidden
309 ;;requirement on the args that they (a) convert to xary internally,
310 ;;and (b) not internally call Kernel, neither of which should be
311 ;;determinable by Kernel code. So this is just a specialization of
312 ;;some yet-to-be-written combiner that handles the general case.
314 ;;$$TRANSITIONAL These are exposed for testing, until we have a means
315 ;;of exposing them for testing without exposing them in general.
316 ;;Later we may wrap this up so that only `listtype' and
317 ;;`destructure-list' are exposed, and possibly `combiner->trivpred'
318 ;;and a trivpred->pred combiner are exposed in unsafe,
319 ;;;_ . pred-trivpred-alist
320 ($define! pred-trivpred-alist
322 (list 'applicative? applicative?/o1)
323 (list 'boolean? boolean?/o1)
324 (list 'character? character?/o1)
325 (list 'combiner? combiner?/o1)
326 (list 'continuation? continuation?/o1)
327 (list 'countable-list? countable-list?/o1)
328 (list 'environment? environment?/o1)
329 (list 'finite-list? finite-list?/o1)
330 (list 'ignore? ignore?/o1)
331 (list 'inert? inert?/o1)
332 (list 'input-port? input-port?/o1)
333 (list 'integer? integer?/o1)
334 (list 'null? null?/o1)
335 (list 'number? number?/o1)
336 (list 'operative? operative?/o1)
337 (list 'output-port? output-port?/o1)
338 (list 'pair? pair?/o1)
339 (list 'port? port?/o1)
340 (list 'posint? posint?/o1)
341 (list 'promise? promise?/o1)
342 (list 'real? real?/o1)
343 (list 'recur-tracker? recur-tracker?/o1)
344 (list 'recurrence-table? recurrence-table?/o1)
345 (list 'string? string?/o1)
346 (list 'symbol? symbol?/o1)
347 (list 'zero? zero?/o1)
349 ;;These don't belong in ground.
350 (list 'trivpred? trivpred?/o1)
351 (list 'vector? vector?/o1)
353 ;;;_ . The environment of them
354 ($define-in-gnd! pred-trivpred-env
355 (eval (list* $bindings->environment pred-trivpred-alist)))
356 ;;;_ . trivpred->pred
357 ($define-in-gnd! trivpred->pred
360 (every? (wrap trivpred) x))))
363 ($define-in-gnd! $define-pred!
364 ($vau ((sym trivpred)) env
366 (list $define-in-gnd! sym (trivpred->pred trivpred)))))
368 ;;;_ . Define `every?' versions of each
369 ;;$$IMPROVE ME This should be for-each1
370 (map1 (wrap $define-pred!) pred-trivpred-alist)
371 ;;;_ . combiner->trivpred
372 ;;$$TRANSITIONAL For now, this assumes `env-into' is where all
373 ;;relevant bindings are found. Later we may pursue a wholly different
375 ;;Returns (#t Object) or (#f Original)
376 ($define-in-gnd! combiner->trivpred
378 ($if (trivpred? comb)
381 ($define! (found? . obj) (cons #f comb))
382 ($if (reverse-binds?/2 comb env-into)
383 ($define! (found? . obj)
384 ($let ((sym (reverse-lookup comb env-into)))
386 (find-binding pred-trivpred-env sym)
392 ;;Retry it, unwrapped once.
393 (combiner->trivpred (unwrap comb))
394 (cons found? obj))))))
395 ;;;_ . type-arg->low-type-arg
396 ($define-in-gnd! type-arg->low-type-arg
398 ($define! (found? . obj)
400 (find-binding typecheck-special-syms arg)
401 (combiner->trivpred arg)))
405 ($define-in-gnd! listtype
407 ;;$$IMPROVE ME Check that they were all converted.
408 ;;$$IMPROVE ME If they weren't, make a more general listtype checker.
411 ;;This makes them into trivpreds OR special keys.
412 (map1 type-arg->low-type-arg args)))
413 (apply listtype/N-trivpred real-args))))
415 ;;;_ . destructure-list
416 ;;NOT ready for general use, same reason.
417 ($define-in-gnd! destructure-list
421 ;;This makes them into trivpreds OR special keys.
422 (map1 type-arg->low-type-arg args)))
423 (apply destructure-list/N-trivpred real-args))))
424 ;;;_ . make-encapsulation-type
425 ($define-in-gnd! make-encapsulation-type
427 ($let (((e p?/o1 d) (make-encapsulation-type/raw)))
428 (list e (trivpred->pred p?/o1) d))))
431 ($define-in-gnd! $cond
433 ($if (null?/1 clauses)
435 ($let ((((test . body) . clauses) clauses))
437 (apply (wrap $sequence) body env)
438 (apply (wrap $cond) clauses env))))))
440 ;;$$TRANSITIONAL John's tests want error-descriptor? but it's not
441 ;;defined, so temporarily set it to always false.
442 ($define-in-gnd! error-descriptor? ($lambda #ignore #f))
444 ;;;_ , Arithmetic initial redefines
446 ($define-in-gnd! =? equal?/2-num-num)
448 ;;;_ , List functions
450 ;;$$TRANSITIONAL This will be done in C.
451 ($define-in-gnd! list-tail
454 (list-tail (cdr ls) (sub k 1))
458 ;;$$MAKE ME SAFER Check that there are at least k1+k2 pairs.
459 ($define-in-gnd! encycle!
462 (set-cdr! (list-tail ls (add k1 (add k2 -1)))
465 ;;;_ . list-neighbors-aux
466 ($define-in-gnd! list-neighbors-aux
468 ;; get n sets of neighbors from ls
473 (cons (listloop listloop-style-neighbors ls n) '())))))
474 ($let* (((p #ignore a c) (get-list-metrics ls))
476 ($if (=? c 0) (- a 1) p)))
478 (aux ls len) len a c))))
481 ;;;_ . list-neighbors-linear
482 ($define-in-gnd! list-neighbors-linear
485 (((neighbors . #ignore) (list-neighbors-aux ls)))
487 ;;;_ . list-neighbors
488 ($define-in-gnd! list-neighbors
491 (((neighbors #ignore a c) (list-neighbors-aux ls)))
492 (encycle! neighbors a c)
495 ;;;_ . compare-neighbors
496 ($define-in-gnd! compare-neighbors
497 ($lambda (op comparands)
499 (((neighbors len . #ignore) (list-neighbors-aux comparands)))
502 ;;counted-every?/5 gives these elements as the first arg,
503 ;;so convert binary op to unary.
508 ($define-in-gnd! equal?
510 (apply compare-neighbors (list equal?/2 args))))
514 ($define-in-gnd! reduce
516 ;;$$TRANSITIONAL This part will be done in C.
517 ($define! reduce-acyclic
519 ($cond ((null?/1 ls) id)
520 ((null?/1 (cdr ls)) (car ls))
523 (reduce-acyclic (cdr ls) bin id))))))
524 ;;$$MOVE ME This counted part is the heart of it, belongs in C,
525 ;;and should take id, which is useful.
531 (reduce-n (cdr ls) bin (sub n 1))))))
532 (wrap ($vau (ls bin id . opt) env
533 ;;Proc to fix the environment that `bin', `pre', `in',
537 ($lambda x (apply appv x env))))
538 ($define! bin (fixenv bin))
539 ($let (((p n a c) (get-list-metrics ls)))
541 (reduce-acyclic ls bin id)
543 ($define! (pre in post) (map1 fixenv opt))
544 ($define! reduced-cycle
545 (post (reduce-n (map1 pre (list-tail ls a))
550 (bin (reduce-n ls bin a)
551 reduced-cycle)))))))))
553 ;;;_ , Arithmetic n-ary defines
555 ($lambda x (reduce x add 0)))
558 ($lambda x (reduce x mul 1)))
561 ($lambda (minuend . subtrahends)
564 (error "`-' with no subtrahends is deliberately not supplied")
565 (sub minuend (apply + subtrahends)))))
568 ($lambda (dividend . divisors)
571 (error "`/' with no divisors is deliberately not supplied")
572 (div dividend (apply * divisors)))))
578 (compare-neighbors >?/2 comparands)))
583 ($lambda (a b) (>?/2 b a))
589 ($lambda (a b) (not? (>?/2 a b)))
595 ($lambda (a b) (not? (>?/2 b a)))
598 ;;;_ . Multiple application on multiple lists
599 ;;;_ , apply-counted-proc
600 ;;$$IMPROVE ME Make `proc' execute in external dynamic environment.
601 ($define-in-gnd! apply-counted-proc
602 ($lambda (counted-proc proc lists)
605 ((pairs-in-top . #ignore) (get-list-metrics lists))
606 ;;If `lists' is cyclic, we'll surround `proc' with
607 ;;something that encycles what it gets.
608 (metrics (map1 get-list-metrics lists))
611 ($lambda ((#ignore #ignore #ignore cycle)) cycle)
616 pairs-in-top 1 zero?/1 (list all-cycles))))
617 ;;Test for same-length.
620 ($lambda ((pairs . #ignore)) pairs)
623 (error "Infinite lists not yet supported")
624 ($if (apply equal? num-pairs-list)
625 ;;$$IMPROVE ME Do this in a given environment.
631 (error "Lists are mixed-length"))))))
635 ($define-in-gnd! every?
636 ($lambda (proc . lists)
643 ($define-in-gnd! some?
644 ($lambda (proc . lists)
653 ($lambda (proc . lists)
654 (apply-counted-proc counted-map/4 proc lists)))
657 ($define-in-gnd! for-each