cs f331 / csce a331 spring 2017 · scheme: data cs f331 programming languages csce a331 programming...

32
Scheme: Data CS F331 Programming Languages CSCE A331 Programming Language Concepts Lecture Slides Monday, April 3, 2017 Glenn G. Chappell Department of Computer Science University of Alaska Fairbanks [email protected] © 2017 Glenn G. Chappell

Upload: lekhue

Post on 04-Jun-2018

231 views

Category:

Documents


0 download

TRANSCRIPT

Scheme: Data

CS F331 Programming Languages

CSCE A331 Programming Language Concepts

Lecture Slides

Monday, April 3, 2017

Glenn G. Chappell

Department of Computer Science

University of Alaska Fairbanks

[email protected]

© 2017 Glenn G. Chappell

ReviewPL Features: Reflection

Reflection in a computer program refers to the ability of the program to deal with its own code at runtime: examining the code, looking at its properties, and modifying it.

An important property of a PL is whether, and how well, it supports reflection.

The Lisp-family PLs are distinguished by their excellent support for reflection.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 2

ReviewPL Categories: Lisp-Family PLs [1/2]

In 1958, MIT professor John McCarthy published a mathematical formalism for describing computation.

This formalism was written in various was; the most common notation was the Symbolic Expression, or S-expression. An S-expression is either an atom (basically a word), a pair (two S-expressions separated by a dot and enclosed in parentheses), or nil (an empty pair of parentheses).

(THIS . (IS . (AN . ((S . (EXPRESSION . ())) . ()))))

A shorter form uses a parenthesized list of space-separated items. Something like “(A . (B . (C . ())))” is written as “(A B C)”.

(THIS IS AN (S EXPRESSION))

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 3

ReviewPL Categories: Lisp-Family PLs [2/2]

An implementation of the evaluation procedure of this formalism, initially written by Dartmouth student Steve Russell, became the programming language Lisp (LISt Processor).

S-expressions are the syntax for both code and data in Lisp.

The C/C++/Java expression (a + 2) * -b would be written as follows in a typical Lisp-family PL: (* (+ a 2) (- b))

Lisp source code is a direct representation of its own AST!

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 4

ReviewIntroduction to Scheme — Characteristics [1/4]

Scheme is a Lisp-family PL with a minimalist design philosophy.

Scheme code consists of parenthesized lists, which may contain atoms or other lists. List items are separated by space; blanks and newlines between list items are treated the same.

(define (hello-world)

(begin

(display "Hello, world!")

(newline)

)

)

When a list is evaluated, the first item should be a procedure(think “function”); the remaining items are its arguments.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 5

ReviewIntroduction to Scheme — Characteristics [2/4]

The type system of Scheme is similar to that of Lua.

Typing is dynamic.

Typing is implicit. Type annotations are generally not used.

Type checking is structural. Duck typing is used.

There is a high level of type safety: operations on invalid types are not allowed, and implicit type conversions are rare.

There is a fixed set of types.

Lua’s fixed set of types includes only 8 types, while Scheme has 36. We look at some of these next.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 6

ReviewIntroduction to Scheme — Characteristics [3/4]

Two heavily used types are pair and null, which are mostly used to construct lists.

Values of all other types are atoms. Here are a few of these:

Booleans. Values are #t (true) and #f (false).

Strings. Enclosed in double quotes: "This is a string."

Characters. For example, here is the 'a' character: #\a

Symbols. A symbol is an identifier: abc x a-long-symbol

Number types. There are seven of these, including arbitrarily large integers (like Haskell’s Integer), floating-point numbers, exact

rational numbers, and complex numbers.

Procedure types. A procedure is what we would call a first-class function. A procedure may be bound to a name (a symbol), or it may be unnamed. There are actually six procedure types, but we will not need to distinguish between these.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 7

ReviewIntroduction to Scheme — Characteristics [4/4]

Scheme has no special syntax for flow of control. Instead, flow-of-control constructs are procedures. Here is some Lua code and more or less equivalent Scheme code.

if x == 3 then -- Lua

io.write("three")

else

io.write("other")

end

(if (= x 3) ; Scheme – "if" is a procedure

(display "three")

(display "other")

)

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 8

ReviewScheme: Expressions & Procedures — General Syntax

We have seen what Scheme code looks like: parenthesized lists of lists, with items separated by space. Many special characters are legal in symbols.

In addition:

Strings are surrounded by double quotes.

A leading single quote suppresses evaluation.

Scheme has three kinds of comments.

A semicolon (;) begins a single-line comment.

Multiline comments: #| … |#

Comment out a single expression: #;EXPR

#;(This code is

commented (out)) (display "But this is not.")

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 9

ReviewScheme: Expressions & Procedures — Expressions [1/4]

Like Haskell, Scheme code consists largely of expressions.

An expression can be:

An atom.

A list whose first item evaluates to a procedure.

To evaluate a list, Scheme begins by evaluating its first item. This should result in a procedure.

Normally, the remaining arguments are then evaluated. The results of these evaluations are passed to the procedure as its arguments. For some special procedures, the remaining arguments are not evaluated.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 10

ReviewScheme: Expressions & Procedures — Expressions [2/4]

For example, + is a symbol. It evaluates to a procedure that

takes zero or more numeric parameters and returns their sum. Informally, we say that + is a procedure.

> (+ 2 7)

9

> (+ 5 3 4 8 1 2 6)

29

Symbols -, *, and / are similar.

> (* (+ 3 5) (- 7 3) ; Like (3 + 5) * (7 – 3)

32

> (* 2 (/ 15 3))

10

3 Apr 2017 CS F331 / CSCE A331 Spring 2017

Some procedures can take a varying number of parameters.

11

ReviewScheme: Expressions & Procedures — Expressions [3/4]

Scheme does not distinguish between operators and other symbols. Nothing is infix.

Scheme uses +, -, *, and / for the basic arithmetic operations. But

the division operator might not do what you expect.

> (/ 4 2)

2

> (/ 4 6)

2/3

> (/ 2/3 4)

1/6

> (+ 1/5 0.7)

0.9

3 Apr 2017 CS F331 / CSCE A331 Spring 2017

A real (floating-point) number, which, as usual with floating-point, is inexact.

An exact rational number

Implicit type conversions:integer → rational → real → complex.

12

ReviewScheme: Expressions & Procedures — Expressions [4/4]

The numeric comparison operators: = < <= > >=

There is no inequality operator!

Logical operations: and or not

> (= 1 2)

#f

> (not (= 1 2))

#t

> (and (> 4 1) (<= 5 2))

#f

3 Apr 2017 CS F331 / CSCE A331 Spring 2017

There are several different kinds of

equality in Scheme. Use the above

comparison operators only with numbers.

13

ReviewScheme: Expressions & Procedures — Lists

Two heavily used procedures are car and cdr. Each takes a pair. car returns the first item of the pair. cdr returns the second.

Thus, for a nonempty list, car returns the first item, while cdr

returns a list of the remaining items.

> (car '(5 4 2 7))

5

> (cdr '(5 4 2 7))

(4 2 7)

cons constructs a pair. We can use it to construct a list from an item and a list, like “:” in Haskell.

> (cons 5 '(4 2 7))

(5 4 2 7)

3 Apr 2017 CS F331 / CSCE A331 Spring 2017

A single quote suppresses evaluation. We do not want to treat 5 as a procedure, passing 4, 2, 7 as its arguments. We want the list.

14

ReviewScheme: Expressions & Procedures — Predicates

Recall: a predicate is a function returning a boolean. It answers a yes/no question about its argument(s). It is traditional for the name of a Scheme predicate to end in a question mark.

Here are some type-checking predicates. Each takes a single parameter, which can be of any type.

number? Returns true (#t) if its argument is a number, otherwise false (#f).

null? Returns true if its argument is null (an empty list).

pair? Returns true if its argument is a pair. Thus, if the argument is a list, then it returns true if the list is nonempty. If neither null?nor pair? returns true for a value, then the value is an atom.

> (number? 3)

#t

> (number? +)

#f

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 15

ReviewScheme: Expressions & Procedures — Binding

Globally bind a symbol to a value with define.

> (define abc (+ 5 3))

> abc

8

> (* abc (- abc 5))

24

> (define xyz +)

> (xyz 3 4)

7

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 16

ReviewScheme: Expressions & Procedures — Defining Procedures [1/2]

We can also define new procedures with define. The first

argument is a list that is essentially a “picture” of a call to our new procedure. The second argument is an expression giving the code for the procedure; this code is not evaluated until the procedure is called. Parameters are bound locally.

> (define (sqr x) (* x x))

> (sqr 6)

36

> (define (not= a b) (not (= a b)))

> (not= 1 3)

#t

> (not= (+ 1 2) 3)

#f

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 17

ReviewScheme: Expressions & Procedures — Defining Procedures [2/2]

if is a three-parameter procedure.

(if COND THEN-EXPR ELSE-EXPR)

The above evaluates COND. If this evaluates to anything other than #f, then it evaluates THEN-EXPR and returns the result;

otherwise, it evaluates ELSE-EXPR and returns the result.

> (if (= 3 3) "yes" "NO")

"yes"

A recursive call is done by using the word being defined inside its body.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017

For code, see proc.scm.

18

Scheme: Dataquote, eval, & More Code — quote

quote is a special procedure that takes one parameter,

suppressing the normal parameter evaluation. It returns this parameter.

> (quote (1 2 3))

(1 2 3)

The leading-single-quote syntax is actually shorthand for quote.

> '(1 2 3) ; Same as (quote (1 2 3))

(1 2 3)

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 19

Scheme: Dataquote, eval, & More Code — eval

eval is a procedure that takes one parameter and evaluates it. eval does not suppress the normal evaluation of parameters,

so, strictly speaking, evaluation happens twice: the parameter is evaluated, and then it evaluates the result.

list is a procedure that takes any number of parameters,

evaluating them as usual, and returns a list holding them.

> (list "hello" '+ 1 2 3))

("hello" + 1 2 3)

> (eval (cdr (list "hello" '+ 1 2 3)))

6

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 20

Scheme: Dataquote, eval, & More Code — More Code [1/3]

Scheme has map, which is much like Haskell’s map.

> (define (sqr n) (* n n)

> (map sqr '(1 2 3 5 7))

(1 4 9 25 49)

Similarly: filter.

> (define (big n) (> n 20)

> (filter big '(1 150 6 37 -8 0 12 1000))

(150 37 1000)

Let’s write our own versions of these.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 21

Scheme: Dataquote, eval, & More Code — More Code [2/3]

A useful function is cond, which does if … elseif ….

(cond

[CONDITION1 EXPR1]

[CONDITION2 EXPR2]

[CONDITION3 EXPR3]

)

The return value is the value of the expression corresponding to the first true condition—or nothing if no condition is true.

The last condition may be else, which makes it handle all

remaining cases.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 22

Scheme: Dataquote, eval, & More Code — More Code [3/3]

TO DO

Write our own version of map; call it mymap.

Similarly, myfilter.

Q. We need to be able to return an empty list. How?

A. Use '(). Or null, which evaluates to an empty list.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 23

Done. See data.scm.

Scheme: DataData Format [1/5]

The dot notation originally used in S-expressions is also valid in Scheme.

> '(1 . 2)

(1 . 2)

A list is really shorthand for the equivalent dot notation, again, just as in the original S-expression syntax.

> '(1 . (2 . (3 . (4 . ()))))

(1 2 3 4)

Dot (.) is not a function. It is simply another way of typing S-

expressions. If you want a normal function that puts things together the way dot does, use cons.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 24

Scheme: DataData Format [2/5]

The main building block for constructing data structures in Scheme is the pair. This is a node with two pointers.

We get the item referenced by the left pointer using car; similarly use cdr for the right pointer.

> (car '(1 . 2))

1

> (cdr '(1 . 2))

2

3 Apr 2017 CS F331 / CSCE A331 Spring 2017

1 2

(1 . 2)

25

Scheme: DataData Format [3/5]

Lists are constructed from pairs and null.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017

(1 2 3) = (1 . (2 . (3 . ())))1

2

3 NULL

26

Scheme: DataData Format [4/5]

The full story on the dot syntax is that the dot may optionally be added just before the last item of a list.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017

(1 2 3)

= (1 . (2 . (3 . ())))

1

2

3 NULL

(1 2 . 3)

= (1 . (2 . 3))

1

2 3

27

Scheme: DataData Format [5/5]

We can create arbitrary binary trees—with the restriction that only leaves have data.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017

(((() . 8) . 1) . (5 . 1))

5 11

8NULL

28

Scheme: DataTaking a Varying Number of Parameters [1/3]

We have seen how to create new procedures using define. So far, all of our procedures have taken a fixed number of parameters. But Scheme allows for procedures like “+”, which can take any

number of parameters.

Suppose we wish to duplicate “+”, in the form of a function called sum. We will use “+”, but only as a 2-parameter function.

Think about a call to sum:

> (sum 1 2 3 4)

10

The above list (sum 1 2 3 4) is the same as (sum . (1 2 3 4)).

A procedure call is a pair. The car is the procedure; the cdr is a

list of the procedure’s arguments (illustrated to the right above).

3 Apr 2017 CS F331 / CSCE A331 Spring 2017

PROC ARGS

Procedure Call

29

Scheme: DataTaking a Varying Number of Parameters [2/3]

A procedure call is a pair: (PROC . ARGS). And define will also

take this form of a “picture” of a function call.

(define (sum . args)

...

)

TO DO

Write procedure sum.

A tricky issue is how to make a recursive call on (cdr args). We

cover this on the next slide.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017

Done. See data.scm.

30

Scheme: DataTaking a Varying Number of Parameters [3/3]

In writing function sum, we need to make a recursive call on(cdr args). How do we do this?

NOT like this (dot is not a function!):

(sum . (cdr args)) ; WRONG!

The following will work, but it is a bit unwieldy:

(eval (cons sum (cdr args)))

Scheme provides apply for this situation. Here is how we do it:

(apply sum (cdr args))

3 Apr 2017 CS F331 / CSCE A331 Spring 2017 31

(sum . (cdr args))

is just another way to write (sum cdr args), which is

not what we want.

Scheme: DataManipulating Trees

Recall that a Scheme value is null, or a pair, or an atom. Any value for which both null? and pair? return #f is an atom.

We can write procedures that deal with a structure, not as a list, but as a tree, traversing the tree and dealing with atoms in some way.

TO DO

Write a procedure atomsum that is given a tree t and returns the

sum of all the atoms in t.

Write a procedure atommap that is given a function f and a tree t

and returns a tree that is t with each atom replaced by the value of

f at that atom.

A useful procedure is error, which, much like Haskell’s error,

takes a string, and crashes with a message if it executes.

3 Apr 2017 CS F331 / CSCE A331 Spring 2017

Done. See data.scm.

32