I am quite confused with cond statements -
I am wondering how I would write something along the lines of this using just the one cond:
(define (name x)
(cond [(statement 1 is true)
[(if statement 1 and statement 2 are both true) *print*]
[(if statement 1 is true and statement 2 is not) *print*]])
[else (statement 1 is false)
[(if statement 1 is false and statement 2 is true) *print*]
[(if statement 1 and statement 2 are both false) *print*]])
(pseudo conditions)
Thank you
Since you are mentioning statement-1 and statement-2 I think your code can be heavily optimized since nested if has already determined the state of statement-1. here is how I see it:
(if statement-1
(if statement-2 ; statement-1 consequent
consequent-1-2-true
alternative-1-true-2-false)
(if statement-2 ; statement-1-alternative
consequent-1-false-2-true
alternative-1-2-false))
statement-2 will only be evaluated once since statement-1 will either be false or true.
A cond is more useful when you have a simple if-elseif where only the alternative has nested ifs.
(cond (predicate-1 consequent-1)
(predicate-2 consequent-2)
...
(predicate-n consequent-2)
(else alternative))
Now you could use a let to calculate the statements in advanced and use and to check that more than one are true:
(let ((result-1 statement-1) (result-2 statement-2))
(cond ((and result-1 result-2) consequent-1-2-true)
(result-1 consequent-1-true-2-false)
(result-2 consequent-1-false-2-true)
(else alternative-1-2-false)))
Of course this let is not necessary if the statements are variables themselves and thus cached. Notice that the tests after the first don't need to check that one is true and the second is not since we know that both cannot be true, then the previous consequent would have fired and the cond had been done. All the perdicates can assume all previous predicates were false.
When writing code it's better to think about what makes the code easier to read and understand. In this case I would not have used cond since the nature of your problem has even nesting on both the consequent and alternative.
Just a followup to my second suggestion (not an answer):
(define (name x)
(if 'statement 1 is true'
(if 'statement 2 is true'
*print1*
*print2*)
(if 'statement 2 is true'
*print3*
*print4*)))
This covers the boolean cases.
Related
I'm having a hard time understanding the syntax of let vs some of the other statements. For example, a "normal" statement has one parentheses:
(+ 2 2)
$2 = 4
Yet the let statement has two:
(let ((x 2)) (+ x 2))
$3 = 4
Why is this so? I find it quite confusing to remember how many parentheses to put around various items.
Firstly, note that let syntax contains two parts, both of which can have zero or more elements. It binds zero or more variables, and evaluates zero or more forms.
All such Lisp forms create a problem: if the elements are represented as a flat list, there is an ambiguity: we don't know where one list ends and the other begins!
(let <var0> <var1> ... <form0> <form1> ...)
For instance, suppose we had this:
(let (a 1) (b 2) (print a) (list b))
What is (print a): is that the variable print being bound to a? Or is it form0 to be evaluated?
Therefore, Lisp constructs like this are almost always designed in such a way that one of the two lists is a single object, or possibly both. In other words: one of these possibilities:
(let <var0> <var1> ... (<form0> <form1> ...))
(let (<var0> <var1> ...) (<form0> <form1> ...))
(let (<var0> <var1> ...) <form0> <form1> ...)
Traditional Lisp has followed the third idea above in the design of let. That idea has the benefit that the pieces of the form are easily and efficiently accessed in an interpreter, compiler or any code that processes code. Given an object L representing let syntax, the variables are easily retrieved as (cadr L) and the body forms as (cddr L).
Now, within this design choice, there is still a bit of design freedom. The variables could follow a structure similar to a property list:
(let (a 1 b 2 c 3) ...)
or they could be enclosed:
(let ((a 1) (b 2) (c 3)) ...)
The second form is traditional. In the Arc dialect of Lisp designed Paul Graham, the former syntax appears.
The traditional form has more parentheses. However, it allows the initialization forms to be omitted: So that is to say if the initial value of a variable is desired to be nil, instead of writing (a nil), you can just write a:
;; These two are equivalent:
(let ((a nil) (b nil) (c)) ...)
(let (a b c) ...)
This is a useful shorthand in the context of a traditional Lisp which uses the symbol nil for the Boolean false and for the empty list. We have compactly defined three variables that are either empty lists or false Booleans by default.
Basically, we can regard the traditional let as being primarily designed to bind a simple list of variables as in (let (a b c) ...) which default to nil. Then, this syntax is extended to support initial values, by optionally replacing a variable var with a (var init) pair, where init is an expression evaluated to specify its initial value.
In any case, thanks to macros, you can have any binding syntax you want. In more than one program I have seen a let1 macro which binds just one variable, and has no parentheses. It is used like this:
(let1 x 2 (+ x 2)) -> 4
In Common Lisp, we can define let1 very easily like this:
(defmacro let1 (var init &rest body)
`(let ((,var ,init)) ,#body))
If we restrict let1 to have a one-form body, we can then write the expression with obsessively few parentheses;
(let1 x 2 + x 2) -> 4
That one is:
(defmacro let1 (var init &rest form)
`(let ((,var ,init)) (,#form)))
Remember that let allows you to bind multiple variables. Each variable binding is of the form (variable value), and you collect all the bindings into a list. So the general form looks like
(let ((var1 value1)
(var2 value2)
(var3 value3)
...)
body)
That's why there are two parentheses around x 2 -- the inner parentheses are for that specific binding, the outer parentheses are for the list of all bindings. It's only confusing because you're only binding one variable, it becomes clearer with multiple variables.
I was a bit surprised by this racket code printing nay when I expected yeah:
(define five 5)
(case 5
[(five) "yeah"]
[else "nay"])
Looking at the racket documentation for case makes it clearer:
The selected clause is the first one with a datum whose quoted form is equal? to the result of val-expr.
So it's about quotation. I'm pretty sure that I did not yet fully grasp what quotation in lisps can buy me. I understand it in the viewpoint of macros and AST transformation. However I'm confused why is it helpful in the case of case for instance..?
I'm also curious, with this specification of case, can I use it to achieve what I wanted to (compare the actual values, not the quoted value), or should I use another construct for that? (cond, while strictly more powerful, is more verbose for simple cases, since you must repeat the predicate at each condition).
The problem is that case introduces implicit quote forms, which cause your example to work for 'five (whose value is 'five), instead of five (whose value is 5).
I almost never use case because of exactly this problem. Instead I use racket's match form with the == pattern:
(define five 5)
(define (f x)
(match x
[(== five) "yeah"]
[_ "nay"]))
(f 5) ; "yeah"
(f 6) ; "nay"
This produces "yeah" on only the value 5, just like you expected. If you wanted it to return "yeah" when it's equal to either five or six, you can use an or pattern:
(define five 5)
(define six 6)
(define (f x)
(match x
[(or (== five) (== six)) "yeah"]
[_ "nay"]))
(f 5) ; "yeah"
(f 6) ; "yeah"
(f 7) ; "nay"
And if you really want to match against quoted datums, you can do that by writing an explicit quote form.
(define (f x)
(match x
[(or 'five 'six) "yeah"]
[_ "nay"]))
(f 5) ; "nay"
(f 6) ; "nay"
(f 7) ; "nay"
(f 'five) ; "yeah"
(f 'six) ; "yeah"
These quote forms are implicit and invisible when you use case, lurking there waiting to cause confusion.
The Racket documentation gives this grammar:
(case val-expr case-clause ...)
where
case-clause = [(datum ...) then-body ...+]
| [else then-body ...+]
Let's compare to your example:
(define five 5)
(case 5 ; (case val-expr
[(five) "yeah"] ; [(datum) then-body1]
[else "nay"]) ; [else then-body2])
We see that (five) is interpreted as (datum). This means that five is
a piece of data (here a symbol), not an expression (later to be evaluated).
Your example of case is evaluated like this:
First the expression 5 is evaluated. The result is the value 5.
Now we look at a clause at a time. The first clause is [(five) "yeah"].
Is the value 5 equal (in the sense of equal?) to one of the datums in (five)? No, so we look at the next clause: [else "nay"]. It is an else-clause so the expression "nay" is evaluated and the result is the value "nay".
The result of the case-expression is thus the value "nay".
Note 1: The left-hand sides of case-clauses are datums (think: they are implicitly quoted).
Note 2: The result of val-expr is compared to the clause datums using equal?. (This is in contrast to Scheme, which uses eqv?.
UPDATE
Why include case? Let's see how one can write the example using cond:
(define five 5)
(let ([val five])
(cond
[(member val '(five)) "yeah"]
[(member val '(six seven)) "yeah"] ; added
[else "nay"])
This shows that one could do without case and just use cond.
However - which version is easier to read?
For a case expression it is easy to see which datums the value is compared to.
Here one must look closely to find the datums. Also in the example we know beforehand that we are trying to find the value among a few list of datums. In general we need to examine a cond-expression more closely to see that's what's happening.
In short: having a case-expression increases readability of your code.
For the historically interested: https://groups.csail.mit.edu/mac/ftpdir/scheme-mail/HTML/rrrs-1986/msg00080.html disussed whether to use eqv? or equal? for case.
UPDATE 2
I'll attempt to given an answer to:
I'm still not clear on the quotation vs working simply on the values though.
I'm wondering specifically why doing the quotation, why working on datum instead
of working on values. Didn't get that bit yet.
Both approaches make sense.
Let's for the sake of argument look at the case where case uses expressions rather than datums in the left hand side of a clause. Also following the Scheme tradition, let's assume eqv? is used for the comparison. Let's call such a
case-expression for ecase (short for expression-case).
The grammar becomes:
(ecase val-expr ecase-clause ...)
where
ecase-clause = [(expr ...) then-body ...+]
| [else then-body ...+]
Your example now becomes:
(define five 5)
(ecase five
[('five) "yeah"]
[else "nay")
This doesn't look too bad and the result is what we are used to.
However consider this example:
(ecase '(3 4)
[('five (list 3 4) "yeah"]
[else "nay")
The result of this would be "nay". The two lists resulting from evaluating the expressions '(3 4) and (list 3 4) are not equal in the sense of eqv?.
This shows that if one chooses to use eqv? for comparisions, having expressions available on the left hand side won't be helpful. The only values that work with eqv? atomic values - and therefore one could just as well use implicit quotations and restrict the left hand side to datums.
Now if equal? was used it would make much more sense to use expressions on the left hand side. The original Racket version of case was the same as the one in Scheme (i.e. it used eq?) later on it was changed to used equal?. If case was designed from scratch, I think, expressions would be allowed rather than datums.
The only remaining issue: Why did the authors of Scheme choose eqv? over equal? for comparisons? My intuition is that the reason were performance (which back in the day was more important than now). The linked to post from the rrrs-authors mailing list gives two options. If you dig a little further you might be able to find responses.
I can't find a reference right now, but case statements use literal, unevaluated data in their different clauses because it is both a frequent use-case and more easily subject to efficient compilation.
You could probably write your own version of Clojure's condp macro or a custom conditional operator to handle your use case.
'and' in Scheme will ignore the error 'division by 0', like (and (negative? (random 100)) (/ 1 0)) returns #f.
How does it do that?
i (define (∧ b₀ b₁) (if (not b₀) #f b₁)), (∧ (negative? (random 100)) (/ 1 0)) still goes into a 'division by 0' error.
You can't define and directly as a function because Scheme is strict--this means that function arguments are always evaluated before being passed to the function.
However, you can define a proper short-circuiting and using a macro. Here's the simplest version in Racket:
(define-syntax-rule (my-and a b) (if a b #f))
or the equivalent form using syntax-rules which is in standard Scheme:
(define-syntax my-and
(syntax-rules ()
[(_ a b) (if a b #f)]))
A macro is not a normal function. Instead, it's a syntactic transformation that runs at compile-time. When you use your new and in your code, it gets "expanded" to the corresponding if expression. So:
(my-and #f (/ 1 0))
gets transformed into
(if #f (/ 1 0) #f)
before your program is run. Since if is built into the language, this has the correct behavior.
Since macros are not functions, it also means you can't pass around as arguments. So you can't write a fold using and directly--you'd have to wrap it into a lambda.
To be more faithful to the original and, you could define my-and to take an arbitrary number of arguments by making the macro recursive. To define a "rest parameter" in a macro, you use the special ... keyword:
(define-syntax my-and
(syntax-rules ()
[(_) #t]
[(_ a) a]
[(_ a b ...) (if a (my-and b ...) #f)]))
If you were using a lazy language like Racket's #lang lazy or Haskell instead, you would not need to use macros here. You could just define and directly:
#lang lazy
(define (and a b) (if a b #f))
or in Haskell:
and a b = if a then b else False
and it would have the correct behavior, as a normal function. You would be able to pass this and to a fold, and it would even stop evaluating the list as soon as it encountered a False! Take a look:
Prelude> foldl and True [True, False, error "fail"]
False
(error in Haskell errors out just like 1/0. Since Haskell is statically typed, the arguments to and have to be booleans so you can't use 1/0 directly.)
Like most languages, Scheme's logical AND uses short circuit evaluation, which means its right operand will only be evaluated if the left operand is true. If the left operand is false, then the result of the expression must be false regardless of the value of the right operand, so if the left operand evaluates to false, it returns false immediately, without evaluating the right operand at all.
To be precise, here's the language from the spec (I'm section 4.2.1 of R5RS, but this isn't an area that's likely to change must between revisions of the spec):
(and <test1> ... )
The <test> expressions are evaluated from left to right, and the value of the first expression that evaluates to a false value (see section 6.3.1) is returned. Any remaining expressions are not evaluated.
Boolean shortcutting. The first argument to "and" evaluates to false, therefore the result must be false, and there's no reason for it to evaluate the second argument (and therefore incur the error).
I have a cond, e.g of the form:
(cond
(condition1) (consequent1)
(condition2) (consequent2))
Say in condition2 I want to compute some value which is expensive, so I would prefer to only do it once. If condition2 is true then I would like to use this expensive value in consequent2. My dilemma is then that I don't want to recompute the value in the condition and consequent, since this is wasteful. I also don't want to throw the whole cond inside a larger let function, e.g.
(let [value-used-in-cond2 do-expensive-computation]
(cond
(condition1) (consequent1)
(condition2) (consequent2)))
since I don't want to compute this value if I never get to condition 2, i.e. if condition1 is true.
Is there an idiomatic way to deal with this? The first thing that comes to mind is to memoizing the expensive function, but there must be simpler solution.
In On Lisp, Paul Graham describes macros for anaphoric variants of Common Lisp conditionals which bind the symbol 'it to the value of the condition expression. These macros obey the same evaluation semantics as the normal conditional forms, so from your example, condition2 will be evaluated after condition1 and only if condition1 is false. All conditions will be evaluated at most once. You can download On Lisp at http://www.paulgraham.com/onlisptext.html, and the code for the anaphoric macros is in figure 14.1 on page 191.
A somewhat ugly solution that should work in Clojure is
(let [expensive-result (or (condition1) (do-expensive-computation)]
(cond (condition1) (consequent1)
(condition2) (consequent2)))
This however requires condition1 to be evaluated twice.
Assuming that lisp / clojure in the heading means Clojure or (another) lisp,
in Common Lisp you can do
(let (var)
(cond
((condition1) (consequent1))
((setq var (condition2)) (consequent2))))
but this will not work in Clojure at the local variable is immutable.
You can use an atom to accomplish something similar with Clojure.
(let [v (atom nil)]
(cond
(condition1) (consequent1)
(do (reset! v (expensive)) (condition2 #v)) (consequent2 #v)))
Use a delay to compute something at most once and use it zero or more times:
(let [expensive-thing (delay do-expensive-computation)]
(cond (condition1) (consequent1)
(condition2 #expensive-thing) (consequent2 #expensive-thing)))
One way of rewriting this in Clojure to avoid repeating the computation would be:
(or
(when (condition1) (consequent1))
(when-let [val2 (condition2)] (consequent2 val2)))
This works assuming that consequent1 and consequent2 never return nil - otherwise evaluation of the or would fall through to the next form.
I had a similar problem, but I only have two case condition so I used a combination of a function and the if-let macro so:
(defn- expensive-computation
[a b]
(if (test (compute a b)) a nil))
(if-let [foo (expensive-computation a b)]
(consequent2 foo)
(consequent1))
As you can see the value is only computed once, after that a simple comparison is done to check if the test of the computation was sucessfull or not. If the test was not sucessful then it return nil, thus executing consequent1.
It is not a super clean solution but it was the best that I found. Hope it helps
If condition2 uses an expensive value, and yet condition2 is false, I assume that it is of the form
(and (expensive-calculation) (other-extra-condition))
What I do in these cases is:
(let (expensive-value)
(cond (condition1 consequent1)
(and (setq expensive-value (expensive-calculation)) (other-extra-condition)) consequent2)
((and expensive-value (other-extra-condition2)) consequent3)
So basically this code's purpose is to simply print out the first n even numbers.
for (i = 0; i <=n; i+= 2)
{
print i;
}
Thing is though, I don't understand Scheme at all. So, help please.
There are several ways to convert the code in the question to Scheme. The first one I can think of:
(define (print-even n)
(let loop ((i 0))
(if (<= i n)
(begin
(print i)
(newline)
(loop (+ i 2))))))
Notice this:
The solution is written as a recursive procedure
Instead of a for loop, I'm using a construct called a named let, which permits the initialization of some iteration variables (i in this case, initialized to 0) and the repeated execution of a recursive procedure (loop in this case), producing an effect similar to a for, even in performance
The stop condition in the "loop" is handled with essentially the same expression: repeat the body of the iteration as long as (<= i n), when that condition becomes false, the iteration ends
The begin surrounds the body of the "loop", just as the curly braces {} do in the original code
The print procedure performs the expected operation; for readability I added a new line after printing each number
The increment part of the original loop i += 2 is handled by the expression (+ i 2), inside the recursive call
So you see, the process being executed is essentially the same, only the way to write it (the syntax!) is different. Give it a try, type this:
(print-even 6)
... And the following will get printed on the screen:
0
2
4
6
Another possible way to implement the procedure, more similar to the original code, although (this is completely subjective) less idiomatic than the previous one:
(define (print-even n)
(do ((i 0 (+ i 2))) ((> i n))
(print i)
(newline)))
Finally, if you're using Racket this will seem even more familiar to you:
#lang racket
(define (print-even n)
(for ((i (in-range 0 (+ n 1) 2)))
(print i)
(newline)))
The first big difference between Scheme and other languages is this: In Scheme, you do (almost) everything recursively.
To implement a simple loop, for instance, you would define a recursive function. This function would first check to see whether it's time to break out of the loop; if is is, it would return the final value. (There is no final value in this case, so it would just return something like (void) or '().) Otherwise, the function would do whatever it's supposed to do, then call itself again.
Any loop variables (such as i) become arguments to the function.
Hopefully this helps you understand how to do this.
The Scheme way to do something like this is using a recursive function like the one below.
(define (doit value n)
(if (<= value n)
(begin
;;...perform loop body with x...
(display value)(newline)
(doit (+ value 2) n))))
To call this function you call (doit 2 n) where n is your n in the for loop.
With regards to learning Scheme, I recommend the first two links below.
For additional information on Scheme see
SICP
How to Design Programs
Schemers
Related Stackoverflow Question
Scheme Cookbook Looping Constructs