How to compare three arguments in Racket? - racket

I know that you can compare two arguments in Racket using (> 3 2) something like that. But how about three number sets? can you use something like
(define smallest-of-three
(lambda (a b c)
(cond (and (> a b) (> a c))a)))
For example?
Thank you

If you want to find the minimum of three numbers do this:
(min a b c)

As a more general solution, you could instead use foldl, like this:
(foldl (lambda (a b) ;; our comparison function
(if (< a b) a b))
a ;; our initial value
(list b c)) ;; the rest of our values
Now we can do much more complicated comparisons, since we can use any procedure that takes two arguments and only returns one of them.
Using a higher order function, we can generalize this even further:
(define (compare-multiple comp-func)
(lambda (first . rest)
(foldl comp-func ;; our comparison function
first ;; our initial value
rest))) ;; the rest of our values
;; I want to make my own min function
(define my-min (compare-multiple (lambda (a b) (if (< a b) a b)))
;; result is 1
(my-min 42 1 45)

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.

Defining a "minimum" function to return the minimum of a list using another function that returns the smaller of two numbers

(defun *smaller* (x y)
( if (> x y) y
x))
(defun *minimum* (lst)
(do ((numbers lst (cdr numbers))
(result (car numbers) (*smaller* result (car numbers))))
((null numbers) result)))
LISP says that variable "numbers" in "minimum" function is an unbound one although I think I've bound it to "lst". What am I missing?
Do binds in parallel. The expression for the initial value of result is (cdr numbers), and numbers is unbound there. Do* would work here.
Another approach to this problem is to try and think about it inductively.
an empty list has no minimum;
if the list is not empty, its first element is a candidate minimum:
if the rest of the list is empty it's the answer
else the candidate minumum is the smaller of the current candidate and the first element of the list, and carry on through the rest of the list.
This translates very naturally into Lisp:
(defun smaller (x y)
(if (< x y) x y))
(defun running-minimum (candidate tail)
(if (null tail)
candidate
(running-minimum (smaller candidate (first tail)) (rest tail))))
(defun minimum (list)
(when (null list)
(error "?")) ;ed is the standard text editor
(running-minimum (first list) (rest list)))
Notes
For good, if now mostly historical, reasons, CL makes no guarantees that code like this will be turned into an iterative process. Many implementations do so, but a conforming implementation need not, and even implementation which do so may not always do so, for instance in interpreted code or code compiled for ease of debugging. So a minimum function like the above is not really very idiomatic CL, and is certainly not completely safe if the code is meant to be portable.
However that is not my goal in this answer: one of the important things that you should get from learning lisp, in my opinion, is the ability to think inductively about solving problems. In other words to think about a class of problems which can be solved by starting from a simple base case and then steps which get from some general case closer to the base case, and then expressing this in code. This is a very different approach to programming than the approach which is natural in more imperative languages, and once you understand it it's a very powerful way of thinking.
As someone whose first serious language was FORTRAN (in the days when that was the correct way of writing its name even!) I think that this inductive approach is very important, and it's that which I wanted to get across here.
(defun smaller (x y)
"returns the smaller number"
(if (> x y)
y
x))
(defun minimum (list)
"returns the smallest number of a list"
(do* ((numbers list (rest numbers))
(result
(first numbers)
(if numbers
(smaller result (first numbers))
result)))
((null numbers) result)))
First of all, as pointed above, you should use do* instead of do, in order to bind the variables sequentially.
Second, you are testing (null numbers) to end the loop. However, when only one element is left to process, numbers is not nil but then it becomes (cdr numbers) which is nil. This nil value is what is being passed to *smaller* as second argument, and that's why you get the error message. To avoid this, you should test for (null (cdr numbers)) instead:
(defun *smaller* (x y)
( if (> x y) y
x))
(defun *minimum* (lst)
(do* ((numbers lst (cdr numbers))
(result (car numbers) (*smaller* result (car numbers))))
((null (cdr numbers)) result)))
This exits the loop when there is only one item left in the list.

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)))

Racket Lisp : comparison between new-if and if

(define (sqrt-iter guess x)
(if (good-enough? guess x)
guess
(sqrt-iter(improve guess x)
x)))
(define (improve guess x)
(average guess(/ x guess)))
(define (average x y)
(/ (+ x y) 2))
(define (good-enough? guess x)
(< (abs (- (square guess) x)) 0.0001))
(define (square x)
(* x x))
(define (sqrt-g x)
(sqrt-iter 1.0 x))
This is a program for sqrt. And the question is what happens when you attempts to use new-if to replace if with new-if.
(define (sqrt-iter guess x)
(if (good-enough? guess x)
guess
(sqrt-iter(improve guess x)
x)))
This is new if
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
My opinion is the result of two program gonna be the same. because new-if and if can produce the same results.
However, new-if proved wrong, because it is a dead circle when I tried.
So, why?
new-if is a function. All the arguments to a function are evaluated before calling the function. But sqrt-iter is a recursive function, and you need to avoid making the recursive call when the argument is already good enough.
The built-in if is syntax, and only evaluates the then-branch or else-branch, depending on the value of the condition.
You can use a macro to write new-if.
This is the perfect example for demonstration the algebraic stepper!
In the the algebraic stepper you can see how the course of the computation differs from your expectation. Here you must pay notice to the differences in evaluation of, say, (new-if 1 2 3) and (if 1 2 3).
If you haven't tried the algebraic stepper before, see this answer to see what it looks like.
Since racket is an applicative procedure the 3rd argument to the new-if is (sqrt-iter(improve guess x) x)). Since sqrt-iter is recursive the 3rd argument never has a value assigned to it. Therefore you never move into the procedure of new-if to evaluate the function.