Custom '+' (sum) function in lisp - lisp

I was reading Roots of Lisp by Paul Graham where he claims that any lisp functionality can be build with the combination of this 7 base functions: quote, atom, eq, cond, cons, car, cdr.
Question: are Lisp dialects really based solely on those functions? How can we define a 'sum' or 'plus' function using the aforementioned 7 primitive functions? e.g. Our own (+ 1 2) function
Note: I'm totally newbie to Lisp but I'm also starting to get very excited about the language. The purpose of this question is purely genuine interest

The author refers to a very famous paper written in 1960 by the Turing Award and Lisp inventor John McCarthy “Recursive Functions of Symbolic Expressions and Their Computation by Machine”, in which he defined the semantics of Lisp as a new computational formalism, equivalent in power to the Turing Machine.
In the paper (and in the Lisp 1.5 Manual) McCarthy described the interpreter for the language, that can be completely written by using only the seven primitive functions mentioned by Graham.
The language was devoted primarily to symbolic computations, and the interpreter presented in the papers concerned only those computations, without resorting to numbers or other data types different from atoms and pairs.
As Graham says in a note at page 11 of Root of Lisp, “It is possible to do arithmetic in McCarthy's 1960 Lisp by using e.g. a list of n atoms to represent the number n”, so performing a sum is simply equivalent to appending two lists.
Of course this way of doing is very inefficient: it is presented only to show the equivalence with other computational formalisms, and in the real interpreters/compilers integers are represented as usual, and have the usual operators.

as far as i remember, there was also an approach to do this using list nesting level (don't really remember, where). Starting from () as zero, (()) == 1 and so on. Then you can simply define inc as list and dec as car:
CL-USER> (defun zero? (x) (eq () x))
ZERO?
CL-USER> (zero? nil)
T
CL-USER> (zero? 1)
NIL
CL-USER> (defparameter *zero* ())
*ZERO*
CL-USER> (defun inc (x) (list x))
INC
CL-USER> (defun dec (x) (car x))
DEC
CL-USER> (defun plus (x y)
(if (zero? y) x (plus (inc x) (dec y))))
PLUS
CL-USER> (plus *zero* (inc (inc *zero*)))
((NIL))
CL-USER> (defparameter *one* (inc *zero*))
*ONE*
CL-USER> (defparameter *two* (inc *one*))
*TWO*
CL-USER> (defparameter *three* (inc *two*))
*THREE*
CL-USER> (plus *two* *three*)
(((((NIL)))))
CL-USER> (equal *two* (dec (dec (dec (plus *two* *three*)))))
T

TL; DR: No. Modern lisp systems have many more primitives than the first lisp and a new primitives are needed for each new primitive data type.
The first Lisp didn't have numbers but it was turing complete. That means it can do any computation that is possible in any other language, but it doesn't mean it would be practical to do so. Number were not hard to mimic, but calculations were slow. There are rumers today about slow arithmetic dating back pre Lisp 1.5.
When I made my first lisp interpreter I couldn't care much for numbers. It's not really an interesting aspect of an interpreter. I did however implement fibonacci as an example and this is how it looks like:
;; This is NOT Common Lisp code. It's Zozotez
(setq + (lambda (x y)
(if x (cons (car x)
(+ (cdr x) y))
y)))
(setq - (lambda (z w)
(if w (- (cdr z)
(cdr w))
z)))
(setq fibonacci
(lambda (n a1 a2)
(if n
(fibonacci (- n '(1))
a2
(+ a2 a1))
a1)))
(fibonacci '(1 1 1 1 1 1 1 1 1) () '(1))
; ==> (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
No numbers! (1 in my language is a symbol so it needs to be quoted or else it will be evaluated like a variable)
As alternative number system I have implemented a positional system, pretty much like how we write numbers with the same rules for adding/multiplying etc. Perhaps a tad faster than lits of length n but more complex to make.
If the Lisp has closures you can do church numerals. Using the same as lambda calculus you can compute anything with just closures. You only need one primitive, lambda. (Again, not the easiest to work with)

Related

Macro expanding to same operator

Many Lisp-family languages have a little bit of syntax sugar for things like addition or comparison allowing more than two operands, if optionally omitting the alternate branch etc. There would be something to be said for implementing these with macros, that would expand (+ a b c) to (+ a (+ b c)) etc; this would make the actual runtime code cleaner, simpler and slightly faster (because the logic to check for extra arguments would not have to run every time you add a pair of numbers).
However, the usual macro expansion algorithm is 'keep expanding the outermost form over and over until you get a non-macro result'. So that means e.g. + had better not be a macro that expands to +, even a reduced version, or you get an infinite loop.
Is there any existing Lisp that solves this problem at macro expansion time? If so, how does it do it?
Common Lisp provides compiler macros.
These can be used for such optimizations. A compiler macro can conditionally decline to provide an expansion by just returning the form itself.
This is an addendum to Rainer's answer: this answer really just gives some examples.
First of all compiling things like arithmetic operations is a hairy business because you there's a particular incentive to try and turn as much as possible into the operations the machine understands and failing to do that can result in enormous slowdowns in numerically intensive code. So typically the compiler has a lot of knowledge of how to compile things, and it is also allowed a lot of freedom: for instance in CL (+ a 2 b 3) can be turned by the compiler into
(+ 5 a b): the compiler is allowed to reorder & coalesce things (but not to change the evaluation order: it can turn (+ (f a) (g b)) into something like (let ((ta (f a)) (tb (g b))) (+ tb ta)) but not into (+ (g b) (f a))).
So arithmetic is usually pretty magic. But it's still interesting to look at how you can do this with macros and why you need compiler macros in CL.
(Note: all of the below macros below are things I wrote without much thought: they may be semantically wrong.)
Macros: the wrong answer
So, addition, in CL. One obvious trick is to have a 'primitive-two-arg' function (which presumably the compiler can inline into assembly in good cases), and then to have the public interface be a macro which expands into that.
So, here is that
(defun plus/2 (a b)
;; just link to the underlying CL arithmetic
(+ a b))
And you can then write the general function in terms of that in the obvious way:
(defun plus/many (a &rest bcd)
(if (null bcd)
a
(reduce #'plus/2 bcd :initial-value a)))
And now you can write the public interface, plus as a macro on top of this:
(defmacro plus (a &rest bcd)
(cond ((null bcd)
a)
((null (rest bcd))
`(plus/2 ,a ,(first bcd)))
(t
`(plus/2 (plus/2 ,a ,(first bcd))
(plus ,#(rest bcd))))))
And you can see that
(plus a b) expands to (plus/2 a b)'
(plus a b c) expands to (plus/2 (plus/2 a b) (plus c)) and thence to (plus/2 (plus/2 a b) c).
And we can do better than this:
(defmacro plus (a &rest bcd)
(multiple-value-bind (numbers others) (loop for thing in (cons a bcd)
if (numberp thing)
collect thing into numbers
else collect thing into things
finally (return (values numbers things)))
(cond ((null others)
(reduce #'plus/2 numbers :initial-value 0))
((null (rest others))
`(plus/2 ,(reduce #'plus/2 numbers :initial-value 0)
,(first others)))
(t
`(plus/2 ,(reduce #'plus/2 numbers :initial-value 0)
,(reduce (lambda (x y)
`(plus/2 ,x ,y))
others))))))
And now you can expand, for instance (plus 1 x y 2.0 3 z 4 a) into (plus/2 10.0 (plus/2 (plus/2 (plus/2 x y) z) a)), which I think looks OK to me.
But this is hopeless. It's hopeless because what happens if I say (apply #'plus ...)? Doom: plus needs to be a function, it can't be a macro.
Compiler macros: the right answer
And this is where compiler macros come in. Let's start again, but this time the function (never used above) plus/many will just be plus:
(defun plus/2 (a b)
;; just link to the underlying CL arithmetic
(+ a b))
(defun plus (a &rest bcd)
(if (null bcd)
a
(reduce #'plus/2 bcd :initial-value a)))
And now we can write a compiler macro for plus, which is a special macro which may be used by the compiler:
The presence of a compiler macro definition for a function or macro indicates that it is desirable for the compiler to use the expansion of the compiler macro instead of the original function form or macro form. However, no language processor (compiler, evaluator, or other code walker) is ever required to actually invoke compiler macro functions, or to make use of the resulting expansion if it does invoke a compiler macro function. – CLHS 3.2.2.1.3
(define-compiler-macro plus (a &rest bcd)
(multiple-value-bind (numbers others) (loop for thing in (cons a bcd)
if (numberp thing)
collect thing into numbers
else collect thing into things
finally (return (values numbers things)))
(cond ((null others)
(reduce #'plus/2 numbers :initial-value 0))
((null (rest others))
`(plus/2 ,(reduce #'plus/2 numbers :initial-value 0)
,(first others)))
(t
`(plus/2 ,(reduce #'plus/2 numbers :initial-value 0)
,(reduce (lambda (x y)
`(plus/2 ,x ,y))
others))))))
Note that the body of this compiler macro is identical to the second definition of plus as a macro above: it's identical because for this function there are no cases where the macro wants to decline the expansion.
You can check the expansion with compiler-macroexpand:
> (compiler-macroexpand '(plus 1 2 3 x 4 y 5.0 z))
(plus/2 15.0 (plus/2 (plus/2 x y) z))
t
The second value indicates that the compiler macro did not decline the expansion. And
> (apply #'plus '(1 2 3))
6
So that looks good.
Unlike ordinary macros a macro like this can decline to expand, and it does so by returning the whole macro form unchanged. For instance here's a version of the above macro which only deals with very simple cases:
(define-compiler-macro plus (&whole form a &rest bcd)
(cond ((null bcd)
a)
((null (rest bcd))
`(plus/2 ,a ,(first bcd)))
(t ;cop out
form)))
And now
> (compiler-macroexpand '(plus 1 2 3 x 4 y 5.0 z))
(plus 1 2 3 x 4 y 5.0 z)
nil
but
> (compiler-macroexpand '(plus 1 2))
(plus/2 1 2)
t
OK.

let vs let* in LISP - is there a difference in efficiency?

This should be a quick one: I've been asking myself often whether there's a difference in efficiency between the LISP special functions let and let*? For instance, are they equivalent when creating only one variable?
As Barmar pointed out, there shouldn't be any performance difference in "production ready" Lisps.
For CLISP, both of these produce the same (bytecode) assembly:
(defun foo (x) (let ((a x) (b (* x 2))) (+ a b)))
(defun bar (x) (let* ((a x) (b (* x 2))) (+ a b)))
Though for non-optimizing, simple interpreters (or also compilers) there could very well be a difference, e.g. because let* and let could be implemented as simple macros, and a single lambda with multiple parameters is probably more efficient than multiple lambdas with a single parameter each:
;; Possible macro expansion for foo's body
(funcall #'(lambda (a b) (+ a b)) x (* x 2))
;; Possible macro expansion for bar's body
(funcall #'(lambda (a) (funcall #'(lambda (b) (+ a b)) (* x 2))) x)
Having multiple lambdas, as well as the (avoidable) closing over a could make the second expansion less "efficient".
When used with only one binding, then there shouldn't be any difference even then, though.
But if you're using an implementation that isn't optimizing let* (or let), then there's probably no point discussing performance at all.
There shouldn't be any performance difference. The only difference between them is the scope of the variables, which is dealt with at compile time. If there's only one variable, there's absolutely no difference.

to apply #' or not to apply #'

I've just started to play around with Lisp (Common-Lisp), here's a function that calculates the average of a list of numbers
CL-USER> (defun average (list) (/ (apply #'+ list) (length list)))
AVERAGE
CL-USER> (average '(1 2 3 4))
5/2
however if I rewrite the function like so
CL-USER> (defun average (list) (/ (+ list) (length list)))
it doesn't work since (+ '(list-of-numbers)) can't be evaluated, hence the arguement of length and the expression in the + are incompatible.
is there a way of cajoling (list) to be evaluated naturally as an expression by + and passed as data to length ? rather than using apply #'
I've tried this:
(defun average (list) (/ (+ list) (length '(list))))
but this doesn't seem to do it either !
See Common lisp: How many argument can a function take?
It would be preferable to use (reduce #'+ list) instead (apply #'+ list) because apply is subject to the limit of number of argument a that function can take.
So your average function should looks like:
(defun average (list)
(/ (reduce #'+ list)
(length list)))
BTW, the code (length '(list)) returns 1 because it returns the lenght of a list containing the symbol "list".
There is no reason not to use APPLY or, better, REDUCE. Here REDUCE is the correct function.
If you program in Lisp, most of the time you have to use a symbol, naming your operation, followed by arguments. This is the general basic expression style in Lisp. You might expect that there are shorter ways to write something like reducing a list with a function. But there isn't, in basic Lisp.
(+ (list 1 2 3 4)) is an error because + expects numbers, not a list.
If you want to sum all numbers in a list, you have to use REDUCE. This operation is also known as folding.
Summing the numbers in a list:
(reduce #'+ (list 1 2 3 4))
Another simple way is to use LOOP:
(loop for n in (list 1 2 3 4) sum n)
Writing something like (length '(list)) makes no sense, since you are quoting a list. A quoted list is treated as data and not code. Since it is constant data, the result is always 1.
One of the Lisp ways to get to short programs is to build up a vocabulary of reusable functions. One doesn't use the shortest notation, but instead one is creating reusable functions with obvious names. Thus, if we sum a lot, we write a sum function:
(defun sum (list)
(reduce #'+ list))
Then average is:
(defun average (list)
(/ (sum list) (length list)))

Problems with Nth in common lisp

I'm trying to write a function that can calculate GPA. Now I can do limited calculation(only 3 ),but I stuck on how to calculate more , without using loop or recursion (that's the requirement of subject) how to expend nth function? like: (nth n) ,if so ,is that mean i need to write a lambda expression? As an newbie, I maynot describe the question clearly, really need some help..
Glist is grade points Clist is credit hours.
GPA=( gradepoint *credithour + gradepoint *credithour) / ( the sum of credithour) like: (3*1+3*2+4*1)/(1+2+1)
here is my code:
(defun gpa (Glist Clist)
(format t "~3,2f~%"
(/
(+(nth 0 (mapcar #' * Glist Clist))
(nth 1 (mapcar #' * Glist Clist))
(nth 2 (mapcar #' * Glist Clist)))
(+ (nth 0 Clist)
(nth 1 Clist)
(nth 2 Clist))
);end "/"
);end "format"
(values) );end
EDIT
This seems like a good opportunity to emphasize some common (little c) Lisp ideas, so I fleshed out my answer to illustrate.
As mentioned in another answer, you could use a sum function that operates on lists (of numbers):
(defun sum (nums)
(reduce #'+ nums))
The dot product is the multiplicative sum of two (equal-length) vectors:
(defun dot-product (x y)
(sum (mapcar #'* x y)))
The function gpa is a simple combination of the two:
(defun gpa (grades credits)
(/ (dot-product grades credits) (sum credits)))
The example from the question results in the answer we expect (minus being formatted as a float):
(gpa '(3 3 4) '(1 2 1))
> 13/4
There are a few things worth mentioning from this example:
You should learn about map, reduce, and their variants and relatives. These functions are very important to Lisp and are very useful for operating on lists. map* functions generally map sequences to a sequence, and reduce usually transforms a sequence into to a single value (you can however use forms like (reduce #'cons '(1 2 3))).
This is a good example of the "bottom-up" approach to programming; by programming simple functions like sum that are often useful, you make it easy to write dot-product on top of it. Now the gpa function is a simple, readable function built on top of the other two. These are all one-liners, and all are easily readable to anyone who has a basic knowledge of CL. This is in contrast to the methodology usually applied to OOP.
There is no repetition of code. Sure, sum is used more than once, but only where it makes sense. You can do very little more to abstract the notion of a sum of the elements of a list. It's more natural in Scheme to write functions with functions, and that's a whole different topic. This is a simple example, but no two functions are doing the same thing.
If you're using nth to traverse a list, you're doing it wrong. In this case, you might want to write a summing function:
(defun sum (items)
(reduce #'+ items))

Conditional anaphoric collection best practices?

I trying to iterate through a sequence, conditionally perform an operation on each element and then collect it (but only if it matched the criteria). Here is a simplified example that works, I just want to know if this is proper or best practice in lisp:
(loop for n in '(1 2 3 4 5)
when (when (equal (mod n 2) 0) n )
collect it)
yields
(2 4)
This works, it just looks funny to me and not so much of the when-when but because I feel like I am having to rig the condition to return what I want. I get that the anaphoric it works on the evaluation of the when but this just seems a little artificial to me. Am I missing something? I have only been a lisper for a few weeks.
Edit: Actually, I am somewhat confused when I tried to apply this. What I really want to do is this:
(loop for n in '(1 2 3 4 5)
when (when (equal (mod n 2) 0) n)
collect it
do (format t "~A" it))
but the second it seems to become unbound... how do I do this?
I don't see why you need anaphor here.
(loop for n in '(1 2 3 4 5)
when (evenp n)
collect n and
do (format t "~A" n))
Delete the keyword AND if you want the FORMAT unconditionally.