About "cond" in scheme - lisp

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

Related

How to define a function-local constant in Common Lisp?

I have a function like this:
(defun lookup-data (index-key)
(let* ((key-table '("key0" "key1" "key2" ...))
(index (position index-key key-table :test #'string-equal))
...
; do stuff with index, among other things
)
The key table (really just a list of strings, but it's being used as a lookup table to map a string to an index number) is a literal value known at read time. I was thinking perhaps it should be made a defparameter or defconstant, but it's not used anywhere outside this one function. I assume the fact that it's a literal means that most compilers can do constant-based optimization on it as-is, but is there something else I should do to mark it as a constant? What are the options here?
Your code is fine.
key-table is a constant, it will be created once, when the function is compiled.
PS. You can also use #. to create more complicated constants that require code:
(defun ... (...)
(let ((unit #.(let ((u (make-array '(10000 10000) :element-type 'double-float
:initial-element 0)))
(dolist (i 10000 unit)
(setf (aref u i i) 1))))
...)
...))
here the unit matrix unit is created at read time and is a constant (well, you can modify it, but...).

Lisp using And in a Cond statement

having a little trouble correctly using "cond" in conjunction with "and" in one of my functions:
(cond (and (find 'hello actionsems)
(find 'formal actionsems))
(print "Chatterbot: Hello, how are you?")
(and (find 'hello actionsems)
(find 'informal actionsems))
(print "Chatterbot: Hey, how's it going?")
)
I am told that I am "attempting to take unbound variable "AND". Could someone point out where in the syntax I made a mistake?
The COND macro takes a list of conditions and evaluate them in turn. The actual syntax from CLHS is:
Syntax:
cond {clause}* => result*
clause::= (test-form form*)
Arguments and Values:
test-form---a form.
forms---an implicit progn.
results---the values of the forms in the first clause whose test-form yields true, or the primary value of the test-form if there are no forms in that clause, or else nil if no test-form yields true.
Taking that, your condition evaluation should look something like below:
(cond ((and (find 'hello actionsems)
(find 'formal actionsems))
(print "Chatterbot: Hello, how are you?"))
((and (find 'hello actionsems)
(find 'infomal actionsems))
(print "Chatterbot: Hey, how's it going?")))

Explanatory conditional evaluation, and monads?

I have a need for something like cond-> which returns the result along with those branches which evaluated true to give that result. Ideally it should be possible to use the explanatory part optionally only for testing and documentation, and have it be normal cond-> in use. I modified cond-> like this:
(defmacro explanatory-cond->
"Adapted from Clojure's cond-> macro to keep a list of which conditions passed during evaluation"
[expr & clauses]
(assert (even? (count clauses)))
(let [g (gensym)
pstep
(fn [[test step]]
`(if ~test
[(-> (if (vector? (first ~g)) (ffirst ~g) (first ~g)) ~step)
(cons [(quote ~test) (quote ~step) (first ~g)] (second ~g))]
~g)
)
]
`(let [~g [~expr nil]
~#(interleave (repeat g) (map pstep (partition 2 clauses)))]
~g)))
which seems to work, but from my shallow knowledge of monads it looks like there might be a case for their use here (boxing and unboxing that vector) - could any gurus comment is this the case & if so, how to go about doing it, and if not is this modification of cond-> the way to go ?

Simply Scheme Exercises. Chapter 06 True and False

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

let inside cond

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