Language Guide: Page 2

A crash course in the particular workings of microscheme

Fundemental Forms (continued)
  • Assignment: (set! <name> <expr>)

    Assignment looks just like definition, but with the ‘set!’ keyword instead of ‘define’. This is used to change the value to which some variable name is bound. That could be a global variable, which is introduced by (define …), a procedure argument, or a local variable introduced by (let …) The set keyword includes an exclamation mark to remind you that it is changing the state of the system; and this is why Scheme is considered not to be purely functional.

  • Conditional: (<predicate> <consequent> <alternative>)

    The conditional form takes at least a predicate and a consequent, and optinally an alternative. Each of these are expressions of any kind. If the predicate evaluates to true (In Scheme, anything other than false, denoted #f, counts as true) then the consequent will be evaluated. If the predicate evaluates to false, and an alternative is given, then it will be evaluated. This is subtly different from the conditional branches of imperative programming. As well as making a decision about which expression to evaluate, the conditional itself inherits the value of whichever branch is chosen. This means you can use the whole expression as a subexpression, whose value depends on the predicate. e.g. (+ 1 (if (= 2 3) 7 13)) evaluates to 14.

  • Conjunction: (and A B C …)

    The conjunction form takes any number of arguments, each of which is a subexpression. It will evaluate those expressions in order. If it reaches one that evaluates to false (denoted #f), then it will stop and return #f. If none of them evaluates to #f, then the value of the final expression will be returned (remember, anything other than #f is considered true). Using this form with zero arguments is equivalent to the true constant #t.

  • Disjunction: (or A B C …)

    Like conjunction, this disjunction form evaluates each of its arguments in order. If any one of them evaluates to anything other than #f, it stops and returns that value. If it reaches the end of the list, and every expression evaluated to #f, then it returns #f. Using this form with zer oarguments is equivalent to the false constant #f.

    When used with Boolean type values, the conjunctive and disjunctive forms work just like boolean operators in imperative languages. (or #f #t #f) evaluates to #t and so forth. In Scheme, however, these forms perform a much more powerful function. Since they are variadic, and will keep evaluating until a false or true subexpression is reached respectively, they can be used as control-flow mechanisms in place of nested (if …) forms.

  • Local Binding: (let ((a X) (b Y) (c Z) …) B …)

    The let form is used to bind names to values only for a specific part of the program. The first argument to let is a list of binding pairs. Each binding pair is a pair of brackets containing a variable name and an expression. The expressions that are given as the body ‘B …’ are evaluated with those names bound to their corrseponding values, and the value of the final expression is returned. Those bindings do not persist outside of the let form. For any code outside of the let's parentheses, the variables a b c … are unchanged, and may not be defined at all.

    Important nuances:

    1. Even if you only give one binding pair, the parentheses around the list of binding pairs is still needed. Hence, you end up with double brackets: (let ((x 5)) (+ x 1)). Missing those is a common mistake.
    2. The variable bindings apply in the body, but not within other binding pairs in the list. i.e., the expression Y should not rely on X being bound to a.

  • Sequence: (begin B1 B2 …)

    Finally, you can group together expressions with the sequencial form, using the begin keyword. The whole thing is treated as one expression, whose subexpressions are executed in sequence. As usual, the value of the final subexpression is returned for the overall expression.

    You can use this in cases where you want to guarantee a group of expressions will be evaluated, or where you want to give multiple expressions in a context where only one is expected.

    (+ 1 (begin 2 4 6)) evaluates to 7. The subexpressions 2 and 4 are evaluated, but they have no effect. 6 is evaluated and returned to the outer + procedure.