CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
Each file represents a module. A binding becomes visible through the
provideconstruct. Function(require "filename")loads a module
(provide (all-defined-out)) makes all bindings visible(provide a c) makes bindings a and c visible(require "foo.rkt") makes all bindings of the module in file foo.rkt
visible in the current module. Both files have to be in the same directory.foo.rkt#lang racket
; `Make variables a and c visible`
(provide a c)
(define a 10)
(define b (+ a 30)
(define (c x) b)
main.rkt(require "foo.rkt")
(c a)
; `b is not visible`
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
; Constructor
(define (point x y z) (list x y z))
; Accessors
(define (point-x pt) (first pt))
(define (point-y pt) (second pt))
(define (point-z pt) (third pt))
name data structure; Constructor
(define (name f m l) (list f m l))
; Accessor
(define (name-first n) (first n))
(define (name-middle n) (second n))
(define (name-last n) (third n))
(define p (point 1 2 3))
(name-first p) ; This should be an error, and instead it happily prints 1
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
struct#lang racket
(require rackunit)
(struct point (x y z) #:transparent)
(define pt (point 1 2 3))
(check-equal? 1 (point-x pt)) ; the accessor point-x is automatically defined
(check-equal? 2 (point-y pt)) ; the accessor point-y is automatically defined
;
(struct name (first middle last))
(define n (name "John" "M" "Smith"))
(check-equal? "John" (name-first n))
(check-true (name? n)) ; We have predicates that test the type of the value
(check-false (point? n)) ; A name is not a point
(check-false (list? n)) ; A name is not a list
*; (point-x n) ;; Throws an exception
*; point-x: contract violation
*; expected: point?
*; given: #<name>
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
expression = value | variable | apply | define
value = number | void | lambda
apply = ( expression+ )
lambda = ( lambda ( variable* ) term+)
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
value = number | void | lambda
lambda = ( lambda ( variable* )
term+)
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
value = number | void | lambda
lambda = ( lambda ( variable* )
term+)
(define (r:value? v)
(or (r:number? v)
(r:void? v)
(r:lambda? v)))
(struct r:void () #:transparent)
(struct r:number (value) #:transparent)
(struct r:lambda (params body) #:transparent)
We are using a prefix
r:because we do not want to redefine standard-library definitions.
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
expression = value | variable | apply
apply = ( expression+ )
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
expression = value | variable | apply
apply = ( expression+ )
(define (r:expression? e)
(or (r:value? e)
(r:variable? e)
(r:apply? e)))
(struct r:variable (name) #:transparent)
(struct r:apply (func args) #:transparent)
In
r:applywe distinguish between the expression that represents the functionfunc, and the (possibly empty) list of argumentsargs.
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
term = define | expression
define =
( define identifier expression )
| ( define ( variable+ ) term+)
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
term = define | expression
define =
( define identifier expression )
| ( define ( variable+ ) term+)
(define (r:term? t)
(or (r:define? t)
(r:expression? t)))
(struct r:define (var body) #:transparent)
For our purposes of defining the semantics in terms of implementing an interpreter, we do not want to distinguish between a basic definition and a function definition, as this would unnecessarily complicate our code. We, therefore, represent a definition with a single structure, which pairs a variable and an expression (e.g., a lambda). In our setting, the distinction between a basic and a function definition is syntactic (not semantic).
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
struct(struct point (x y z) #:transparent)
Simplifies the definition of data structures:
point-xpoint?What is
#:transparent? A transparent struct prints its contents when rendered as a string.
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
(require rackunit)
; Supplied by the stdlib
(check-equal? 3 (exact-floor 3.14))
(check-equal?
(list 1 2 3)
(list-exact-floor (list 1.1 2.6 3.0)))
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
(require rackunit)
; Supplied by the stdlib
(check-equal? 3 (exact-floor 3.14))
(check-equal?
(list 1 2 3)
(list-exact-floor (list 1.1 2.6 3.0)))
(define (list-exact-floor l)
(match l
[(list) (list)]
[(cons h l)
(cons
(exact-floor h)
(list-exact-floor l))]))
Can we generalize this for any operation on lists?
(check-equal?
(list-exact-floor (list 1.1 2.6 3.0)))
(list (exact-floor 1.1) (exact-floor 2.6) (exact-floor 3.0)))
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
map(define (map f l)
(match l
[(list) (list)]
[(cons h l) (cons (f h) (map f l))]))
map(define (list-exact-floor l)
(map exact-floor l))
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
Recursive code mirrors the structure of your data!
Think of how many constructors your data has, those will be your recursive cases.
(list): return the list constructor (list)(cons h l): add one element f h to the recursive result (map f l) with constructor cons(rest l)(+ n 1) if you approach an upper bound(- n 1) if you approach a lower boundCS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
(list) (handle-base)(cons h l) (handle-step)(define (rec l)
(match l
[(list) `handle-base`]
[(cons h l) `(handle-step h (rec l))`]))
CS450 ☽ Modules, structs, updating lists, exercises ☽ Lecture 5 ☽ Tiago Cogumbreiro
(list) (handle-base)(cons h l) (handle-step)(define (rec l)
(match l
[(list) `handle-base`]
[(cons h l) `(handle-step h (rec l))`]))
map(define (map f l)
(match l
[(list) `(list)`] ; <------------------- `handle-base = (list) `
[(cons h l) ; <------------------- `(handle-step h (rec l))`
(cons (f `h`) ; <--------------------- `use of: h`
`(map f l)`) ; <--------------------- `use of: (rec l)`
In this version, we make the base and handle-steps explicit. Previous solution coalesces nested conds into one.