(if (> 10 5)
(format t "First number is greater ~%"))
(if (> 10 15)
(format t "First number is greater ~%")
(format t "Second number is greater ~%"))
(if (= 10 10)
(format t "Both numbers are equal"))
The syntax of if in most Lisps is (if <test> <then> [<else>]) although there may be some variation: sometimes the <else> is mandatory, and in some older lisps there can be many forms for <else> (I think elisp is the only commonly-used lisp where that is the case now). So a nested if is simple:
(if a
...
(if b
...
(if c
...
...)))
This is annoying in terms of indentation, so there is a form called cond in which the above expression would be, in Common Lisp:
(cond
(a ...)
(b ...)
(c ...)
(t ...))
or in Scheme
(cond
(a ...)
(b ...)
(c ...)
(else ...))
cond has the nice feature that all the ...s can be many forms.
If you didn't have cond you could write it in terms of if: here's a version using Scheme's macros (actually Racket's: void is Racket I think), called kond:
(define-syntax kond
(syntax-rules (else)
[(_)
(void)]
[(_ (else form ...))
(begin form ...)]
[(_ (test form ...)
more ...)
(if test
(begin form ...)
(kond more ...))]))
Similarly, if you didn't have if you could write it in terms of cond: here's one called yf written in terms of kond using Scheme macros again:
(define-syntax yf
(syntax-rules ()
[(_ test result)
(kond (test result))]
[(_ test result otherwise)
(kond (test result)
(else otherwise))]))
Both of these may be variously buggy.
Historically, cond was the primitive I think.
I finally figured out.
(cond ((> 10 5)
(format t "First numbers is greater. ~%")
(< 10 15)
(format t "Second number is greater. ~%")
(= 10 10)
(format t "Both numbers are equal. ~%")))
Related
Working on this program that's supposed to take a vector of integers as input and return the one with the longest integer. Example (vector 20 738 5942 125) and would return 4 as its the longest one. I'm pretty sure I have most of this done the only issue I have is in the conditional as I have to call an outside function (count-integers), this is what I have so far:
(require while)
(define (empty-VINT? low high) (> low high))
(define (count-integers n)
(cond [(< n 10) 1]
(else(+ 1 (count-integers [/ n 10])))))
(define (count-digits V)
(local [
(define x (void))
(define accum (void))
(define largest 0)]
(begin
(set! x (vector-length V))
(set! accum 0)
(while (< accum (vector-length V))
(cond [(empty-VINT? x accum) accum]
[(> (count-integers (vector-ref V accum) largest)
(add1 x) accum(vector-ref V accum))]
[else add1 accum])))))
Right now when its run, I get this message: cond: expected a clause with a question and an answer, but found a clause with only one part. Any suggestions would be great, thanks
First of all, it's not clear what do you want to return. 4 isn't the longest integer (that's 5942), 4 is a maximal digit count among integers in given vector.
Secondly, your code isn't idiomatic and without your comment, it's very hard to say what's going on. Programming in functional languages requies functional way of thinking. Forget about while, set!, void, local and nested define and instead spend some time learning about apply, map, filter and foldl.
I would solve this problem like this:
(define (digits number)
(string-length (number->string number)))
(define (max-digit-count vec)
(apply max (map digits (vector->list vec))))
(max-digit-count (vector 20 738 5942 125))
=> 4
From comments:
Design and implement a function to find the number of digits in the longest integer in a (vectorof integer) ...
use ... while loops
So a plan (design) might be:
count-digits: integer -> natural
max-digit-count: (vectorof integer) -> natural
..something while something max count-digits something ???
Implementing count-digits seems straightforward (but
integers can be negative, and in Racket (integer? 123.000) is true).
#lang racket
(define (count-digits int) ;; Integer -> Natural
;; produce count of digits in int
(string-length (number->string (abs (exact-truncate int)))))
As #Gwang-Jin Kim mentions, while could be defined:
(define-syntax-rule (while condition body ...)
;; From: https://stackoverflow.com/questions/10968212/while-loop-macro-in-drracket
(let loop ()
(when condition
body ...
(loop))))
and then one could use it:
(define (max-digit-count vec) ;; VectorOfInteger -> Natural
;; produce maximum of digit counts of vec elements
(define vx 0)
(define acc 0)
(while (< vx (vector-length vec))
(set! acc (max accum (count-digits (vector-ref vec vx))))
(set! vx (add1 vx)))
acc)
(max-digit-count (vector 20 -738.00 5942 125)) ;=> 4
One of the problems with while is that it can't produce a value (where would it come
from if the condition is false on entry?)
If one "enhanced" while a bit:
(define-syntax-rule (while< x-id limit a-id a-init update)
;; "while loop" incrementing x-id from 0 to limit-1, updating a-id
(let loop ([x-id 0] [a-id a-init])
(if (< x-id limit)
(loop (add1 x-id) update)
a-id)))
max-digit-count could be neater:
(define (max-digit-count vec) ;; VectorOfInteger -> Natural
;; produce maximum of digit counts of vec elements
(while< vx (vector-length vec)
acc 0 (max acc (count-digits (vector-ref vec vx)))))
#MartinPuda's answer is quite good.
I would have defined:
(define (digits n (acc 0))
(if (< n 1)
acc
(digits (/ n 10) (+ acc 1))))
(define (max-digits lst)
(digits (car (sort lst >))))
To apply it:
(max-digits (vector->list (vector 20 738 5942 125)))
Why you should not use while
Using while would force you to mutate variable values. It is much more "natural" for lisp languages to follow the functional style (recursive functions instead of while loops or other loops) rather than the imperative style with mutation of variables.
That is why while is not in the lisp languages.
But if you want to use it:
(define-syntax-rule (while condition body ...)
;; From: https://stackoverflow.com/questions/10968212/while-loop-macro-in-drracket
(let loop ()
(when condition
body ...
(loop))))
(define (digits n (acc 0))
(cond ((< n 1) acc)
(else (digits (/ n 10) (+ acc 1)))))
(define (max-digits lst)
(let ((max-digit 0))
(while (not (null? lst))
(let ((digit (digits (car lst))))
(when (< max-digit digit)
(set! max-digit digit))
(set! lst (cdr lst))))
max-digit))
Then you can try:
> (max-digits (vector->list v))
4
> (max-digits '(1111 123456 2345 34))
6
Prefer let over define
Why? Because if you use let, you can control the scope of the to-be-mutated variable very precisely. You can define in your definition, from where on your variable canNOT have any effect on your code (since its scope ended at some point). While with define you don't have this fine-grained control. (Or this control is implicit not explicite like with let). You could delete/unbind the variable explicitely but that is rarely done in real life.
Therefore, in Lisp, for variable declarations use whenever possible let, especially whenever you deal with mutated variables.
All imperative = declarations should be in Lisp languages let expressions!
You can use function arguments instead of let-definitions, because they are anyway implemented using lets
Just you save syntactically some lines - and the fewer lines you occupy the cleaner the code.
#lang racket
(define (digits n)
(string-length (number->string n)))
(define (max-digit a b)
(if (< (digits a) (digits b)) b a))
(define (max-digits lst (res ""))
(while (not (null? lst))
(set! res (max-digit res (car lst)))
(set! lst (cdr lst)))
(digits res))
I am using Emacs, Slime, and SBCL. Simplifying a problem that I am facing, suppose I have this function working:
(defun get-answer (x y z)
(format t "Which animal would you like to be: ~s ~s ~s ~%" x y z)
(let ((answer (read-line)))
(cond ((equal answer x) (format t "user picks ~s" x))
((equal answer y) (format t "user picks ~s" y))
((equal answer z) (format t "user picks ~s" z)))))
It works for a fixed number of inputs:
CL-USER> (get-answer "fish" "cat" "owl")
Which animal would you like to be: "fish" "cat" "owl"
fish
user picks "fish"
NIL
I would like to generalize this function writing a variant argument macro that builds a variant number of cond clauses. Basically, Common Lisp macro would write the cond clause for me :)
For instance, I wish I could call it like:
CL-USER> (get-answer '("pig" "zebra" "lion" "dog" "cat" "shark"))
Or just:
CL-USER> (get-answer '("dog" "cat"))
Either way, it would generate 6 and 2 appropriate cond clauses, respectively. I tried building something to achieve this goal.
My draft/sketch focusing on the cond clause part is:
(defmacro macro-get-answer (args)
`(cond
(,#(mapcar (lambda (str+body)
(let ((str (first str+body))
(body (second str+body)))
`((string= answer ,str)
,body)))
args))))
The variable answer was supposed to hold the value inserted by the user. However, I can't manage to make it work. slime-macroexpand-1 is not being really helpful.
As an error message, I get:
The value
QUOTE
is not of type
LIST
Which is not something that I was expecting. Is there a way to fix this?
Thanks.
I don't think you need a macro. Note that there's a repeating pattern of ((equal answer x) (format t "user picks ~s" x)), so you should think how to simplify that.
So, this is your function and expected inputs:
(defun get-answer (x y z)
(format t "Which animal would you like to be: ~s ~s ~s ~%" x y z)
(let ((answer (read-line)))
(cond ((equal answer x) (format t "user picks ~s" x))
((equal answer y) (format t "user picks ~s" y))
((equal answer z) (format t "user picks ~s" z)))))
(get-answer '("pig" "zebra" "lion" "dog" "cat" "shark"))
(get-answer '("dog" "cat"))
I'd write something like this:
(defun get-answer (args)
(format t "Which animal would you like to be: ~{~s ~} ~%" args)
(let ((answer (read-line)))
(when (member answer args :test #'string=)
(format t "User picks ~s" answer)
answer)))
Tests:
(get-answer '("pig" "zebra" "lion" "dog" "cat" "shark"))
(get-answer '("dog" "cat"))
Note that your function always returned NIL, mine returns chosen string or NIL. After you recieve user input, you probably don't want to discard it immediately.
And if you have string with values, like this:
(get-answer '(("pig" 1) ("zebra" 3) ("lion" 2) ("dog" 8) ("cat" 12) ("shark" 20)))
I'd use find:
(defun get-answer (args)
(format t "Which animal would you like to be: ~{~s ~} ~%" (mapcar #'first args))
(let* ((answer (read-line))
(match (find answer args :test #'string= :key #'car)))
(when match
(format t "User picks ~s " (first match))
(second match))))
This function returns NIL or value of chosen animal.
The question is a little bit strange, but maybe the point is just to learn about Common Lisp's macros. One could just calculate the members of the condition in a first place. That means, generate a list of string= forms. Then just return a list containing the cond special form and the list of ((string= str) return-value).
(defmacro get-answer (answers)
(let ((clauses (mapcar (lambda (str+body)
(let ((str (first str+body))
(body (second str+body)))
`((string= ,str) ,body))) answers)))
`(cond ,#clauses)))
To test macros, one can use macroexpand and macroexpand-1.
> (macroexpand-1 '(get-answer (("test1" 1) ("test2" 2))))
(COND
((STRING= "test1") 1)
((STRING= "test2") 2))
But I don't personally think it is worth a macro. I think there is nothing wrong with the following function:
(defun get-answer (answer)
(cond
((string= answer "dog") 6)
((string= answer "cat") 2)))
As with Martin Půda's answer: this is not a good place where you need a macro. In particular if you want some undetermined number of options, pass a list of them: Common Lisp has extremely good list-handling functions.
In the simple case you give, the function becomes almost trivial:
(defun get-answer (options)
(format t "Which animal would you like to be (from ~{~A~^, ~})? " options)
(let ((selected (car (member (read-line) options :test #'string-equal))))
(format t "picked ~S~%" (or selected "(a bad answer)"))
selected))
If what you want to to is to map a value selected by the user to another value, then what you want is an alist or a plist:
(defun get-answer/map (option-map)
(format t "Which animal would you like to be (from ~{~A~^, ~})? "
(mapcar #'car option-map))
(let ((selected (assoc (read-line) option-map :test #'string-equal)))
(format t "picked ~A~%" (if selected (car selected) "(a bad value)"))
;; Second value tells us if fn succeeded, as first can be NIL
(values (cdr selected) selected)))
The whole purpose of functions like member and assoc is to search for entries in lists: there is no use in laboriously reimplementing half-working versions of them by writing lots of cond clauses, whether or not you do this automatically.
Now, people often say 'but I want to learn macros, so I will start by learning how to rewrite functions as macros'. That is a not where to start: macros are never useful for rewriting functions in this way, and thinking they are is very damaging.
Here's one simple example of a case where this can't work:
(get-answer (read-options-from-file *my-options-file*))
If get-answer were a macro how is this meant to work? The number of options is not only unknown at macroexpansion time, it is not even knowable, even in principle, because neither the file's name nor its contents can possibly be known at compile time.
Macros are not replacements for functions: they are are functions between languages: a macro compiles a language which is CL (+ other macros) + the language understood by the macro into a language which is CL (+ other macros).
I am slightly struggling to think of a case where a macro might be useful here, but perhaps we can imagine a language which has a with-answer-options form:
(with-answer-options (a)
("elephant" (explode-world :because-of a))
("fish" (set-fire-to-computer :blaming a)))
Note that this form now looks nothing like a function call: it is instead a little language which slightly extends CL, and which will get mapped to CL by the following macro:
(defmacro with-answer-options ((var &optional (prompt "Pick an answer"))
&body clauses)
(unless (symbolp var)
(error "~S should be a variable" var))
(let ((choices (mapcar #'car clauses)))
(unless (every #'stringp choices)
(error "choices should be (<literal string> form ...)"))
`(let ((,var (progn (format t "~A from ~{~A~^ ~}? "
,prompt ',choices)
(read-line))))
(cond
,#(mapcar (lambda (clause)
(destructuring-bind (val &body body) clause
`((string-equal ,var ',val)
,#body)))
clauses)
(t (error "~A is not one of ~{~A~^ ~}" ,var ',choices))))))
So now:
> (with-answer-options (a "Pick a bad thing")
("elephant" (explode-world :because-of a))
("fish" (set-fire-to-computer :blaming a)))
Pick a bad thing from elephant fish? frog
Error: frog is not one of elephant fish
There is a QUOTE, because your macro form contains one:
CL-USER 8 > (defmacro macro-get-answer (args) (print args) nil)
MACRO-GET-ANSWER
CL-USER 9 > (macro-get-answer '(1 2 3))
(QUOTE (1 2 3))
NIL
CL-USER 10 > (macro-get-answer (quote (1 2 3)))
(QUOTE (1 2 3))
NIL
Possible solutions:
don't use a quote
remove the quote
How would you replace the cond to an if else in this program?
#lang racket
(define (my-map f lst)
(cond
[(empty? lst) empty]
[else (cons (f (first lst))
(my-map f (rest lst)))]))
A cond expression with just one condition and a single expression as the consequent and an else part with a single expression as the alternative can be easily transformed into an if expression. For example, this:
(cond (<cond1> <exp1>)
(else <exp2>))
Is equivalent to this:
(if <cond1> ; condition
<exp1> ; consequent
<exp2>) ; alternative
In particular, your code can be rewritten as:
(define (my-map f lst)
(if (empty? lst)
empty
(cons (f (first lst))
(my-map f (rest lst)))))
Also notice that a cond is just a shorter way to express a series of nested if expressions. Think of it as a shorthand for IF-ELSE IF-ELSE IF-ELSE in other programming languages. In fact, for the general case many interpreters implement this:
(cond (<cond1> <exp1> <exp2>) ; we can have any number of conditions
(<cond2> <exp3> <exp4>) ; and any number of expressions after condition
(else <exp5> <exp 6>))
... As a syntactical transformation that (ignoring the => syntax) gets expanded into:
(if <cond1>
(begin
<exp1>
<exp2>)
(if <cond2>
(begin
<exp3>
<exp4>)
(begin ; the last expression is the `else` part
<exp5>
<exp6>)))
Notice that the expressions after each condition are inside a begin form, meaning that in a cond they're implicitly inside a begin - so you can write more than one! whereas in an if expression only a single expression can go in either the consequent or the alternative, and if more than one is needed a begin must be used. As always, refer to the documentation for more details.
Every cond:
(cond (predicate consequent)
(predicate2 consequent2-1 consequent2-2)
(else alternative))
Can be rewritten:
(if predicate
consequent
(if predicate2
(begin
consequent2-1
consequent2-2)
alternative))
Your example becomes particularly simple because there is not more than 2 clauses and the code does not make use of explicit begin.
Racket isn't really Scheme as, for example, Racket requires a different if syntax than Scheme. But, figuring that you are, in fact, learning Scheme you might check out the Scheme R7RS Specification; it provides a definition of cond in terms of if. Here is a definition that I've simplified for you by axing templates involving '=>':
(define-syntax cond
(syntax-rules (else)
((cond (else result1 result2 ...))
(begin result1 result2 ...))
((cond (test)) test)
((cond (test) clause1 clause2 ...)
(let ((temp test))
(if temp temp
(cond clause1 clause2 ...))))
((cond (test result1 result2 ...))
(if test (begin result1 result2 ...)))
((cond (test result1 result2 ...)
clause1 clause2 ...)
(if test
(begin result1 result2 ...)
(cond clause1 clause2 ...)))))
Beautiful, yes?
(define [DML vara]
(cond
((atom? (car vara))
(cond
((eqan? (car vara) 'N)
(display (cdr vara)))
(else (negate vara)))
)))
I'm currently trying to save the content of a return right now for simplicity I was testing the negate function it "returns" a list and I wanted to save the result of that function to do testing. How do I actually save the list return from negate.
Kind of like (x = (negate vara)) where x is the list. I look up let on google and in stack over flow but I can't find a very simple basic assignment.
Excuse my poor syntax on scheme I'm just starting..and going from imperative language to function isn't so smooth..
edit:
I wanted to print out the result expression of (negate vara) but since scheme only prints out the last "recursive call" (pardon my bad wording). I wanted it to use the resulting list from (negate vara) but still print out that list like
say if I had
(else (test (negate vara)))
...
(define (test vara)
(display "test")
)
I wanted it to display
'(O a b)) ;list
here
As you already know, a let expression will do the trick:
(let ((x 10)
(y 20))
(+ x y))
=> 30
The above expression binds values to two variables, x and y. These bindings will exist inside the body of the let. Implicitly, all the expressions in the let form are packed inside a begin, and the end result of the whole expression is the final expression. Notice that one binding cannot refer to the others in the definition part; if one variable needs to refer to previous definitions, then use a let*:
(let* ((x 10)
(y (* x 2)))
(+ x y))
=> 30
Finally, if you need to create a recursive definition use letrec:
(letrec ((fact (lambda (x)
(if (zero? x) 1 (* x (fact (sub1 x)))))))
(fact 10))
=> 3628800
You could make a procedure like you proposed:
(define (test var)
(display var)
var)
(test (negate (test vara)))) ; prints our argument and return
Or you could use DrRacket and use the debugger. You'll miss it after using it once!
In Python, I can do something like this:
t = (1, 2)
a, b = t
...and a will be 1 and b will be 2. Suppose I have a list '(1 2) in Scheme. Is there any way to do something similar with let? If it makes a difference, I'm using Racket.
In racket you can use match,
(define t (list 1 2))
(match [(list a b) (+ a b)])
and related things like match-define:
(match-define (list a b) (list 1 2))
and match-let
(match-let ([(list a b) t]) (+ a b))
That works for lists, vectors, structs, etc etc. For multiple values, you'd use define-values:
(define (t) (values 1 2))
(define-values (a b) (t))
or let-values. But note that I can't define t as a "tuple" since multiple values are not first class values in (most) scheme implementations.
A bare-bones idiom is to use apply with lambda where you'd use let, like:
(define t '(1 2))
(apply (lambda (a b)
;; code that would go inside let
)
t)
The advantage is that it works on any implementation. Of course this can only be used on simple cases, but sometimes that's all you need.
The general term for what you're looking for (at least in Lisp-world) is destructuring and a macro that implements it is known as destructuring-bind. In Common Lisp, it works like this:
(destructuring-bind (a b c) '(1 2 3)
(list a b c)) ;; (1 2 3)
it also works for multiple "levels" of nesting:
(destructuring-bind (a (b c) d) '(1 (2 3) 4)
(list a b c d)) ;; (1 2 3 4)
It looks like there's a nice implementation of destructuring-bind as a scheme macro.
I think this is what you are looking for:
http://www.phyast.pitt.edu/~micheles/scheme/scheme16.html
Look at let-values or let+.
This works in Racket if you don't want to bring in the match dependency:
From a list:
(let-values ([(a b c) (apply values '(1 2 3))])
(+ a b c))
Or directly from a values expression:
(let-values ([(a b c) (values 1 2 3)])
(+ a b c))
Here is a simple destructuring-bind macro for schemes with case-lambda (such as Racket or Chez Scheme):
(define-syntax bind
(syntax-rules ()
((_ arg pat def body)
(apply
(case-lambda
[pat body]
[x def] )
arg ))))
Here is the example that motivated me to write this macro. Putting the default before the body makes for readable code:
(define (permutations l)
;
(define (psub j k y)
;
(define (join a b)
(bind a (ah . at) b
(join at (cons ah b)) ))
;
(define (prec a b z)
(bind b (bh . bt) z
(prec (cons bh a) bt
(psub (cons bh j) (join a bt) z) )))
;
(if (null? k)
(cons (reverse j) y)
(prec (list) k y) ))
;
(psub (list) (reverse l) (list)) )
Here are benchmarks for computing permutations of length 9, on various schemes:
0m0.211s Chez Scheme
0m0.273s Bigloo
0m0.403s Chicken
0m0.598s Racket
The translation to GHC Haskell is 5x faster than Chez Scheme. Guile is much slower than any of these schemes.
Aside from the ease of leveraging the existing case-lambda code, I like how this macro accepts exactly the same syntax as function definition argument lists. I love the simplicity of scheme. I'm old enough to remember programming Fortran on punched cards, where the allowed syntax varied wildly with context. Scheme is supposed to be better than that. The impulse is overwhelming to guild the lily on macros like this. If you can't justify changing the syntax for function definitions too, then don't change that syntax here either. Having an orthogonal grammar is important.