Lists CSC 358/458 4.3.2006. Outline Lab #1 / Homework #1 Lists A question List Internals of Lists...

Post on 08-Jan-2018

220 views 1 download

description

Lab #1 (defun add-car (lst1 lst2) (+ (car lst1) (car lst2))) (defun deal-hand (size deck) (let ((hand '())) (dotimes (i size) (push (pop deck) hand)) hand)) (defun count-face-cards (hand) (let ((counter 0)) (dolist (card hand) (if (face-cardp card) (incf counter))) counter)) (defun face-cardp (card) (not (numberp (card-rank card))))

Transcript of Lists CSC 358/458 4.3.2006. Outline Lab #1 / Homework #1 Lists A question List Internals of Lists...

Lists

CSC 358/4584.3.2006

Outline

Lab #1 / Homework #1 Lists

A questionListInternals of ListsList operations

Extended Example

Lab #1

(defun add-car (lst1 lst2) (+ (car lst1) (car lst2)))

(defun deal-hand (size deck) (let ((hand '())) (dotimes (i size) (push (pop deck) hand)) hand))

(defun count-face-cards (hand) (let ((counter 0)) (dolist (card hand) (if (face-cardp card) (incf counter))) counter))

(defun face-cardp (card) (not (numberp (card-rank card))))

Lab #1 (Extra credit)

(defun average-face-cards (trials size) (let ((deck (make-deck)) (count 0)) (dotimes (k trials) (setf deck (shuffle-deck deck)) (incf count (count-face-cards (deal-hand size deck)))) (/ (float count) trials)))

Homework #1

;; Cheating version (using case)(defun card-blackp (card) (case (card-suit card) ((H D) nil) ((S C) t)))

;; Non-cheating version (using cond)(defun card-blackp (card) (let ((suit (card-suit card))) (cond ((or (eq suit 'H) (eq suit 'D)) nil)

(t t))))

;; Functional version with boolean return value(defun card-blackp (card) (let ((suit (card-suit card))) (or (eq suit 'S) (eq suit 'C))))

Homework #1

(defun not-twenty-onep (card1 card2) (let ((rank1 (card-rank card1)) (rank2 (card-rank card2))) (if (and (= rank1 1) (= rank2 1)) ;; special case 12 (let ((value1 (card-points-bj rank1)) (value2 (card-points-bj rank2))) (let ((value-sum (+ value1 value2))) (if (= value-sum 21) nil value-sum))))))

(defun card-points-bj (rank) (case rank ((k q j) 10) (1 11) (otherwise rank)))

Homework #1

(defun card-points-skat (rank) (case rank (1 11) (10 10) (k 4) (q 3) (j 2) (otherwise 0)))

(defun skat-trick (trick) (let ((score 0)) (dolist (card trick) (incf score (card-points-skat (card-rank card)))) score))

Homework #1 (XC)(defun can-buildp (hand center) (dolist (hand-card hand) (dolist (center-card center) (if (can-build-cards hand-card center-card hand) (return-from can-buildp

(list hand-card center-card)))))))

(defun can-build-cards (hand-card center-card hand) (let ((hand-value (card-points-cassino (card-rank hand-card))) (center-value (card-points-cassino

(card-rank center-card)))) (let ((build-value (+ hand-value center-value))) (dolist (card hand) (if (= build-value (card-points-cassino

(card-rank card))) (return-from can-build-cards t))))))

(defun card-points-cassino (rank) (case rank (k 13) (q 12) (j 11) (otherwise rank)))

Homework #1

(defun can-buildp (hand center) (let ((ans nil)) (dolist (hand-card hand) (dolist (center-card center)

(if (can-build-cards hand-card center-card hand) (setf ans (list hand-card center-card)))))

ans))

Last week

How to deal with card games with different point values? One possibility

• lots of named functions• ick

Better approach be data-driven let the functions be defined by the data

Problem don't want an extra argument to a comparison

operator• suppose I want to supply the comparison to a sort

function?

Lisp solution

Create an anonymous function using the datause this function for comparing

Benefitscan create as many as neededsymbol table not filled with

unnecessary stuff

card-comparator

(defvar *default-card-values* '((K 13) (Q 12) (J 11)))

(defvar *ace-high-values* '((1 14) (K 13) (Q 12) (J 11)))

(defvar *skat-card-values* '((1 14) (10 13) (K 12) (Q 11) (J 10)))

(defun rank-to-number2 (rank card-values) (let ((value-pair (assoc rank card-values))) (if value-pair (cadr value-pair) rank)))

(defun card-comparator (&optional (card-values *default-card-values*))

#'(lambda (card1 card2) (let ((rank1 (card-rank card1)) (rank2 (card-rank card2))) (< (rank-to-number2 rank1 card-values) (rank-to-number2 rank2 card-values)))))

Some syntax: lambda

lambdaa lot more about this next weekthis is how we define an anonymous

function defun is just a convenience

(setf (function foo) #'(lambda (x y) (+ x y)))

the same as (defun foo (x y) (+ x y))

lambda is fundamental

Optional arguments

More about this next week I can specify in the parameter list that

some arguments are optionaland then supply default values

Optional arguments must be at the endfor obvious reasons

Closure

Note the function I define using lambda refers to a parameter defined in the

enclosing scope• card-values

the function is returned to the caller• the enclosing scope disappears

can I do this? Yes!

technical term = "lexical closure" more about this next week

Lists

A Question

Why can’t I really deal from my deck?Why does this function not change the

value of its argument?(defun mypop (lst)

(pop lst))> (setf l1 '(a b c))> (mypop l1)A> l1(A B C)

Lists

sequences of itemsatoms or lists

carfirst element

cdrrest

consbuilds a list

Other List Builders

lista list containing the arguments

appenda list combining the arguments

Internals (a b c)

A

B

nil

C

Nested List

nil

A

B

nil

Enil

C

D

Improper List

A B

What Does It Do?*

(setf l1 '(a (b c))) (setf l2 '((d) e)) (car l2) (cdr l1) (cons 'b l1) (list l2 'd) (append l1 l2)

What does it do?

(pop l1) special form short for (setf l1 (cdr l1))

(defun mypop (lst)(pop lst))

(defun my pop (lst)(setf lst (cdr lst)))

(mypop l1) l1 doesn't change

why should it? it is still bound to the same thing

How can we achieve this?

Global variableick

Game state structurepass in and outcontents manipulatedbetter

Example: Blackjack

(defun make-bj-game (player-count) (list (shuffle-deck (make-deck))

(make-list player-count :initial-element nil)))

(defun player-count (game) (length (hands game)))

(defun deck (game) (cadr game))

(defun hands (game) (caddr game))

(defun hand (player game) (nth player (hands game)))

New function

make-listnote the function call:initial-element

• keyword argument• we'll see this again later

Shared Structure

It is easy to create lists that share structure(setf c (append a b))

Not a problem unless a or b is destructively modified

List Functions

Accessorsnavigating around in lists

Operationsmanipulate the whole list

Destructive operationsmodify the list

List Accessors

car, cdr positional

first, second, third(nth i lst)(nthcdr i lst)

end of the listlastactually returns last cdr

List Operations

Many! Mapping functions Boolean operations Finding Modifying (copy) Reduce

Mapping

Functions that apply a function over and over across a list

(mapcar #’fn lst)applies the function to each element in

the listreturns a list of the results

Also works with multiple lists(mapcar #’fn lst1 lst2)

Example

Matt's question What if I want to add 5 to everything in

a list?(mapcar #'(lambda (x) (+ x 5)) '(1 2 3))

Other Mapping Functions

maplistapplies to successive cdrs

mapcanjoins results with append

mapc, mapllike mapcar and maplist but doesn't

return results

Boolean Operations

logical summary of a list relative to a function

(some #’fn lst) true if any element of lst returns true when

the function is applied every

false if any element returns false notany notevery

Example

flushpis a poker hand a flush?

• 5-card hand, please logic

all cards the same suitsimple method

• all spades or all clubs or ...better way?

Finding Operations

(member elem lst)if elem is in list, returns the cdr

headed by elem (position elem lst)

if elem is in list, return position index both return nil is absent

Modifications

(remove elem lst) returns a copy of lst with elem removed not “destructive” Also "if" version

• remove-if• has a test instead of an element

(substitute old new lst) returns a copy of lst with old replaced by new

Reduce

“reduce” list into a single value (reduce #’fn lst)

applies fn to first two elementsapplies fn to that result and next

elementetc.

(reduce #’+ ‘(1 2 3 4)) => 10

Example

count-face-cardsmapcar and reduce

Original version(defun count-face-cards (hand) (let ((counter 0)) (dolist (card hand) (if (face-cardp card) (incf counter))) counter))

(defun face-cardp (card) (not (numberp (card-rank card))))

Destructive Operations I

Most Lisp operations return “new” listsremove(setf lst ‘(b a b a b))(remove ‘a lst) => (b b b)lst => (b a b a b)Use the result of the function

New cons cells creatednot always what you want

Destructive Operations II

Alter the contents of cons cellsrplaca = replace the carrplacd = replace the cdrnconc = destructive appenddelete = destructive removensubst = destructive subst

Others“n” means “non-consing”

Generalized Variables

setf can be similarly used(setf (car lst) val)(setf (cdr lst) val)

Main reason to useefficiency

• creating new cons cells• creating garbage

Problems with Destructive Operations

Shared structure Effects hard to predict Not necessary Main reason to use

efficiencybut remember Knuth

• “Premature optimization is the root of all evil.”

Example

Look at deck after shuffle-deck

defsetf One principle of Lisp is that the

programmer has the same power as the language designer

You can create your own generalized variablesuse defsetf

Example

(defun 3rd (lst) (nth 2 lst))

(defun set-3rd (lst value) (setf (nth 2 lst) value))

(defsetf 3rd set-3rd)

(setf lst '( a b c d))

(setf (3rd lst) 'q)

lst => (a b q d)

(setf (3rd lst))

Association List

Allows lookup of values associated with keys ((key1 . val1) (key2 . val2) ... (keyn . valn))

OK for short associations large associations a hash table is better

(assoc key alist) returns the pair

(rassoc val alist) returns the pair

Keyword parameters

what if the value is not an atom?(rassoc '(21 M) '((John 21 M) (Jane 19 F) (Joe 25

M)))

doesn’t work because rassoc uses eq extra arguments to rassoc

:testspecifies which function to use instead

of default(rassoc '(21 M) '((John 21 M) (Jane 19 F) (Joe 25

M)):test #'equal)

Keyword Parameters

Many functions have these Most common

:test:key

• specifies a function to apply before testing(rassoc '21 '((John 21 M) (Jane 19 F) (Joe 25 M))

:key #'car)

:start:end

Equality Operators

= numerical equality only

eq reference equality

eql eq numbers and characters

equal tests lists element by element can be expensive!

Which one to use? if you know your data type, be specific

• (equal for lists, = for numbers, eql for everything else) if you really want reference equality, use eq

Defining Keyword Parameters (defun foo (a b &key c (d 5))

...)5 is the default value for d

can be called(foo 1 2)(foo 1 2 :c 1 :d 3)

Example

sorting handsby rankby suitallow different possibilities(sort-hand hand :test ...)

Sequences

Many of the list function also work on vectorslisp 1-D arrays

The data type that covers both lists and vectors is called the "sequence"functions that take a sequence as an

argument will operate on either

Extended Example

blackjack