New Lisp functions ASSOC, EFFACE, MAPLIST
This commit is contained in:
parent
41cecdc522
commit
5ee9531e6b
|
@ -1,6 +1,6 @@
|
||||||
# beowulf
|
# beowulf
|
||||||
|
|
||||||
LISP 1.5 is to all Lisp dialects as Beowulf is to Emglish literature.
|
LISP 1.5 is to all Lisp dialects as Beowulf is to English literature.
|
||||||
|
|
||||||
## What this is
|
## What this is
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,11 @@
|
||||||
(APPEND LAMBDA
|
(APPEND LAMBDA
|
||||||
(X Y) (COND ((NULL X) Y) ((QUOTE T) (CONS (CAR X) (APPEND (CDR X) Y)))))
|
(X Y) (COND ((NULL X) Y) ((QUOTE T) (CONS (CAR X) (APPEND (CDR X) Y)))))
|
||||||
(APPLY)
|
(APPLY)
|
||||||
|
(ASSOC LAMBDA (X L)
|
||||||
|
(COND
|
||||||
|
((NULL L) (QUOTE NIL))
|
||||||
|
((AND (CONSP (CAR L)) (EQ (CAAR L) X)) (CDAR L))
|
||||||
|
((QUOTE T) (ASSOC X (CDR L)))))
|
||||||
(ATOM)
|
(ATOM)
|
||||||
(CAR)
|
(CAR)
|
||||||
(CAAAAR LAMBDA (X) (CAR (CAR (CAR (CAR X)))))
|
(CAAAAR LAMBDA (X) (CAR (CAR (CAR (CAR X)))))
|
||||||
|
@ -43,6 +48,7 @@
|
||||||
(CDDR LAMBDA (X) (CDR (CDR X)))
|
(CDDR LAMBDA (X) (CDR (CDR X)))
|
||||||
(CDR)
|
(CDR)
|
||||||
(CONS)
|
(CONS)
|
||||||
|
(CONSP)
|
||||||
(COPY
|
(COPY
|
||||||
LAMBDA
|
LAMBDA
|
||||||
(X)
|
(X)
|
||||||
|
@ -53,6 +59,11 @@
|
||||||
(DIFFERENCE)
|
(DIFFERENCE)
|
||||||
(DIVIDE
|
(DIVIDE
|
||||||
LAMBDA (X Y) (CONS (QUOTIENT X Y) (CONS (REMAINDER X Y) (QUOTE NIL))))
|
LAMBDA (X Y) (CONS (QUOTIENT X Y) (CONS (REMAINDER X Y) (QUOTE NIL))))
|
||||||
|
(DOC)
|
||||||
|
(EFFACE
|
||||||
|
LAMBDA (X L) (COND ((NULL L) (QUOTE NIL))
|
||||||
|
((EQUAL X (CAR L)) (CDR L))
|
||||||
|
((QUOTE T) (RPLACD L (EFFACE X (CDR L))))))
|
||||||
(ERROR)
|
(ERROR)
|
||||||
(EQ)
|
(EQ)
|
||||||
(EQUAL)
|
(EQUAL)
|
||||||
|
@ -78,6 +89,7 @@
|
||||||
((QUOTE T) (INTERSECTION (CDR X) Y))))
|
((QUOTE T) (INTERSECTION (CDR X) Y))))
|
||||||
(LENGTH LAMBDA (L) (COND ((EQ NIL L) 0) (T (ADD1 (LENGTH (CDR L))))))
|
(LENGTH LAMBDA (L) (COND ((EQ NIL L) 0) (T (ADD1 (LENGTH (CDR L))))))
|
||||||
(LESSP)
|
(LESSP)
|
||||||
|
(MAPLIST LAMBDA (L F) (COND ((NULL L) NIL) ((QUOTE T) (CONS (F (CAR L)) (MAPLIST (CDR L) F)))))
|
||||||
(MEMBER
|
(MEMBER
|
||||||
LAMBDA
|
LAMBDA
|
||||||
(A X)
|
(A X)
|
||||||
|
|
7
resources/mexpr/assoc.mexpr.lsp
Normal file
7
resources/mexpr/assoc.mexpr.lsp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
;; Not present in Lisp 1.5(!)
|
||||||
|
|
||||||
|
assoc[x; l] = [null[l] -> NIL;
|
||||||
|
and[consp[car[l]]; eq[caar[l]; x]] -> cdar[l];
|
||||||
|
T -> assoc[x; cdr[l]]]
|
||||||
|
|
||||||
|
;; (ASSOC 'C (PAIR '(A B C D E F) (RANGE 1 6)))
|
6
resources/mexpr/efface.mexpr.lsp
Normal file
6
resources/mexpr/efface.mexpr.lsp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
;; page 63. I'm not at all sure why an implementation using RPLACD is preferred
|
||||||
|
;; over a pure functional implementation here.
|
||||||
|
|
||||||
|
efface[x; l] = [null[l] -> NIL;
|
||||||
|
equal[x; car[l]] -> cdr[l];
|
||||||
|
T -> rplacd[l; efface[x; cdr[l]]]]
|
4
resources/mexpr/maplist.mexpr.lsp
Normal file
4
resources/mexpr/maplist.mexpr.lsp
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
;; page 63
|
||||||
|
|
||||||
|
maplist[l; f] = [null[l] -> nil;
|
||||||
|
T -> cons[f[car[l]]; maplist[cdr[l]; f]]]
|
|
@ -13,7 +13,7 @@
|
||||||
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell
|
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell
|
||||||
pretty-print T F]]
|
pretty-print T F]]
|
||||||
[beowulf.host :refer [ADD1 AND ASSOC ATOM ATOM? CAR CDR CONS DEFINE
|
[beowulf.host :refer [ADD1 AND ASSOC ATOM ATOM? CAR CDR CONS DEFINE
|
||||||
DIFFERENCE EQ EQUAL ERROR FIXP GENSYM
|
DIFFERENCE DOC EQ EQUAL ERROR FIXP GENSYM
|
||||||
GREATERP lax? LESSP LIST NUMBERP OBLIST
|
GREATERP lax? LESSP LIST NUMBERP OBLIST
|
||||||
PAIRLIS PLUS QUOTIENT REMAINDER RPLACA RPLACD SET
|
PAIRLIS PLUS QUOTIENT REMAINDER RPLACA RPLACD SET
|
||||||
TIMES TRACE traced? UNTRACE]]
|
TIMES TRACE traced? UNTRACE]]
|
||||||
|
@ -256,6 +256,7 @@
|
||||||
CONS (safe-apply CONS args)
|
CONS (safe-apply CONS args)
|
||||||
DEFINE (DEFINE (CAR args))
|
DEFINE (DEFINE (CAR args))
|
||||||
DIFFERENCE (DIFFERENCE (CAR args) (CADR args))
|
DIFFERENCE (DIFFERENCE (CAR args) (CADR args))
|
||||||
|
DOC (DOC (first args))
|
||||||
EQ (safe-apply EQ args)
|
EQ (safe-apply EQ args)
|
||||||
EQUAL (safe-apply EQUAL args)
|
EQUAL (safe-apply EQUAL args)
|
||||||
ERROR (safe-apply ERROR args)
|
ERROR (safe-apply ERROR args)
|
||||||
|
|
|
@ -118,5 +118,7 @@
|
||||||
(case (:cause data)
|
(case (:cause data)
|
||||||
:quit nil
|
:quit nil
|
||||||
;; default
|
;; default
|
||||||
(pprint data))
|
(do
|
||||||
|
(println "ERROR: " (.getMessage e))
|
||||||
|
(pprint data)))
|
||||||
(println e))))))))
|
(println e))))))))
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
NOTE: this is *very* hacky. You almost certainly do not want to
|
NOTE: this is *very* hacky. You almost certainly do not want to
|
||||||
use this!"
|
use this!"
|
||||||
(:require [beowulf.io :refer [default-sysout SYSIN]]
|
(:require ;; [beowulf.io :refer [default-sysout SYSIN]]
|
||||||
[beowulf.host :refer [ASSOC]]
|
[beowulf.manual :refer [format-page-references index
|
||||||
[beowulf.manual :refer [format-page-references index *manual-url*]]
|
*manual-url* page-url]]
|
||||||
[beowulf.oblist :refer [NIL oblist]]
|
[beowulf.oblist :refer [NIL oblist]]
|
||||||
[clojure.java.browse :refer [browse-url]]
|
[clojure.java.browse :refer [browse-url]]
|
||||||
[clojure.string :refer [join replace upper-case]]))
|
[clojure.string :refer [join replace upper-case]]))
|
||||||
|
@ -31,8 +31,10 @@
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(def host-functions
|
(def host-functions
|
||||||
"Functions which we can infer are written in Clojure."
|
"Functions which we can infer are written in Clojure. We need to collect these
|
||||||
(reduce
|
at run-time, not compile time, hence memoised function, not variable."
|
||||||
|
(memoize
|
||||||
|
(fn [] (reduce
|
||||||
merge
|
merge
|
||||||
{}
|
{}
|
||||||
(map
|
(map
|
||||||
|
@ -40,7 +42,7 @@
|
||||||
['beowulf.bootstrap
|
['beowulf.bootstrap
|
||||||
'beowulf.host
|
'beowulf.host
|
||||||
'beowulf.io
|
'beowulf.io
|
||||||
'beowulf.read])))
|
'beowulf.read])))))
|
||||||
|
|
||||||
;; OK, this, improbably, works. There's probably a better way...
|
;; OK, this, improbably, works. There's probably a better way...
|
||||||
;; (:doc (meta (eval (read-string (str "#'" "beowulf.read" "/" "READ")))))
|
;; (:doc (meta (eval (read-string (str "#'" "beowulf.read" "/" "READ")))))
|
||||||
|
@ -60,7 +62,7 @@
|
||||||
|
|
||||||
|
|
||||||
(defn- get-metadata-for-entry [entry key]
|
(defn- get-metadata-for-entry [entry key]
|
||||||
(let [fn (host-functions (symbol (first entry)))]
|
(let [fn ((host-functions) (symbol (first entry)))]
|
||||||
(get-metadata-for-function fn key)))
|
(get-metadata-for-function fn key)))
|
||||||
|
|
||||||
(defn infer-type
|
(defn infer-type
|
||||||
|
@ -70,7 +72,7 @@
|
||||||
(cond
|
(cond
|
||||||
(= (second entry) 'LAMBDA) "Lisp function"
|
(= (second entry) 'LAMBDA) "Lisp function"
|
||||||
(= (second entry) 'LABEL) "Labeled form"
|
(= (second entry) 'LABEL) "Labeled form"
|
||||||
(host-functions (first entry)) (if (fn? (eval (symbol (host-functions (first entry)))))
|
((host-functions) (first entry)) (if (fn? (eval (symbol ((host-functions) (first entry)))))
|
||||||
"Host function"
|
"Host function"
|
||||||
"Host variable")
|
"Host variable")
|
||||||
:else "Lisp variable"))
|
:else "Lisp variable"))
|
||||||
|
@ -118,12 +120,12 @@
|
||||||
|
|
||||||
(defn gen-doc-table
|
(defn gen-doc-table
|
||||||
([]
|
([]
|
||||||
(gen-doc-table default-sysout))
|
;; (gen-doc-table default-sysout))
|
||||||
([sysfile]
|
;; ([sysfile]
|
||||||
(when (= NIL @oblist)
|
;; (when (= NIL @oblist)
|
||||||
(try (SYSIN sysfile)
|
;; (try (SYSIN sysfile)
|
||||||
(catch Throwable any
|
;; (catch Throwable any
|
||||||
(println (.getMessage any) " while reading " sysfile))))
|
;; (println (.getMessage any) " while reading " sysfile))))
|
||||||
(join
|
(join
|
||||||
"\n"
|
"\n"
|
||||||
(doall
|
(doall
|
||||||
|
@ -151,3 +153,18 @@
|
||||||
(list "## Index"
|
(list "## Index"
|
||||||
""
|
""
|
||||||
(gen-doc-table)))))))))
|
(gen-doc-table)))))))))
|
||||||
|
|
||||||
|
(defn open-doc
|
||||||
|
"Open the documentation page for this `symbol`, if known, in the default
|
||||||
|
web browser."
|
||||||
|
[symbol]
|
||||||
|
(let [doc (get-metadata-for-function symbol :doc)]
|
||||||
|
(if-let [pages (:page-nos (index (keyword symbol)))]
|
||||||
|
(browse-url (page-url (first pages)))
|
||||||
|
(if doc
|
||||||
|
(println doc)
|
||||||
|
(throw (ex-info "No documentation found"
|
||||||
|
{:phase :host
|
||||||
|
:function 'DOC
|
||||||
|
:args (list symbol)
|
||||||
|
:type :beowulf}))))))
|
|
@ -6,6 +6,7 @@
|
||||||
[beowulf.cons-cell :refer [F make-cons-cell make-beowulf-list
|
[beowulf.cons-cell :refer [F make-cons-cell make-beowulf-list
|
||||||
pretty-print T]]
|
pretty-print T]]
|
||||||
;; note hyphen - this is Clojure...
|
;; note hyphen - this is Clojure...
|
||||||
|
[beowulf.gendoc :refer [open-doc]]
|
||||||
[beowulf.oblist :refer [*options* oblist NIL]])
|
[beowulf.oblist :refer [*options* oblist NIL]])
|
||||||
(:import [beowulf.cons_cell ConsCell]
|
(:import [beowulf.cons_cell ConsCell]
|
||||||
;; note underscore - same namespace, but Java.
|
;; note underscore - same namespace, but Java.
|
||||||
|
@ -268,8 +269,8 @@
|
||||||
;; TODO: These are candidates for moving to Lisp urgently!
|
;; TODO: These are candidates for moving to Lisp urgently!
|
||||||
|
|
||||||
(defn ASSOC
|
(defn ASSOC
|
||||||
"If a is an association list such as the one formed by PAIRLIS in the above
|
"If `a` is an association list such as the one formed by PAIRLIS in the above
|
||||||
example, then assoc will produce the first pair whose first term is x. Thus
|
example, then assoc will produce the first pair whose first term is `x`. Thus
|
||||||
it is a table searching function.
|
it is a table searching function.
|
||||||
|
|
||||||
All args are assumed to be `beowulf.cons-cell/ConsCell` objects.
|
All args are assumed to be `beowulf.cons-cell/ConsCell` objects.
|
||||||
|
@ -478,3 +479,24 @@
|
||||||
[s]
|
[s]
|
||||||
(when (symbol? s)
|
(when (symbol? s)
|
||||||
(swap! traced-symbols #(set (remove (fn [x] (= s x)) %)))))
|
(swap! traced-symbols #(set (remove (fn [x] (= s x)) %)))))
|
||||||
|
|
||||||
|
;;;; Extensions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(defn DOC
|
||||||
|
"Open the page for this `symbol` in the Lisp 1.5 manual, if known, in the
|
||||||
|
default web browser.
|
||||||
|
|
||||||
|
**NOTE THAT** this is an extension function, not available in strct mode."
|
||||||
|
[symbol]
|
||||||
|
(when (lax? 'DOC)
|
||||||
|
(open-doc symbol)))
|
||||||
|
|
||||||
|
(defn CONSP
|
||||||
|
"Return `T` if object `o` is a cons cell, else `F`.
|
||||||
|
|
||||||
|
**NOTE THAT** this is an extension function, not available in strct mode.
|
||||||
|
I believe that Lisp 1.5 did not have any mechanism for testing whether an
|
||||||
|
argument was, or was not, a cons cell."
|
||||||
|
[o]
|
||||||
|
(when (lax? 'CONSP)
|
||||||
|
(if (instance? o ConsCell) 'T 'F)))
|
|
@ -63,7 +63,9 @@
|
||||||
"Dump the current content of the object list to file. If no `filepath` is
|
"Dump the current content of the object list to file. If no `filepath` is
|
||||||
specified, a file name will be constructed of the symbol `Sysout` and
|
specified, a file name will be constructed of the symbol `Sysout` and
|
||||||
the current date. File paths will be considered relative to the filepath
|
the current date. File paths will be considered relative to the filepath
|
||||||
set when starting Lisp."
|
set when starting Lisp.
|
||||||
|
|
||||||
|
**NOTE THAT** this is an extension function, not available in strct mode."
|
||||||
([]
|
([]
|
||||||
(SYSOUT nil))
|
(SYSOUT nil))
|
||||||
([filepath]
|
([filepath]
|
||||||
|
@ -92,7 +94,9 @@
|
||||||
|
|
||||||
**NOTE THAT** if the provided `filename` does not end with `.lsp` (which,
|
**NOTE THAT** if the provided `filename` does not end with `.lsp` (which,
|
||||||
if you're writing it from the Lisp REPL, it won't), the extension `.lsp`
|
if you're writing it from the Lisp REPL, it won't), the extension `.lsp`
|
||||||
will be appended."
|
will be appended.
|
||||||
|
|
||||||
|
**NOTE THAT** this is an extension function, not available in strct mode."
|
||||||
([]
|
([]
|
||||||
(SYSIN (or (:read *options*) default-sysout)))
|
(SYSIN (or (:read *options*) default-sysout)))
|
||||||
([filename]
|
([filename]
|
||||||
|
|
Loading…
Reference in a new issue