2008-09-16 Introduction to Scheme ======================================================================== >>> Introduction to Scheme Scheme syntax... Reminder - the parens can be compared to C parens - they mean apply something - this is the reason why (+ (1) (2)) won't work - if you use C syntax that is "+(1(), 2())" but "1" isn't a function so "1()" is an error. An important difference between _syntax_ and _semantics_ - a good way to think about this is the difference between the string "42" stored in a file somewhere (two ASCII values), and the number "42" stored in memory (in some representation). You could also continue with the above example - there is nothing wrong with "murder" - it's just a word, but murder is something you'll go to jail for. The evaluation function that Scheme uses is actually a function that takes a piece of syntax and returns (or executes) its semantics. ======================================================================== `define' is used for definitions, do not use them for changing values, for example, you should not try to (define x (+ x 1)): this will not work in the early language levels, and will lead to penalty if used later. ======================================================================== There are two boolean values built in to Scheme - `#t' (true) and `#f' (false). They can be used in `if' statements, for example: (if (< 2 3) 10 20) --> 10 because (< 2 3) evaluates to #t. As a matter of fact, *any* value except for #f is considered to be true, so: (if 0 1 2) --> 1 (if "false" 1 2) --> 1 ======================================================================== Note: Scheme is a _functional_ language -- so _everything_ has a value. This makes the expression (if test consequent) have no meaning when "test" evaluates to #f. This is unlike Pascal/C where statements _do_ something (side effect) like printing or an assignment - here an if statement with no alternate part will just "do nothing" if the test is false... Scheme, however, must return some value - our implementation could decide on simply returning #f as the value of (if #f something) but this is something you shouldn't rely on (as all other "it-will-probably-do-this" things), and, in MzScheme it returns something different. In any case, in the early language levels, the condition expression must be a boolean, and you cannot use an `if' with one branch only. ======================================================================== Well, *almost* everything is a value... There are certain things that are part of Scheme's syntax -- for example `if' and `define' are special forms, they do not have a value! More about this shortly. ======================================================================== `cond' is used for a sequence of `if...else if...else if...else'. The problem is that nested `if's are inconvenient. For example, (define (digit-num n) (if (<= n 9) 1 (if (<= n 99) 2 (if (<= n 999) 3 (if (<= n 9999) 4 "a lot"))))) In C/Java/Whatever, you'd write: function digit_num(n) { if (n <= 9) return 1; else if (n <= 99) return 2; else if (n <= 999) return 3; else if (n <= 9999) return 4; else return "a lot"; } (Side question: why isn't there a `return' statement in Scheme?) But trying to force Scheme code to look similar: (define (digit-num n) (if (<= n 9) 1 (if (<= n 99) 2 (if (<= n 999) 3 (if (<= n 9999) 4 "a lot"))))) is more than just bad taste -- the indentation rules are there for a reason, the main one is that you can see the structure of your program at a quick glance, and this is no longer true in the above code. (Such code will be penalized!) So, instead of this, we can use Scheme's `cond' statement, like this: (define (digit-num n) (cond [(<= n 9) 1] [(<= n 99) 2] [(<= n 999) 3] [(<= n 9999) 4] [else "a lot"])) Note that `else' is a keyword that is used by the `cond' form. Also note that square brackets are read by DrScheme like round parens, it will only make sure that the paren pairs match. We use this to make code more readable -- specifically, there is a major difference between the above use of "[]" from the conventional use of "()". Can you see what it is? The general structure of a `cond': (cond [test-1 expr-1] [test-2 expr-2] ... [test-n expr-n] [else else-expr]) ======================================================================== Example for using an if statement, and a recursive function: (define (fact n) (if (zero? n) 1 (* n (fact (- n 1))))) Use this to show the different tools, esp: * special objects that *cannot* be used * syntax-checker * stepper * submission tool (installing, registering and submitting) An example of converting it to tail recursive form: (define (helper n acc) (if (zero? n) acc (helper (- n 1) (* acc n)))) (define (fact n) (helper n 1)) ======================================================================== Additional notes about homework submissions: * Begin every function with clear documentation: a purpose of statement and its type. * Document the function when needed, and according to the guidelines above and in the style guide. * After the function, always have a few test cases -- they should cover your complete code (make sure to include possible corner cases). ======================================================================== >>> Introduction to Scheme: Lists & Recursion Lists: a fundamental Scheme data type. A list is defined as either: 1. the empty list (`null', `empty', or '()), 2. a pair (`cons' cell) of anything and a list. As simple as this may be, it gives us precise *formal* rules to prove that something is a list. * Why is there a "the" in the first rule? Examples: null (cons 1 null) (cons 1 (cons 2 (cons 3 null))) (list 1 2 3) ; a more convenient function to get the above List operations -- predicates: null? ; true only for the empty list pair? ; true for any cons cell list? ; this can be defined using the above Why can't we define `list?' as (define (list? x) (or (null? x) (pair? x))) The difference between the above definition and the proper one can be observed in the full Scheme language, not in the student languages. List operations -- destructors for pairs (cons cells): first rest Traditionally called `car', `cdr'. Also, any `cr' combination for that is made of up to four `a's and `d's -- we will probably not use much more than `cadr', `caddr' etc. ========================================================================