Minor progress on Lisp functions
This commit is contained in:
		
							parent
							
								
									37ba03f05e
								
							
						
					
					
						commit
						c3b327f760
					
				
					 8 changed files with 116 additions and 3 deletions
				
			
		
							
								
								
									
										35
									
								
								TEST.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								TEST.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
				
			||||||
 | 
					;; Beowulf  Sysout file generated at 2023-03-29T12:34:39.278
 | 
				
			||||||
 | 
					;; generated by simon
 | 
				
			||||||
 | 
					;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					((NULL
 | 
				
			||||||
 | 
					    LAMBDA (X) (COND ((EQUAL X (QUOTE NIL)) (QUOTE T)) ((QUOTE T) (QUOTE F))))
 | 
				
			||||||
 | 
					  (GCD
 | 
				
			||||||
 | 
					    LAMBDA
 | 
				
			||||||
 | 
					    (X Y)
 | 
				
			||||||
 | 
					    (COND
 | 
				
			||||||
 | 
					      ((GREATERP X Y) (GCD Y X))
 | 
				
			||||||
 | 
					      ((EQUAL (REMAINDER Y X) 0) X) ((QUOTE T) (GCD (REMAINDER Y X) X))))
 | 
				
			||||||
 | 
					  (NIL)
 | 
				
			||||||
 | 
					  (T . T)
 | 
				
			||||||
 | 
					  (F)
 | 
				
			||||||
 | 
					  (ADD1)
 | 
				
			||||||
 | 
					  (APPEND)
 | 
				
			||||||
 | 
					  (APPLY)
 | 
				
			||||||
 | 
					  (ATOM)
 | 
				
			||||||
 | 
					  (CAR)
 | 
				
			||||||
 | 
					  (CDR)
 | 
				
			||||||
 | 
					  (CONS)
 | 
				
			||||||
 | 
					  (DEFINE)
 | 
				
			||||||
 | 
					  (DIFFERENCE)
 | 
				
			||||||
 | 
					  (EQ)
 | 
				
			||||||
 | 
					  (EQUAL)
 | 
				
			||||||
 | 
					  (EVAL)
 | 
				
			||||||
 | 
					  (FIXP)
 | 
				
			||||||
 | 
					  (INTEROP)
 | 
				
			||||||
 | 
					  (NUMBERP)
 | 
				
			||||||
 | 
					  (OBLIST)
 | 
				
			||||||
 | 
					  (PLUS)
 | 
				
			||||||
 | 
					  (PRETTY)
 | 
				
			||||||
 | 
					  (QUOTIENT) (REMAINDER) (RPLACA) (RPLACD) (SET) (SYSIN) (SYSOUT) (TIMES))
 | 
				
			||||||
							
								
								
									
										62
									
								
								doc/mexpr.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								doc/mexpr.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,62 @@
 | 
				
			||||||
 | 
					# M-Expressions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					M-Expressions ('mexprs') are the grammar which John McCarthy origininally used to write Lisp, and the grammar in which many of the function definitions in the [Lisp 1.5 Programmer's Manual](https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf) are stated. However, I have not seen anywhere a claim that Lisp 1.5 could *read* M-Expressions, and it is not clear to me whether it was even planned that it should do so.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Rather, it seems to me probably that M-Expressions were only ever a grammar intended to be written on paper, like [Backus Naur Form](https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form), to describe and to reason about algorithms.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					I set out to make Beowulf read M-Expressions essentially out of curiousity, to see whether it could be done. I had this idea that if it could be done, I could implement most of Lisp 1.5 simply by copying in the M-Expression definitions out of the manual.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Consequently, the Beowulf parser can parse the M-Expression grammar as stated in the manual, and generate S-Expressions from it according to the table specified on page 10 of the manual.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There are two problems with this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Problems with interpreting M-Expressions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Generating idiomatic Lisp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In the M-Expression notation, a lower case character or sequence of characters represents a variable; an upper case character represents a constant. As the manual says,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 2 . The obvious translation of letting a constant translate into itself will not work.
 | 
				
			||||||
 | 
					Since the translation of `x` is `X`, the translation of `X` must be something else to avoid
 | 
				
			||||||
 | 
					ambiguity. The solution is to quote it. Thus `X` is translated into `(QUOTE X)`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Thus, necessarily, the translation of a constant must always be quoted. In practice, key constants in Lisp such as `T` are bound to themselves, so it is idiomatic in Lisp, certainly in the way we have learned to use it, to write, for example,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					(SET (QUOTE NULL) 
 | 
				
			||||||
 | 
					    (QUOTE (LAMBDA (X) 
 | 
				
			||||||
 | 
					        (COND 
 | 
				
			||||||
 | 
					            ((EQUAL X NIL) T) (T F)))))
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					However, the literal translation of
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					null[x] = [x = NIL -> T; T -> F]
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					is
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					(SET (QUOTE NULL) 
 | 
				
			||||||
 | 
					    (QUOTE (LAMBDA (X) 
 | 
				
			||||||
 | 
					        (COND 
 | 
				
			||||||
 | 
					            ((EQUAL X (QUOTE NIL)) (QUOTE T))
 | 
				
			||||||
 | 
					            ((QUOTE T) (QUOTE F))))))
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This is certainly more prolix and more awkward, but it also risks being flat wrong.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Is the value of `NIL` the atom `NIL`, or is it the empty list `()`? If the former, then the translation from the M-Expression above is correct. However, that means that recursive functions which recurse down a list seeking the end will fail. So the latter must be the case.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`NULL` is described thus (Ibid, p11):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> This is a predicate useful for deciding when a list is exhausted. It is true if and only if its argument is `NIL`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					I think there is an ambiguity in referencing constants which are not bound to themselves in the M-Expression notation as given in the manual. This is particularly problematic with regards to `NIL`, but there may be others instances.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Curly braces
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The use of curly braces is not defined in the grammar as stated on page 10. They are not used in the initial definition of `APPLY` on page 13, but they are used in the more developed restatement on page 70. I believe they are to be read as indicating a `DO` statement -- a list of function calls to be made sequentially but without strict functional dependence on one another -- but I don't find the exposition here particularly clear and I'm not sure of this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Consequently, the M-Expression interpreter in Beowulf does not interpret curly braces.
 | 
				
			||||||
| 
						 | 
					@ -1 +0,0 @@
 | 
				
			||||||
(DEFUN COUNT (L) (COND ((EQ '() L) 0) (T (PLUS 1 (COUNT (CDR L))))))
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
gcd[x;y] = [x>y -> gcd[y;x];
 | 
					gcd[x;y] = [x>y -> gcd[y;x];
 | 
				
			||||||
            rem[y;x] = 0 -> x;
 | 
					            rem[y;x] = 0 -> x;
 | 
				
			||||||
            T -> gcd[rem[y;x];x]]
 | 
					            T -> gcd[rem[y;x];x]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;; gcd[x;y] = [x>y -> gcd[y;x]; rem[y;x] = 0 -> x; T -> gcd[rem[y;x];x]]
 | 
				
			||||||
							
								
								
									
										1
									
								
								resources/length.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								resources/length.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					(DEFUN LENGTH (L) (COND ((EQ NIL L) 0) (T (ADD1 (LENGTH (CDR L))))))
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
;; Binding all system functions to NIL so that you can see on the OBLIST that
 | 
					;; Binding all system functions to NIL so that you can see on the OBLIST that
 | 
				
			||||||
;; they exist.
 | 
					;; they exist.
 | 
				
			||||||
(ADD1 . NIL)
 | 
					(ADD1 . NIL)
 | 
				
			||||||
 | 
					(AND . NIL)
 | 
				
			||||||
(APPEND . NIL)
 | 
					(APPEND . NIL)
 | 
				
			||||||
(APPLY . NIL)
 | 
					(APPLY . NIL)
 | 
				
			||||||
(ATOM . NIL)
 | 
					(ATOM . NIL)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@
 | 
				
			||||||
            [clojure.tools.trace :refer [deftrace]]
 | 
					            [clojure.tools.trace :refer [deftrace]]
 | 
				
			||||||
            [beowulf.cons-cell :refer [CAR CDR CONS LIST make-beowulf-list make-cons-cell
 | 
					            [beowulf.cons-cell :refer [CAR CDR CONS LIST make-beowulf-list make-cons-cell
 | 
				
			||||||
                                       pretty-print T F]]
 | 
					                                       pretty-print T F]]
 | 
				
			||||||
            [beowulf.host :refer [ADD1 DIFFERENCE FIXP NUMBERP PLUS QUOTIENT
 | 
					            [beowulf.host :refer [AND ADD1 DIFFERENCE FIXP NUMBERP PLUS QUOTIENT
 | 
				
			||||||
                                  REMAINDER RPLACA RPLACD SUB1 TIMES]]
 | 
					                                  REMAINDER RPLACA RPLACD SUB1 TIMES]]
 | 
				
			||||||
            [beowulf.io :refer [SYSIN SYSOUT]]
 | 
					            [beowulf.io :refer [SYSIN SYSOUT]]
 | 
				
			||||||
            [beowulf.oblist :refer [*options* oblist NIL]]
 | 
					            [beowulf.oblist :refer [*options* oblist NIL]]
 | 
				
			||||||
| 
						 | 
					@ -404,6 +404,7 @@
 | 
				
			||||||
      (APPLY fn args environment)
 | 
					      (APPLY fn args environment)
 | 
				
			||||||
      (case function-symbol ;; there must be a better way of doing this!
 | 
					      (case function-symbol ;; there must be a better way of doing this!
 | 
				
			||||||
        ADD1 (apply ADD1 args)
 | 
					        ADD1 (apply ADD1 args)
 | 
				
			||||||
 | 
					        AND (apply AND args)
 | 
				
			||||||
        APPEND (apply APPEND args)
 | 
					        APPEND (apply APPEND args)
 | 
				
			||||||
        APPLY (apply APPLY args)
 | 
					        APPLY (apply APPLY args)
 | 
				
			||||||
        ATOM (ATOM? (CAR args))
 | 
					        ATOM (ATOM? (CAR args))
 | 
				
			||||||
| 
						 | 
					@ -417,6 +418,7 @@
 | 
				
			||||||
        ;; think about EVAL. Getting the environment right is subtle
 | 
					        ;; think about EVAL. Getting the environment right is subtle
 | 
				
			||||||
        FIXP (apply FIXP args)
 | 
					        FIXP (apply FIXP args)
 | 
				
			||||||
        INTEROP (when (lax? INTEROP) (apply INTEROP args))
 | 
					        INTEROP (when (lax? INTEROP) (apply INTEROP args))
 | 
				
			||||||
 | 
					        LIST (apply LIST args)
 | 
				
			||||||
        NUMBERP (apply NUMBERP args)
 | 
					        NUMBERP (apply NUMBERP args)
 | 
				
			||||||
        OBLIST (OBLIST)
 | 
					        OBLIST (OBLIST)
 | 
				
			||||||
        PLUS (apply PLUS args)
 | 
					        PLUS (apply PLUS args)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,17 @@
 | 
				
			||||||
;; those which can be implemented in Lisp should be, since that aids
 | 
					;; those which can be implemented in Lisp should be, since that aids
 | 
				
			||||||
;; portability.
 | 
					;; portability.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(defn AND 
 | 
				
			||||||
 | 
					  "True if and only if none of my `args` evaluate to either `F` or `NIL`,
 | 
				
			||||||
 | 
					   else `F`.
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   In `beowulf.host` principally because I don't yet feel confident to define
 | 
				
			||||||
 | 
					   varargs functions in Lisp."
 | 
				
			||||||
 | 
					  [& args]
 | 
				
			||||||
 | 
					  (if (empty? (filter #(or (= 'F %) (empty? %)) args))
 | 
				
			||||||
 | 
					    'T
 | 
				
			||||||
 | 
					    'F))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defn RPLACA
 | 
					(defn RPLACA
 | 
				
			||||||
  "Replace the CAR pointer of this `cell` with this `value`. Dangerous, should
 | 
					  "Replace the CAR pointer of this `cell` with this `value`. Dangerous, should
 | 
				
			||||||
  really not exist, but does in Lisp 1.5 (and was important for some
 | 
					  really not exist, but does in Lisp 1.5 (and was important for some
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue