Greets, I'm new to SO so please take care of me.
Exercise 6.1 in Simply Scheme has the expression:
(cond (empty? 3)
(square 7)
(else 9))
My mind says it should evaluate (square 7) and return that. (empty? 3) is evaluated instead (returned the atom — tried it with other atoms and lists, same deal).
I'm confused.
What I know:
Everything in Scheme that is not false is true. If 3 is true and is not empty (#f), why does the cond expression return (empty? 3)?
The first argument to a cond expression is evaluated and where it is true, returns #t, the value defined or #undefined dependent on context. If false, it continues evaluating the cond arguments successively until it does so (or finds no suitable return value) then exits the cond.
What I don't know:
(empty? 3) on its own returns #f. Why does the cond terminate here and not evaluate (square 7)?
Why does the evaluation of (empty? 3) within the cond return the atom, not #t or #f?
I am using SCM with Slib and the additional libraries supplied with Simply Scheme (simply.scm, functions.scm, ttt.scm, match.scm, database.scm) loaded.
The empty? definition in simply.scm is beyond my scheme grasp at this point.
The cond form is like this:
(cond (something-to-check-for-truthiness value-if-truthiness-succeed)
...other checks in the same format as above )
Now if you put your code into this format then.
empty? i.e just the function empty (not its call) fits in place of something-to-check-for-truthiness and a function is always a truth value hence number 3 is returned which is after empty? and fits into value-if-truthiness-succeed slot. So, there is no call to empty?function at all.
That's not quite what cond does.
cond accepts one or more arguments, each argument which must be a list of scheme-expressions.
(cond (#t)) is a valid cond statement.
It evaluates the first expression, and if true, evaluates as many additional s-epressions in that list, and returns the value of the last expression evaluated.
(cond (#t 1 2 3 4 (if (number? 0) "Yeah, sanity!" "It rubs lotion on it's skin"))) is a valid cond statement
Related
it should count the elements of a list, but says "*** - +: NIL is not a number"
(setq A '(2 3 4 3 2 6 7 8 4 3 5 6))
(defun big (A)
(if (not (null (car A))) (+ 1 (big (cdr A))) ) ;if the first element is not null, add 1 to the count of the elements to the rest of the list
)
(print (big A))
Type error
An IF expression has either 2 or 3 arguments:
(if test something)
(if test something something-else)
When it only has 2 arguments, it is as-if the third argument, something-else, was NIL. That means that the IF expression evaluates to NIL when the test expression is false. In your case, you have 2 arguments:
(defun big (A)
(if (not (null (car A)))
;; "then" branch (when condition is true)
(+ 1 (big (cdr A)))
;; no "else" branch (when condition is false)
))
So you know that sometimes a call to big might return NIL.
But, you also write:
(+ 1 (big (cdr A)))
This expression looks like (+ 1 x) with x being a call to big, meaning that x might evaluate to NIL in some cases. That's the case you hit with the debugger.
If you make sure the if expression always return a number, by returning for example zero in the else branch, then you won't have the same error about trying to add a number to NIL.
Counting elements
But then, you would still have other bugs, since you say that the function big "should count the elements of a list". If you want to count the element of a list, you never need to look at the elements stored in the list, you only need to know that they exist.
When you write (car a), you are accessing the first element of the list. You then check if that value is non-nil, but it is perfectly valid to have a list filled with NIL values:
'(NIL NIL NIL)
That list has 3 elements, and at no point the fact that they are NIL should matter when counting them.
A recursive function working on a list typically needs to cover two cases, namely if the list is empty or not. You check if the current list is empty by calling (null list) or (endp list) (just doing (if list ... ...) works too since NIL is the only false value).
The test for null car doesn’t do any good, cdr will return nil before car does.
You need a base case where you find you’re done and return something instead of recursing. Right now you don’t have that. Look at examples of simple recursive functions and see how they have a base case.
To count the elements in a list there are two cases:
The base case where the list is empty (return 0)
The recursive case where the list isn’t empty (return 1 + the count of the cdr of the passed in list)
I am new to lisp and I have a problem, I'm trying to find the number in the list but it is not working. I haven't made the return statement yet
(defun num (x 'y)
(if (member x '(y)) 't nil))
(write (num 10 '(5 10 15 20)))
My output just outputs the nil instead of doing the function and I'm confused of what I am doing wrong.
Solution
(defun member-p (element list)
"Return T if the object is present in the list"
(not (null (member element list))))
The not/null pattern is equivalent to (if (member element list) t nil) but is more common.
In fact, you do not really need this separate function,
member is good enough.
The -p suffix stands for predicate, cf. integerp and upper-case-p.
Your code
You cannot quote lambda list elements, so you need to replace defun num (x 'y) with defun num (x y)
You need not quote t
Quoting '(y) makes no sense, replace it with y.
You do not need to write the function call, the REPL will do it for you.
See also
When to use ' (or quote) in Lisp?
Can you program without REPL on Lisp?
You are almost certainly expected to not just use member, but to write a function which does what you need (obviously in real life you would just use member because that's what it's for).
So. To know if an object is in a list:
if the list is empty it's not;
if the head of the list is equal to the object it is;
otherwise it is in the list if it's in the tail of the list.
And you turn this into a function very straightforwardly:
(defun num-in-list-p (n l)
;; is N in L: N is assumed to be a number, L a list of numbers
(cond ((null l)
nil)
((= n (first l))
t)
(t
(num-in-list-p n (rest l)))))
You could use the built in position function which will return the index of the number if it is in the list:
(position 1 '(5 4 3 2 1))
If you want to define your own function:
CL-USER> (defun our-member(obj lst)
(if(zerop (length lst))
nil
(if(equal(car lst)obj)
T
(our-member obj (cdr lst)))))
OUR-MEMBER
CL-USER> (our-member 1 '(5 4 3 2 1))
T
CL-USER> (our-member 99 '(1 2 3 4 5))
NIL
We can create a function called "our-member" that will take an object (in your case a number) and a list (in your case a list of numbers) as an argument. In this situation our "base-case" will be whether or not the length of the list is equal to zero. If it is and we still haven't found a match, we will return nil. Otherwise, we will check to see if the car of the list (the first element in the list) is equal to the obj that we passed. If so, we will return T (true). However, if it is not, we will call the function again passing the object and the cdr of the list (everything after the car of the list) to the function again, until there are no items left within the list. As you can see, The first example of a call to this function returns T, and the second example call returns NIL.
What makes this utility function a good example is that it essentially shows you the under workings of the member function as well and what is going on inside.
So I'm slightly confused on an introduction to Racket.
I need to write a function called "extend" that takes an element and a predicate, and "extends" the predicate to include the element. For example:
((extend 1 even?) 1)
#t
((extend 3 even?) 3)
#f
I'm fairly new to the language but I don't understand how to get a function to be used or return as a predicate. Not sure if I'm overthinking it or what.
A function is just a value and extend is just a variable like + and cons that evaluate to a function value. functions can be passed as arguments and you just use whatever name you have given it as if it's a function, by using parentheses, and it just works.
A function returns the value the last expression evaluate to. To get it to be a function it either needs to be a variable that evaluate to a function or a lambda that also evaluate to a function.
(define (double-up fn)
(lambda (value)
(fn (fn value)))) ; see. Just use fn as if it is a procedure
((double-up add1) 4) ; ==> 6
(define add2 (double-up add1))
(add2 4) ; ==> 6
(define error-use (double-up 5)) ; works like a charm
(error-use 4)
; Signals "application: not a procedure"
; since `5` isn't a procedure.
Here is another example which is more similar to your assignment. It takes a number, then returns a function that takes another number and then adds them together. Here I choose to define it locally and then leave it as the last expession so that it becomes the result.
(define (make-add initial-value)
(define (adder new-value)
(+ initial-value new-value))
adder) ; this is the result
((make-add 5) 7) ; ==> 12
A predicate is what we call functions often called in predicate position in conditionals (like if and cond). Thus just a function that either return #t or #f and often bound to variables ending with question mark as a naming convention.
I want to be able to do this. For example, this is my code:
(cond [true AA]
[else BB])
In AA, I want it to do 2 things. 1 is to set the value of a global variable, and then return a string. How would I go about doing that?
In the cond special form, there's an implicit begin after each condition, so it's ok to write several expressions, remembering that only the value of the last one will be returned. Like this:
(cond [<first condition>
(set! global-variable value)
"string to return"]
[else
"other return value"])
This sort of thing can be easily found in the Scheme R5RS specification. It really is worth a read as it is one of the finest language specifications ever written!
Other syntactic keywords that you might find of use:
(if <predicate> <consequent> <alternate>)
(begin <expression-or-declaration> ... <expression>)
(case <expression> <case-clause> ...)
(and <test> ...)
... others ...
create a helper function that does 2 things. have your if statement call said function when appropriate:
(cond [(test? something) (your-function your-data)]
[else (another-function your-data)])
A less straightforward way would be to call two functions and "link" them with an "and":
(cond [(test? something)
(and (do-this data) (do-that data))]
[else (do-something-else data)])
I'm working with clojure and while I've dabbled with lisps before, I'm having trouble finding a clean way to nest let statements in cond statements. For example, consider the following function:
(defn operate-on-list [xs]
(let [[unpack vector] (first xs)]
(cond
[(empty? xs) 'empty
unpack vector
:else (operate-on-list (rest xs))])))
It's a pretty standard recursive operation on a list, but it needs to do some work on the first element in the list before it works with the contents. The issue, of course, is that the list may be empty.
In this example, it wouldn't be hard to change unpack to ((first xs) 0) and vector to ((first xs) 1), but this quickly gets ugly if more work needs to be done on (first xs).
Is there any way to effectively use a let statement part-way through a cond?
Thanks.
-Nate
In cases like these, you're best off using if-let:
(defn operate-on-list [xs]
(if-let [[unpack v] (first xs)]
(cond
unpack v
:else (operate-on-list (rest xs)))))
This code walks the given list seq-able (list, vector, array...) of vectors and returns the second element of the first vector whose first element is true (meaning not false or nil). nil is returned if no such vector is found.
Note that vector is a built-in function, so I've chosen v as the variable name, just in case the need to use the function in the body arises in the future. More importantly, you're using too many brackets in your cond syntax; fixed in this version.
UPDATE: Two additional things worth noting about if-let:
The way if-let works, if (first xs) happens to be nil (false would be the same), the destructuring binding never takes place, so Clojure won't complain about not being able to bind nil to [unpack v].
Also, if-let accepts an else clause (in which you can't refer to the variables bound in if-let bindings vector -- though if you're in the else clause, you know they where false or nil anyway).
;use conditional let: http://richhickey.github.com/clojure-contrib/cond-api.html
(use 'clojure.contrib.cond)
(cond-let [b]
nil b
12 (prn (+ b 1))
:else 17 )
;==> 13
Another good example can be found here http://www.mail-archive.com/clojure#googlegroups.com/msg03684.html
Sort of like this, with a let inside the scope of the cond?
(defn operate-on-list [list]
(let [ el_first (first list) ]
(cond
(nil? el_first) (println "Finished")
:else (do
(let [ list_rest (rest list) ]
(println el_first)
(operate-on-list list_rest))))))
(operate-on-list '(1 2 3))
The output is:
1
2
3
Finished