;; The first three lines of this file were inserted by DrRacket. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname |lect20-law-of-racket;-scope|) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) ;;;; ; The Law of Scheme/Racket/Lisp ; lambda (λ) ; let and friends (revisited) #| In Racket, we have *expressions*; every expression *evaluates* to a *value*. E.g. (+ 2 3) evaluates to 5 That's all(*) we do, in racket! An *expr* (syntax) is either: - a value - an identifier - a function-application: (expr_0 expr_1 ... expr_n) - a special form: - (define id expr) [Note that (define (id0 ... idn) expr) is just syntactic sugar for: (define id0 (λ (id1 ... idn) expr)) ] - (cond [expr_q0 expr_a0] [expr_q1 expr_a1] ... [expr_qn expr_an]) - if: (if expr_tst expr_thn expr_els) - define-struct - let Examples: - values 17 #t 'ehllo "eh?" empty (λ (n) (* 3 n)) - identifiers pi num-people + - function application (+ 2 3) (sqrt 23) (* 2 pi (sqrt 23) (+ 2 3)) = (+ 2 3.14 4.87 5) - let (see below for examples) Semantics: - values evaluate to themselves! - identifiers go find the corresponding `define`, use that value. - function application (expr_0 expr_1 ... expr_n) Evaluate each expression, getting values val_0, val_1, ..., val_n Note: val_0 had better be a function! In the body of val_0, replace each parameter with val_1,..., val_n; evaluate that resulting expression. - special forms: - define - cond: takes a *list* of question/answer expressions: -- (cond) evaluates to an error. -- (cond [expr_q0 expr_a0] [expr_q1 expr_a1] ... [expr_qn expr_an]) Evaluate expr_q0 (it had better be a boolean); if the value is true, then evaluate expr_a0 and return that result else return the result of evaluating: (cond [expr_q1 expr_a1] ... [expr_qn expr_an]) - if: (if expr_cond expr_then expr_else) evaluate expr_cond (it had better be a boolean); call the result v_cond. If v_cond is true, return result of eval'ing expr_then; otherwise return result of eval'ing expr_else alternately: the result of eval'ing `if` is syntactic sugar for: the result of evaling (cond [expr_cond expr_then] [else expr_else]) - and, or - define-struct - let, let* Hey: let's look more closely at functions: In "function-application" semantics, we say that the function-application simplifies to "the body of the function, where parameters(identifiers) have been substituted with the arguments(values)" But: what about the very (*) Okay, I'm fudging a bit: `define` isn't really an expression; you can't write (+ 7 (define x 99) 3) However, note that `let` *is* an expression, and it's not too hard to imagine a world where your entire file is really surrounded by one big `let`. ...And we saw that `let` can be translated to a lambda ... ...so can we make a language that doesn't use `define` at all, just uses `lambda` and parameters? See: "the lambda calculus"; "the Y combinator"; "church numerals". |# ;;; step through: (define (sum nums) (cond [(empty? nums) 0] [(cons? nums) (+ (first nums) (sum (rest nums)))])) (sum (cons 2 (cons 9 (cons 1 (cons 44 empty))))) ;;; Note: we will *not* talk about tail-recursion yet -- ;;; let's get more practice with regular ol' functions. ;;; (But we can point out how the stack piles up, for `sum`.)