[Cs254f11] Several questions

Lee Spector lspector at hampshire.edu
Tue Oct 4 10:37:37 EDT 2011


I think the thing that you have to wrap your head around is the lisp evaluation rule. Once you get this everything will seem simple and natural, since it's applied consistently. But until you do I can see that it would be confusing. The lisp evaluation rule is something like this (in my own formulation that I'm making up just now):

To evaluate expression E:

1) If E is a number or something else that evaluates to itself then return E itself and you're done.

2) If E is a symbol then it should have been bound to a value (by a def, or by a let, etc.); return that value and you're done.

3) If E specifies a vector or a set or a map (in [], #{}, or {} respectively) then evaluate all of the stuff inside of it and return the resulting vector/set/map.

4) If E is a list (in ()) then unless rule 5 applies it's a function call. Evaluate everything in it and CALL the value of the first thing, which should be a function, with the values of all of the other things as its arguments.

5) If E is a list (in ()) BUT the first thing in it names a macro or a "special form" (see http://clojure.org/special_forms), then something special may happen! (See below).

Rule 4 means that evaluating ( 0 ) will try to call 0 as a function (on no arguments, since there's nothing else in that list). Not what you want. On the other hand, evaluating 0 gives 0 (by rule 1).

Rules 1-4 are pretty simple and that's what you really have to wrap your head around, but rule 5 is necessary in some cases because you don't always want to "evaluate everything" in a list as it says in rule 4. A prime example of this is "if". For example, if I say: 

(if (> x 0) (println "positive") (println "not positive"))

then I don't want it to print both "positive" and "not positive" before calling a function called "if", but that's what would happen if "if" was defined as an ordinary function so that rule 4 applied. The whole point of "if" is that you only want to evaluate one of the branches, not both, so calls to "if" have to act differently than ordinary function calls. So "if" is defined as a special form. That just means that it can control the evaluation of its arguments. You need something like this in some other cases to, like if you're creating a loop structure or if you're defining a variable. For example, if "def" was an ordinary function then (def foo 22) would try to evaluate foo before calling def on the result, but that's craziness -- foo doesn't yet HAVE a value until def does its thing, and besides we want to define foo itself, not something that's stored in foo...

Macros are essentially like special forms but you can create them yourself. In fact, a bunch of built-in things in Clojure that seem like they'd have to be special forms are actually macros, defined using a small core set of special forms. Defining macros is cool (and this makes lisp powerful in some exciting ways) but this is a pretty advanced topic that you don't need to know anything about to do lots and lots of sophisticated programming. So don't worry about it. All you need to know is that special forms and macros exist so, so that in a few special cases rule 4 won't apply and there'll be special behavior. It's usually obvious when that has to happen, and most of the time thinking in terms of rules 1-4 will solve the kinds of problems that you're having.

In your example, BTW, you had an "if", and that means that we don't "evaluate everything" in advance. But if the condition is true then the first following expression is evaluated and its value is returned, while if it's false then the second following expression is evaluated and its value is returned. Those evaluations of those expressions are normal and the normal rules (1-4) apply to them.

 -Lee





On Oct 4, 2011, at 9:38 AM, Wm. Josiah Erikson wrote:

> Ah! Thanks. I had tried
> 
> (if (= arg1 true) (* 1 modification) ( 0 ) )
> 
> because I thought that the "else" had to be enclosed in parentheses. But it makes sense, I guess, that if you do that, it tries to evaluate it. It's stuff like that that still has me stumped about this language.
> 
> 	-Josiah
> 
> 
> 
> 
> On 10/3/11 7:50 PM, Lee Spector wrote:
>> Josiah,
>> 
>> The answer to the first part is simpler than you probably expected:
>> 
>> On Oct 3, 2011, at 6:20 PM, Wm. Josiah Erikson wrote:
>> 
>>> I'm sure there is a quick and easy answer to both of these questions. I'm still trying to get my chops. So I've got a function:
>>> 
>>> (defn modified_truth
>>> "If the first argument is literally true, as in that exact string,
>>>  then this function will return the second argument.
>>>  Otherwise, this function will return 0."
>>> [arg1 modification]
>>> (if (= arg1 true) (* 1 modification) (* 0 1)))
>>> 
>>> So the (* 0 1) is silly and is really just a way to return 0. Is there a better way to just have something that evaluates to 0? I hate wasting CPU cycles :)
>> The best way to write something that evaluates to 0 is: 0
>> 
>> So you could do:
>> 
>> (if (= arg1 true) (* 1 modification) 0)
>> 
>> Since multiplying by 1 doesn't do anything either you could do:
>> 
>> (if (= arg1 true) modification 0)
>> 
>> Comments on your second question to come later...
>> 
>>  -Lee
>> 
>> --
>> Lee Spector, Professor of Computer Science
>> Cognitive Science, Hampshire College
>> 893 West Street, Amherst, MA 01002-3359
>> lspector at hampshire.edu, http://hampshire.edu/lspector/
>> Phone: 413-559-5352, Fax: 413-559-5438
>> 
> 
> -- 
> Wm. Josiah Erikson
> Network Engineer
> Hampshire College
> Amherst, MA 01002
> (413) 559-6091
> 

--
Lee Spector, Professor of Computer Science
Cognitive Science, Hampshire College
893 West Street, Amherst, MA 01002-3359
lspector at hampshire.edu, http://hampshire.edu/lspector/
Phone: 413-559-5352, Fax: 413-559-5438



More information about the Cs254f11 mailing list