Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

The Reasoned Schemer

Download as pdf or txt
Download as pdf or txt
You are on page 1of 177
At a glance
Powered by AI
The goal is to show the beauty of relational programming by extending Scheme with new constructs to combine functional and relational programming styles.

The goal of this book is to show the beauty of relational programming. We believe that it is natural to extend functional programming to relational programming.

Our main assumption is that you understand the first eight chapters of The Little Schemer. The only true requirement, however, is that you understand functions as values.

The Reasoned Schemer

The Reasoned Schemer

Daniel P. Friedman
William E. Byrd
Oleg Kiselyov
Drawings by Duane Bibby

The MIT Press


Cambridge, Massachusetts
London, England

c 2005 Massachusetts Institute of Technology


!

All rights reserved. No part of this book may be reproduced in any form by any electronic
or mechanical means (including photocopying, recording, or information storage and retrieval)
without permission in writing from the publisher.
MIT Press books may be purchased at special quantity discounts for business or sales promotional use. For information, please e-mail special sales@mitpress.mit.edu or write to
Special Sales Department, The MIT Press, 55 Hayward Street, Cambridge, Mass. 02142.
This book was set in Computer Modern by the authors using LATEX. Printed and bound in the
United States of America.
Library of Congress Cataloging-in-Publication Data
Friedman, Daniel P.
The reasoned schemer / Daniel P. Friedman, William E. Byrd, and Oleg Kiselyov; drawings
by Duane Bibby.
p. cm.
Includes index.
ISBN 0-262-56214-6 (pbk. : alk. paper)
1. Scheme (Computer program language) I. Byrd, William E. II. Kiselyov, Oleg. III. Title.
QA76.73.S34F76
005.13! 3dc22

2005

10 9 8 7 6 5 4 3 2 1

2005051092

To Mary, Sarah, Rachel, Shannon and Rob,


and to the memory of Brian.
To Mom, Dad, Brian, Mary, and Renzhong.

((Contents)
(Preface ix)
((1. Playthings) 2)
((2. Teaching Old Toys New Tricks) 16)
((3. Seeing Old Friends in New Ways) 26)
((4. Members Only) 46)
((5. Double Your Fun) 60)
((6. The Fun Never Ends . . . ) 76)
((7. A Bit Too Much) 86)
((8. Just a Bit More) 108)
((9. Under the Hood) 130)
((10. Thin Ice) 144)
(Connecting the Wires 158)
(Welcome to the Club 162)
(Index 164))

Preface
The goal of this book is to show the beauty of relational programming. We believe that it is
natural to extend functional programming to relational programming. We demonstrate this by
extending Scheme with a few new constructs, thereby combining the benefits of both styles. This
extension also captures the essence of Prolog, the most well-known logic programming language.
Our main assumption is that you understand the first eight chapters of The Little Schemer 1 .
The only true requirement, however, is that you understand functions as values. That is, a
function can be both an argument to and the value of a function call. Furthermore, you should
know that functions remember the context in which they were created. And thats itwe
assume no further knowledge of mathematics or logic. Readers of the appendix Connecting
the Wires, however, must also have a rudimentary knowledge of Scheme macros at the level of
let, and, and cond.
In order to do relational programming, we need only two constants: #s and #u, and only
three operators: , fresh, and conde . These are introduced in the first chapter and are the
only operators used until chapter 6. The additional operators we introduce are variants of these
three. In order to keep this extension simple, we mimicked existing Scheme syntax. Thus, #s
and #u are reminiscent of the Boolean constants: #t and #f; fresh expressions resemble lambda
expressions; and conde expressions are syntactically like cond expressions.
We use a few notational conventions throughout the textprimarily changes in font for
different classes of symbols. Lexical variables are in italics, forms are in boldface, data are
in sans serif, and lists are wrapped by boldfaced parentheses ((). A relation, a function that
returns a goal as its value, ends its name with a superscript o (e.g., car o and null o ). We also
use a superscript with our interface to Scheme, run, which is fully explained in the first chapter.
We have taken certain liberties with punctuation to increase clarity, such as frequently omitting
a question mark when a question ends with a special symbol. We do this to avoid confusion
with function names that might end with a question mark.
In chapters 7 and 8 we define arithmetic operators as relations. The +o relation can not
only add but also subtract; o can not only multiply but also factor numbers; and log o can not
only find the logarithm given a number and a base but also find the base given a logarithm and
a number. Just as we can define the subtraction relation from the addition relation, we can
define the exponentiation relation from the logarithm relation.
In general, given (o x y z ) we can specify what we know about these numbers (their values,
whether they are odd or even, etc.) and ask o to find the unspecified values. We dont specify
how to accomplish the task; rather, we describe what we want in the result.
1 Friedman,

Preface

Daniel P., and Matthias Felleisen. The Little Schemer, fourth ed. MIT Press, 1996.

ix

This book would not have been possible without earlier work on implementing and using
logic systems with Matthias Felleisen, Anurag Mendhekar, Jon Rossie, Michael Levin, Steve
Ganz, and Venkatesh Choppella. Steve showed how to partition Prologs named relations into
unnamed functions, while Venkatesh helped characterize the types in this early logic system.
We thank them for their effort during this developmental stage.
There are many others we wish to thank. Mitch Wand struggled through an early draft and
spent several days in Bloomington clarifying the semantics of the language, which led to the
elimination of superfluous language forms. We also appreciate Kent Dybvigs and Yevgeniy
Makarovs comments on the first few chapters of an early draft and Amr Sabrys Haskell
implementation of the language.
We gratefully acknowledge Abdulaziz Ghuloums insistence that we remove some abstract
material from the introductory chapter. In addition, Azizs suggestions significantly clarified the
run interface. Also incredibly helpful were the detailed criticisms of Chung-chieh Shan, Erik
Hilsdale, John Small, Ronald Garcia, Phill Wolf, and Jos Koot. We are especially grateful to
Chung-chieh for Connecting the Wires so masterfully in the final implementation.
We thank David Mack and Kyle Blocher for teaching this material to students in our
undergraduate programming languages course and for making observations that led to many
improvements to this book. We also thank those students who not only learned from the
material but helped us to clarify its presentation.
There are several people we wish to thank for contributions not directly related to the
ideas in the book. We would be remiss if we did not acknowledge Dorai Sitarams incredibly
clever Scheme typesetting program, SLATEX. We are grateful for Matthias Felleisens typesetting
macros (created for The Little Schemer ), and for Oscar Waddells implementation of a tool that
selectively expands Scheme macros. Also, we thank Shriram Krishnamurthi for reminding us of
a promise we made that the food would be vegetarian in the next little book. Finally, we thank
Bob Prior, our editor, for his encouragement and enthusiasm for this effort.
Food appears in examples throughout the book for two reasons. First, food is easier to
visualize than abstract symbols; we hope the food imagery helps you to better understand the
examples and concepts. Second, we want to provide a little distraction. We know how frustrating
the subject matter can be, thus these culinary diversions are for whetting your appetite. As
such, we hope that thinking about food will cause you to stop reading and have a bite.
You are now ready to start. Good luck! We hope you enjoy the book.

Bon appetit!
Daniel P. Friedman
William E. Byrd
Bloomington, Indiana
Oleg Kiselyov
Monterey, California

Preface

The Reasoned Schemer

Chapter 1

Playthings

Welcome.

Have you read The Little Schemer ?

It is good to be here.

#f.

Or The Little LISPer .

Are you sure you havent read


The Little Schemer?

Do you know about


Lambda the Ultimate?

Are you sure you have read that much of


The Little Schemer ?

Well. . .

#t.

Absolutely.

If you are familiar with recursion and know that functions


are values, you may continue anyway.

What is #s

It is a goal that succeeds.

succeed,
because it succeeds.

It is a goal that fails; it is unsuccessful.

#s is written succeed.

What is the name of #s

What is #u

#u is written fail.

Playthings

What is the name of #u

What is the value of

10

(run (q)
#u)

fail,
because it fails.

(),
since #u fails, and because the expression
(run (q) g . . . )
has the value () if any goal in g . . . fails.

This expression is written (run #f (q) #u).

What is the value of

11

(run (q)
( #t q))

(#t)),
because #t is associated with q if ( #t q)
succeeds.

( v w ) is read unify v with w and is written ==.

What is the value of

12

(run (q)
#u
( #t q))

What value is associated with q in


(run (q)
#s
( #t q))

(),
because the expression
(run (q) g . . . ( #t q))
has the value () if the goals g . . . fail.

13

#t (a Boolean value),
because the expression
(run (q) g . . . ( #t q))
associates #t with q if the goals g . . . and
( #t q) succeed.

This expression is written (run #f (q) g ...).

Thank you George Boole (18151864).

Chapter 1

Then, what is the value of

14

(run (q)
#s
( #t q))

What value is associated with r in

15

(run (r )
#s
( corn r ))

(#t)),
because #s succeeds.

corn ,
because r is associated with corn when
( corn r ) succeeds.

It should be clear from context that corn is a value; it is


not an expression. The phrase the value associated with
corresponds to the phrase the value of, but where the outer
parentheses have been removed. This is our convention for
avoiding meaningless parentheses.

corn is written as the expression (quote corn).

What is the value of

16

(run (r )
#s
( corn r ))

What is the value of

17

(run (r )
#u
( corn r ))

What is the value of

18

(run (q)
#s
( #f q))

Does

19

(corn)),
because r is associated with corn when
( corn r ) succeeds.

(),
because #u fails.

(#f)),
because #s succeeds and because run
returns a nonempty list if its goals succeed.

It depends on the value of x .

( #f x )
succeed?

Playthings

Does

20

No,
since #f is not equal to #t.

21

Yes,
since #f is equal to #f.

(let ((x #t))


( #f x ))
succeed?

This let expression is the same as


((lambda (x ) ( #f x )) #t).

We say that let binds x to #t and evaluates the body


( #f x ) using that binding.

Does
(let ((x #f))
( #f x ))
succeed?

What is the value of

22

(run (x )
(let ((x #f))
( #t x )))

What value is associated with q in

23

(run (q)
(fresh (x )
( #t x )
( #t q)))

(),
since #t is not equal to #f.

#t,
because (fresh (x . . . ) g . . . ) binds fresh
variables to x . . . and succeeds if the goals
g . . . succeed. ( v x ) succeeds when x is
fresh.

When is a variable fresh?

24

When it has no association.

Is x the only variable that starts out fresh in

25

No,
since q also starts out fresh.

(run (q)
(fresh (x )
( #t x )
( #t q)))

Chapter 1

The Law of Fresh


If x is fresh, then ( v x ) succeeds
and associates x with v .

What value is associated with q in

26

(run (q)
(fresh (x )
( x #t)
( #t q)))

What value is associated with q in

27

(run (q)
(fresh (x )
( x #t)
( q #t)))

#t,
because the order of arguments to does
not matter.

#t,
because the order of arguments to does
not matter.

The Law of

( v w ) is the same as ( w v ).

What value is associated with x in

28

(run (x )
#s)

,
a symbol representing a fresh variable.

This symbol is .0, and is created using (reify-name 0).


See the definition of reify-name in frame 52 of chapter 9
(i.e., 9:52).

Playthings

What is the value of

29

(run (x )
(let ((x #f))
(fresh (x )
( #t x ))))

What value is associated with r in

30

( 0 ),
since the x in ( #t x ) is the one
introduced by the fresh expression; it is
neither the x introduced in the run
expression nor the x introduced in the
lambda expression.
(

(run (r )
(fresh (x y)
( (cons x (cons y () )) r )))

() is (quote ()).

What value is associated with s in

31

(run (r )
(fresh (x )
(let ((y x ))
(fresh (x )
( (cons y (cons x (cons y ()))) r )))))

What value is associated with r in

33

1 ).
The expressions in this and the previous
frame differ only in the names of the
lexical variables. Therefore the values are
the same.

(run (s)
(fresh (t u)
( (cons t (cons u ())) s)))

32

Thank you, Thoralf Albert Skolem (18871963).

What value is associated with r in

).
1
For each different fresh variable there is a
symbol with an underscore followed by a
numeric subscript. This entity is not a
variable but rather is a way of showing
that the variable was fresh. We say that
such a variable has been reified .

1
0 ).
Within the inner fresh, x and y are
different variables, and since they are still
fresh, they get different reified names.

).
1
0
x
and
y are different variables, and since
(run (r )
they
are
still fresh, they get different
(fresh (x )
reified
names.
Reifying r s value reifies the
(let ((y x ))
fresh
variables
in the order in which they
(fresh (x )
( (cons x (cons y (cons x ()))) r ))))) appear in the list.
(

Chapter 1

What is the value of

34

(run (q)
( #f q)
( #t q))

What is the value of

35

(run (q)
( #f q)
( #f q))

What value is associated with q in

36

(run (q)
(let ((x q))
( #t x )))

What value is associated with r in

37

(run (r )
(fresh (x )
( x r ) ))

What value is associated with q in

38

(run (q)
(fresh (x )
( #t x )
( x q)))

What value is associated with q in


(run (q)
(fresh (x )
( x q)
( #t x )))

Playthings

39

().
The first goal ( #f q) succeeds,
associating #f with q; #t cannot then be
associated with q, since q is no longer
fresh.
(#f)).
In order for the run to succeed, both
( #f q) and ( #f q) must succeed. The
first goal succeeds while associating #f
with the fresh variable q. The second goal
succeeds because although q is no longer
fresh, #f is already associated with it.

#t,
because q and x are the same.

,
because r starts out fresh and then r gets
whatever association that x gets, but both
x and r remain fresh. When one variable
is associated with another, we say they
co-refer or share.

#t,
because q starts out fresh and then q gets
x s association.

#t,
because the first goal ensures that
whatever association x gets, q also gets.

Are q and x different variables in

40

(run (q)
(fresh (x )
( #t x )
( x q)))

Yes, they are different because both


(run (q)
(fresh (x )
( (eq? x q) q)))

and
(run (q)
(let ((x q))
(fresh (q)
( (eq? x q) x ))))
associate #f with q. Every variable
introduced by fresh (or run) is different
from every other variable introduced by
fresh (or run).

What is the value of

41

(cond
(#f #t)
(else #f))

Which #f is the value?

42

Does

43

(cond
(#f #s)
(else #u))

Thank you, Jacques Herbrand (19081931).

#f,
because the question of the first cond line
is #f, so the value of the cond expression is
determined by the answer in the second
cond line.

The one in the (else #f) cond line.

No,
it fails because the answer of the second
cond line is #u.

succeed?

10

Chapter 1

Does

44

No,
because the question of the first conde line
is the goal #u.

45

Yes,
because the question of the first conde line
is the goal #u, so conde tries the second
line.

46

Yes,
because the question of the first conde line
is the goal #s, so conde tries the answer of
the first line.

(cond
(#u #s)
(else #u))
e

succeed?

conde is written conde and is pronounced con-dee.


conde is the default control mechanism of Prolog. See
William F. Clocksin. Clause and Effect. Springer, 1997.

Does
(cond
(#u #u)
(else #s))
e

succeed?

Does
(conde
(#s #s)
(else #u))
succeed?

What is the value of


(run (x )
(conde
(( olive x ) #s)
(( oil x ) #s)
(else #u)))

Playthings

47

(olive oil)),
because ( olive x ) succeeds; therefore, the
answer is #s. The #s preserves the
association of x to olive. To get the second
value, we pretend that ( olive x ) fails;
this imagined failure refreshes x . Then
( oil x ) succeeds. The #s preserves the
association of x to oil. We then pretend
that ( oil x ) fails, which once again
refreshes x . Since no more goals succeed,
we are done.

11

The Law of conde


To get more values from conde ,
pretend that the successful conde
line has failed, refreshing all variables that got an association from
that line.

What does the e stand for in conde

What is the value of

48

49

(run1 (x )
(conde
(( olive x ) #s)
(( oil x ) #s)
(else #u)))

It stands for every line, since every line can


succeed.

(olive)),
because ( olive x ) succeeds and because
run1 produces at most one value.

This expression is written (run 1 (x ) ...).

What is the value of

50

(run (x )
(conde
(( virgin x ) #u)
(( olive x ) #s)
(#s #s)
(( oil x ) #s)
(else #u)))

In the previous run expression, which


conde line led to 0

12

(olive 0 oil)).
Once the first conde line fails, it is as if
that line were not there. Thus what results
is identical to
(conde
(( olive x ) #s)
(#s #s)
(( oil x ) #s)
(else #u)).

51

(#s #s),
since it succeeds without x getting an
association.

Chapter 1

What is the value of

52

(run (x )
(conde
(( extra x ) #s)
(( virgin x ) #u)
(( olive x ) #s)
(( oil x ) #s)
(else #u)))
2

(extra olive)),
since we do not want every value; we want
only the first two values.

When we give run a positive integer n and the run


expression terminates, it produces a list whose length is less
than or equal to n.

What value is associated with r in

53

(split pea)).

(run (r )
(fresh (x y)
( split x )
( pea y)
( (cons x (cons y ())) r )))

What is the value of

54

The list ((split pea)) (navy bean))).

(run (r )
(fresh (x y)
(conde
(( split x ) ( pea y))
(( navy x ) ( bean y))
(else #u))
( (cons x (cons y ())) r )))

What is the value of

55

The list ((split pea soup)) (navy bean soup))).

(run (r )
(fresh (x y)
(conde
(( split x ) ( pea y))
(( navy x ) ( bean y))
(else #u))
( (cons x (cons y (cons soup ()))) r )))

Playthings

13

Consider this very simple definition.

56

(tea cup)).

(define teacup o
(lambda (x )
(conde
(( tea x ) #s)
(( cup x ) #s)
(else #u))))
What is the value of
(run (x )
(teacup o x ))

Also, what is the value of

57

(run (r )
(fresh (x y)
(conde
((teacup o x ) ( #t y) #s)
(( #f x ) ( #t y))
(else #u))
( (cons x (cons y ())) r )))

((tea #t)) (cup #t)) (#f #t))).


From (teacup o x ), x gets two associations,
and from ( #f x ), x gets one association.

The question is the first goal of a line, however the answer


is the rest of the goals of the line. They must all succeed for
the line to succeed.

What is the value of


(run (r )
(fresh (x y z )
(conde
(( y x ) (fresh (x ) ( z x )))
((fresh (x ) ( y x )) ( z x ))
(else #u))
( (cons y (cons z ())) r )))

14

58

((

0
1) ( 0
1 )),
but it looks like both occurrences of 0
have come from the same variable and
similarly for both occurrences of 1 .

Chapter 1

59

Then, what is the value of


(run (r )
(fresh (x y z )
(conde
(( y x ) (fresh (x ) ( z x )))
((fresh (x ) ( y x )) ( z x ))
(else #u))
( #f x )
( (cons y (cons z ())) r )))

What is the value of

60

(run (q)
(let ((a ( #t q))
(b ( #f q)))
b))

What is the value of


(run (q)
(let ((a ( #t q))
(b (fresh (x )
( x q)
( #f x )))
(c (conde
(( #t q) #s)
(else ( #f q)))))
b))

61

((#f 0 ) ( 0 #f))),
which clearly shows that the two
occurrences of 0 in the previous frame
represent different variables.

(#f)), which shows that ( #t q) and ( #f q)


are expressions, each of whose value is a goal.
But, here we only treat the ( #f q)
expressions value, b, as a goal.

(#f)), which shows that ( . . . ), (fresh . . . ),


and (conde . . . ) are expressions, each of
whose value is a goal. But, here we only
treat the fresh expressions value, b, as a
goal. This is indeed interesting.

= Now go make yourself a peanut butter and jam sandwich. =

This space reserved for

JAM STAINS!

Playthings

15

Chapter 2

Teaching Old Toys New Tricks

What is the value of

c,

because (x y) applies (lambda (a) a) to c.

(let ((x (lambda (a) a))


(y c))
(x y))

What value is associated with r in

(run (r )
(fresh (y x )
( (x y)) r )))

It should be clear from context that this list is a value; it is


not an expression. This list could have been built (see 9:52)
using (cons (reify-name 0) (cons (reify-name 1) ())).

This list is written as the expression (,x ,y) or


(cons x (cons y ())). This list is distinguished from the
function application (x y) by the use of bold parentheses.

((

(run (r )
(fresh (v w )
( (let ((x v ) (y w )) (x y))) r )))

What is the value of

What is the value of

) ,
because the variables in (x y)) have been
introduced by fresh.

)),
0
1
because v and w are variables introduced
by fresh.

grape.

a.

a,

(car (grape raisin pear)))

What is the value of


(car (a c o r n)))

What value is associated with r in


(run (r )
(car o (a c o r n)) r ))

because a is the car of (a c o r n)).

car o is written caro and is pronounced car-oh.


Henceforth, consult the index for how we write the names of
functions.

Teaching Old Toys New Tricks

17

What value is associated with q in

(run (q)
(car o (a c o r n)) a)
( #t q))

What value is associated with r in

pear,
since x is associated with the car of (r y)),
which is the fresh variable r . Then x is
associated with pear, which in turn
associates r with pear.

Whereas car takes one argument, car o takes


two.

(run (r )
(fresh (x y)
(car o (r y)) x )
( pear x )))

Here is the definition of car o .

#t,
because a is the car of (a c o r n)).

(define car o
(lambda (p a)
(fresh (d )
( (cons a d ) p))))
What is unusual about this definition?

What is the value of

10

Thats easy: (grape a)).

(cons
(car (grape raisin pear)))
(car ((a)) (b)) (c)))))

What value is associated with r in

11

Thats the same: (grape a)).

(run (r )
(fresh (x y)
(car o (grape raisin pear)) x )
(car o ((a)) (b)) (c))) y)
( (cons x y) r )))

Why can we use cons

18

12

Because variables introduced by fresh are


values, and each argument to cons can be
any value.

Chapter 2

What is the value of

13

Thats easy: (raisin pear)).

(cdr (grape raisin pear)))

What is the value of

14

c.

15

c.

(car (cdr (a c o r n))))

What value is associated with r in


(run (r )
(fresh (v )
(cdr o (a c o r n)) v )
(car o v r )))

The process of transforming (car (cdr l ))


into (cdr o l v ) and (car o v r ) is called
unnesting.

Some readers may recognize the similarity between


unnesting and continuation-passing style.

Here is the definition of cdr o .

16

Oh. It is almost the same as car o .

(define cdr o
(lambda (p d )
(fresh (a)
( (cons a d ) p))))

What is the value of

17

Thats easy: ((raisin pear)) a)).

(cons
(cdr (grape raisin pear)))
(car ((a)) (b)) (c)))))

What value is associated with r in

18

Thats the same: ((raisin pear)) a)).

(run (r )
(fresh (x y)
(cdr o (grape raisin pear)) x )
(car o ((a)) (b)) (c))) y)
( (cons x y) r )))

Teaching Old Toys New Tricks

19

What value is associated with q in

19

(run (q)
(cdr o (a c o r n)) (c o r n)))
( #t q))

What value is associated with x in

20

#t,
because (c o r n)) is the cdr of (a c o r n)).

o,

(run (x )
(cdr o (c o r n)) (x r n))))

What value is associated with l in

21

(run (l )
(fresh (x )
(cdr o l (c o r n)))
(car o l x )
( a x )))

What value is associated with l in

22

(run (l )
(cons o (a b c)) (d e)) l ))

What value is associated with x in

23

(a c o r n)),
because if the cdr of l is (c o r n)), then l
must be the list (a c o r n)), where a is the
fresh variable introduced in the definition
of cdr o . Taking the car o of l associates the
car of l with x . When we associate x with
a, we also associate a, the car of l , with a,
so l is associated with the list (a c o r n)).
((a b c)) d e)),
since cons o associates l with
(cons (a b c)) (d e))).

d.

(run (x )
(cons o x (a b c)) (d a b c))))

What value is associated with r in

24

(run (r )
(fresh (x y z )
( (e a d x ) r )
(cons o y (a z c)) r )))

What value is associated with x in


(run (x )
(cons o x (a x c)) (d a x c))))

20

25

because (o r n)) is the cdr of (c o r n)), so x


gets associated with o.

Since (cons d (a b c))) is (d a b c)), cons o


associates x with d.

(e a d c)),
because first we associate r with a list
whose last element is the fresh variable x .
We then perform the cons o , associating x
with c, z with d, and y with e.

d.

What value can we associate with x so


that (cons x (a x c))) is (d a x c))?
Obviously, d is the value.

Chapter 2

What value is associated with l in

26

(run (l )
(fresh (x )
( (d a x c)) l )
(cons o x (a x c)) l )))

What value is associated with l in

27

(run (l )
(fresh (x )
(cons o x (a x c)) l )
( (d a x c)) l )))

Define cons o using .

28

What value is associated with l in

29

(d a d c)),
because we cons x onto (a x c)), and
associate l with the list (x a x c)). Then
when we associate l with (d a x c)), we
associate x with d.

(define cons o
(lambda (a d p)
( (cons a d ) p)))

(run (l )
(fresh (d x y w s)
(cons o w (a n s)) s)
(cdr o l s)
(car o l x )
( b x )
(cdr o l d )
(car o d y)
( e y)))

What is the value of

(d a d c)),
because l is (d a x c)). Then when we
cons o x onto (a x c)), we associate x with
d.

30

(b e a n s)).
l must clearly be a five element list, since s
is (cdr l ). Since l is fresh, (cdr o l s) places
a fresh variable in the first position of l ,
while associating w and (a n s)) with the
second position and the cdr of the cdr of l ,
respectively. The first variable in l gets
associated with x , which in turn gets
associated with b. The cdr of l is a list
whose car is the variable w . That variable
gets associated with y, which in turn gets
associated with e.

#f.

(null? (grape raisin pear)))

What is the value of

31

#t.

(null? ())

Teaching Old Toys New Tricks

21

What is the value of

32

().

(run (q)
(null o (grape raisin pear)))
( #t q))

What is the value of

33

(#t)).

(run (q)
(null o ())
( #t q))

What is the value of

34

(()).

(run (x )
(null o x ))

Define null o using .

35

What is the value of

36

(define null o
(lambda (x )
( () x )))

#f.

(eq? pear plum)

What is the value of

37

#t.

(eq? plum plum)

What is the value of

38

().

(run (q)
(eq o pear plum)
( #t q))

22

Chapter 2

What is the value of

39

(#t)).

(run (q)
(eq o plum plum)
( #t q))

Define eq o using .

40

It is easy.
(define eq o
(lambda (x y)
( x y)))

Is (split ! pea)) a pair?

41

Yes.

Is (split ! x ) a pair?

42

Yes.

What is the value of

43

#t.

(pair? ((split)) ! pea)))

What is the value of

44

#f.

(pair? ())

Is pair a pair?

45

No.

Is pear a pair?

46

No.

47

Yes,
it is the pair (pear ! ()).

48

pear.

Is (pear)) a pair?

What is the value of


(car (pear)))

Teaching Old Toys New Tricks

23

What is the value of

49

().

(cdr (pear)))

How can we build these pairs?

50

Use Cons the Magnificent.

What is the value of

51

((split)) ! pea)).

(cons (split)) pea)

What value is associated with r in

52

! salad)).

(run (r )
(fresh (x y)
( (cons x (cons y salad)) r )))

Here is the definition of pair o .

53

No, it is not.

(define pair o
(lambda (p)
(fresh (a d )
(cons o a d p))))
Is pair o recursive?

What is the value of

54

(#t)).

(run (q)
(pair o (cons q q))
( #t q))

What is the value of

55

().

(run (q)
(pair o ())
( #t q))

24

Chapter 2

56

What is the value of

().

(run (q)
(pair o pair)
( #t q))

What value is associated with x in

57

).

(run (x )
(pair o x ))

What value is associated with r in

58

(run (r )
(pair o (cons r pear)))

Is it possible to define car o , cdr o , and pair o


using cons o

59

Yes.

This space reserved for

Conso the Magnificento

Teaching Old Toys New Tricks

25

Chapter 3

Seeing Old Friends in New Ways

Consider the definition of list?.

#t.

(define list?
(lambda (l )
(cond
((null? l ) #t)
((pair? l ) (list? (cdr l )))
(else #f))))
What is the value of
(list? ((a)) (a b)) c)))

What is the value of

#t.

(list? ())

What is the value of

#f.

(list? s)

What is the value of

(list? (d a t e ! s)))

#f,
because (d a t e ! s)) is not a proper list.

Consider the definition of list o .


(define list o
(lambda (l )
(conde
((null o l ) #s)
((pair o l )
(fresh (d )
(cdr o l d )
(list o d )))
(else #u))))
How does list o differ from list?

Seeing Old Friends in New Ways

A list is proper if it is the empty list or if its cdr is proper.

The definition of list? has Boolean values as


questions and answers. list o has goals as
questions and answers. Hence, it uses
conde instead of cond.

else is like #t in a cond line, whereas else is like #s in a


conde line.

27

Where does
(fresh (d )
(cdr o l d )
(list o d ))

It is an unnesting of (list? (cdr l )). First we


take the cdr of l and associate it with a fresh
variable d , and then we use d in the
recursive call.

come from?

The First Commandment


To transform a function whose value is a Boolean
into a function whose value is a goal, replace cond
with conde and unnest each question and answer.
Unnest the answer #t (or #f) by replacing it with #s
(or #u).

What value is associated with x in

(run (x )
(list o (a b x d)) ))

,
since x remains fresh.

where a, b, and d are symbols, and x is a


variable.

Reminder: This is the same as (a b ,x d)


).

Why is

the value associated with x in

When determining the goal returned by list o ,


it is not necessary to determine the value of
x . Therefore x remains fresh, which means
that the goal returned from the call to list o
succeeds for all values associated with x .

When list o reaches the end of its argument,


it succeeds. But x does not get associated
with any value.

(run (x )
(list o (a b x d))))

How is

the value associated with x in

(run (x )
(list o (a b x d))))

28

Chapter 3

What value is associated with x in

10

().

(run (x )
(list o (a b c ! x )))
1

Why is () the value associated with x in

11

Because (a b c ! x ) is a proper list when x is


the empty list.

12

When list o reaches the end of (a b c ! x ),


(null o x ) succeeds and associates x with the
empty list.

13

It has no value.
Maybe we should use run5 to get the first
five values.

(run (x )
(list o (a b c ! x )))
1

How is () the value associated with x in


(run1 (x )
(list o (a b c ! x )))

What is the value of


(run (x )
(list o (a b c ! x )))

What is the value of

14

(run (x )
(list o (a b c ! x )))
5

Describe what we have seen in transforming


list? into list o .

Seeing Old Friends in New Ways

15

(()
( 0)
( 0 1)
( 0 1 2)
( 0 1 2 3 )).

In list? each cond line results in a value,


whereas in list o each conde line results in a
goal. To have each conde result in a goal, we
unnest each cond question and each cond
answer. Used with recursion, a conde
expression can produce an unbounded
number of values. We have used an upper
bound, 5 in the previous frame, to keep from
creating a list with an unbounded number of
values.

29

Consider the definition of lol?, where lol?


stands for list-of-lists?.

16

As long as each top-level value in the list l is


a proper list, lol? returns #t. Otherwise, lol?
returns #f.

17

The definition of lol? has Boolean values as


questions and answers. lol o has goals as
questions and answers. Hence, it uses conde
instead of cond.

(define lol?
(lambda (l )
(cond
((null? l ) #t)
((list? (car l )) (lol? (cdr l )))
(else #f))))
Describe what lol? does.

Here is the definition of lol o .


(define lol o
(lambda (l )
(conde
((null o l ) #s)
((fresh (a)
(car o l a)
(list o a))
(fresh (d )
(cdr o l d )
(lol o d )))
(else #u))))
How does lol o differ from lol?

What else is different?

Is the value of (lol o l ) always a goal?

What is the value of


(run1 (l )
(lol o l ))

30

18

19

20

(list? (car l )) and (lol? (cdr l )) have been


unnested.

Yes.

(()).
Since l is fresh, (null o l ) succeeds and in
the process associates l with ().

Chapter 3

What value is associated with q in

21

(run (q)
(fresh (x y)
(lol o ((a b)) (x c)) (d y))))
( #t q)))

What value is associated with q in

22

(run (q)
(fresh (x )
(lol o ((a b)) ! x ))
( #t q)))
1

What is the value of

23

(run (x )
(lol o ((a b)) (c d)) ! x )))
1

What is the value of

24

(run (x )
(lol o ((a b)) (c d)) ! x )))
5

What do we get when we replace x by the


last list in the previous frame?

25

#t,
since ((a b)) (x c)) (d y))) is a list of lists.

#t,
because null o of a fresh variable always
succeeds and associates the fresh variable,
in this case x , with ().

(()),
since replacing x with the empty list in
((a b)) (c d)) ! x ) transforms it to
((a b)) (c d)) ! ()), which is the same as
((a b)) (c d))).

(()
(())
(() ())
(() () ())
(() () () ())).

((a b)) (c d)) ! (() () () ())),


which is the same as
((a b)) (c d)) () () () ()).

Is (tofu tofu)) a twin?

Is (e tofu)) a twin?

Seeing Old Friends in New Ways

26

Yes,
because it is a list of two identical values.

27

No,
because e and tofu differ.

31

Is (g g g)) a twin?

Is ((g g)) (tofu tofu))) a list of twins?

Is ((g g)) (e tofu))) a list of twins?

Consider the definition of twins o .

28

No,
because it is not a list of two values.

29

Yes,
since both (g g)) and (tofu tofu)) are twins.

30

No,
since (e tofu)) is not a twin.

31

No, it isnt.

(define twins o
(lambda (s)
(fresh (x y)
(cons o x y s)
(cons o x () y))))
Is twins o recursive?

What value is associated with q in

32

#t.

(run (q)
(twins o (tofu tofu)))
( #t q))

What value is associated with z in

33

tofu.

(run (z )
(twins o (z tofu))))

Why is tofu the value associated with z in


(run (z )
(twins o (z tofu))))

32

34

Because (z tofu)) is a twin only when z is


associated with tofu.

Chapter 3

How is tofu the value associated with z in

35

In the call to twins o the first cons o


associates x with the car of (z tofu)), which is
z , and associates y with the cdr of (z tofu)),
which is (tofu)). Remember that (tofu)) is the
same as (tofu ! ()). The second cons o
associates x , and therefore z , with the car of
y, which is tofu.

36

Here it is.

(run (z )
(twins o (z tofu))))

Redefine twins o without using cons o .

(define twins o
(lambda (s)
(fresh (x )
( (x x ) s))))

Consider the definition of lot o .

37

lot stands for list-of-twins.

(define lot o
(lambda (l )
(conde
((null o l ) #s)
((fresh (a)
(car o l a)
(twins o a))
(fresh (d )
(cdr o l d )
(lot o d )))
(else #u))))
What does lot stand for?
What value is associated with z in

38

().

(run (z )
(lot o ((g g)) ! z )))
1

Why is () the value associated with z in


(run (z )
(lot o ((g g)) ! z )))
1

Seeing Old Friends in New Ways

39

Because ((g g)) ! z ) is a list of twins when z


is the empty list.

33

What do we get when we replace z by ()

40

((g g)) ! ()),


which is the same as
((g g))).

How is () the value associated with z in

41

(run1 (z )
(lot o ((g g)) ! z )))

42

What is the value of


(run (z )
(lot o ((g g)) ! z )))
5

Why are the nonempty values (

n)

What do we get when we replace z by the


fourth list in frame 42?

In the first call to lot o , l is the list


((g g)) ! z ). Since this list is not null,
(null o l ) fails and we move on to the second
conde line. In the second conde line, d is
associated with the cdr of ((g g)) ! z ), which
is z . The variable d is then passed in the
recursive call to lot o . Since the variable z
associated with d is fresh, (null o l ) succeeds
and associates d and therefore z with the
empty list.

(()
((
((
((
((

))
)(
0) (
0) (

0
0

(run (r )
(fresh (w x y z )
(lot o ((g g)) (e w ) (x y)) ! z ))
( (w (x y)) z ) r )))
5

34

))
)(

))).

43

Each n corresponds to a fresh variable that


has been introduced in the question of the
second conde line of lot o .

44

((g g)) ! ((

)(

)(

))),

which is the same as


((g g)) (

What is the value of

))
)(
1) (

45

((e
(e
(e
(e
(e

(
(
(
(
(

0
0
0
0
0

)
0)
0)
)
0
)
0
0

)(

())
(( 1
(( 1
(( 1
(( 1

)(

)))
)(2
)(2
1
)(2
1
1
1

)).

)))
)(3
)(3
2
2
2

3
3

)))
)(4

)))).

Chapter 3

What do we get when we replace w , x , y,


and z by the third list in the previous frame?

46

((g g)) (e e)) (


((g g)) (e e)) (

What is the value of

47

(run (out)
(fresh (w x y z )
( ((g g)) (e w ) (x y)) ! z ) out)
(lot o out)))
3

Here is listof o .

) ! ((

)(

))),

which is the same as

48

(((g g)) (e e)) (


((g g)) (e e)) (
((g g)) (e e)) (

)(

))
)(
)(
0

)(

)).

))
)(
1

))).

))
)(

))).

Yes.

(define listof o
(lambda (pred o l )
(conde
((null o l ) #s)
((fresh (a)
(car o l a)
(pred o a))
(fresh (d )
(cdr o l d )
(listof o pred o d )))
(else #u))))
Is listof o recursive?

What is the value of

49

(run (out)
(fresh (w x y z )
( ((g g)) (e w ) (x y)) ! z ) out)
(listof o twins o out)))
3

Now redefine lot o using listof o and twins o .

50

(((g g)) (e e)) (


((g g)) (e e)) (
((g g)) (e e)) (

))
)(
)(
0

Thats simple.
(define lot o
(lambda (l )
(listof o twins o l )))

Seeing Old Friends in New Ways

35

Remember member?

51

(define member?
(lambda (x l )
(cond
((null? l ) #f)
((eq-car? l x ) #t)
(else (member? x (cdr l ))))))

member? is an old friend, but thats a


strange way to define it.
(define eq-car?
(lambda (l x )
(eq? (car l ) x )))

Define eq-car?.
Dont worry. It will make sense soon.

52

Okay.

What is the value of

53

#t, but this is uninteresting.

(member? olive (virgin olive oil)))


Consider this definition of eq-car o .

54

(define member o
(lambda (x l )
(conde
((null o l ) #u)
((eq-car o l x ) #s)
(else
(fresh (d )
(cdr o l d )
(member o x d ))))))

(define eq-car
(lambda (l x )
(car o l x )))
o

Define member o using eq-car o .

Is the first conde line unnecessary?

55

Which expression has been unnested?

56

What value is associated with q in

57

(run (q)
(member o olive (virgin olive oil)))
( #t q))

36

Yes.
Whenever a conde line is guaranteed to
fail, it is unnecessary.
(member? x (cdr l )).
#t,
because (member o a l ) succeeds, but this
is still uninteresting.

Chapter 3

What value is associated with y in

58

(run (y)
(member o y (hummus with pita))))
1

What value is associated with y in

59

(run1 (y)
(member o y (with pita))))

What value is associated with y in

60

(run (y)
(member o y (pita))))
1

What is the value of

61

(run (y)
(member o y ()))

What is the value of

62

(run (y)
(member o y (hummus with pita))))

Why is y a fresh variable each time we enter


member o recursively?

Seeing Old Friends in New Ways

63

hummus,
because we can ignore the first conde line
since l is not the empty list, and because
the second conde line associates the fresh
variable y with the value of (car l ), which
is hummus.

with,
because we can ignore the first conde line
since l is not the empty list, and because
the second conde line associates the fresh
variable y with the value of (car l ), which
is with.

pita,
because we can ignore the first conde line
since l is not the empty list, and because
the second conde line associates the fresh
variable y with the value of (car l ), which
is pita.

(),
because the (null o l ) question of the first
conde line now holds, resulting in failure
of the goal (member o y l ).

(hummus with pita)),


since we already know the value of each
recursive call to member o , provided y is
fresh.

Since we pretend that the second conde line


has failed, we also get to assume that y has
been refreshed.

37

So is the value of

64

Yes.

(run (y)
(member o y l ))

always the value of l

Using run , define a function called identity


whose argument is a list, and which returns
that list.

65

What value is associated with x in

66

(define identity
(lambda (l )
(run (y)
(member o y l ))))

e.

(run (x )
(member o e (pasta x fagioli))))

Why is e the value associated with x in

67

(run (x )
(member o e (pasta x fagioli))))

What have we just done?

68

What value is associated with x in

69

Because (member o e (pasta e fagioli)))


succeeds.

We filled in a blank in the list so that


member o succeeds.

(run1 (x )
(member o e (pasta e x fagioli))))

What value is associated with x in


(run1 (x )
(member o e (pasta x e fagioli))))

38

70

The list contains three values with a


variable in the middle. The member o
function determines that x s value should
be e.

e,

,
because the recursion succeeds before it
gets to the variable x .

because the recursion succeeds when it


gets to the variable x .

Chapter 3

71

What is the value of

((e

)(

e))).

(run (r )
(fresh (x y)
(member o e (pasta x fagioli y)))
( (x y)) r )))

What does each value in the list mean?

72

There are two values in the list. We know


from frame 70 that when x gets associated
with e, (member o e (pasta x fagioli y)))
succeeds, leaving y fresh. Then x is
refreshed. For the second value, y gets an
association, but x does not.

What is the value of

73

((tofu !

)).

(run (l )
(member o tofu l ))
1

Which lists are represented by (tofu !

What is the value of

74

Every list whose car is tofu.

75

It has no value,
because run never finishes building the
list.

76

((tofu ! 0 )
( 0 tofu ! 1 )
( 0 1 tofu ! 2 )
( 0 1 2 tofu ! 3 )
( 0 1 2 3 tofu ! 4 )).
Clearly each list satisfies member o , since
tofu is in every list.

(run (l )
(member o tofu l ))

What is the value of


(run (l )
(member o tofu l ))
5

Seeing Old Friends in New Ways

39

77

Assume that we know how the first four lists


are determined. Now we address how the
fifth list appears. When we pretend that
eq-car o fails, l is refreshed and the last
conde line is tried. l is refreshed, but we
recur on its cdr, which is also fresh. So each
value becomes one longer than the previous
value. In the recursive call (member o x d ),
the call to eq-car o associates tofu with the
car of the cdr of l . Thus 3 will appear where
tofu appeared in the fourth list.

Is it possible to remove the dotted variable at


the end of each list, making it proper?

78

Perhaps,
but we do know when weve found the
value were looking for.

Yes, thats right. That should give us enough


of a clue. What should the cdr be when we
find this value?

79

It should be the empty list if we find the


value at the end of the list.

Here is a definition of pmember o .

80

Explain why the answer is


((tofu ! 0 )
( 0 tofu ! 1 )
( 0 1 tofu ! 2 )
( 0 1 2 tofu ! 3 )
( 0 1 2 3 tofu ! 4 ))

(define pmember o
(lambda (x l )
(conde
((null o l ) #u)
((eq-car o l x ) (cdr o l ()))
(else
(fresh (d )
(cdr o l d )
(pmember o x d ))))))

((tofu))
( 0 tofu))
( 0 1 tofu))
( 0 1 2 tofu))
( 0 1 2 3 tofu))).

What is the value of


(run5 (l )
(pmember o tofu l ))

40

Chapter 3

What is the value of

81

Is it (#t #t))?

(run (q)
(pmember o tofu (a b tofu d tofu)))
( #t q))

No, the value is (#t)). Explain why.

Here is a refined definition of pmember o .

82

The test for being at the end of the list


caused this definition to miss the first tofu.

83

We have included an additional conde line


that succeeds when the car of l matches x .

(define pmember o
(lambda (x l )
(conde
((null o l ) #u)
((eq-car o l x ) (cdr o l ()))
((eq-car o l x ) #s)
(else
(fresh (d )
(cdr o l d )
(pmember o x d ))))))
How does this refined definition differ from
the original definition of pmember o

What is the value of

84

Is it (#t #t))?

(run (q)
(pmember o tofu (a b tofu d tofu)))
( #t q))

No, the value is (#t #t #t)). Explain why.

Seeing Old Friends in New Ways

85

The second conde line contributes a value


because there is a tofu at the end of the list.
Then the third conde line contributes a
value for the first tofu in the list and it
contributes a value for the second tofu in the
list. Thus in all, three values are contributed.

41

86

We have included a test to make sure that its


cdr is not the empty list.

How can we simplify this definition a bit


more?

87

We know that a conde line that always fails,


like the first conde line, can be removed.

Now what is the value of

88

Here is a more refined definition of


pmember o .
(define pmember o
(lambda (x l )
(conde
((null o l ) #u)
((eq-car o l x ) (cdr o l ()))
((eq-car o l x )
(fresh (a d )
(cdr o l (a ! d ))))
(else
(fresh (d )
(cdr o l d )
(pmember o x d ))))))
How does this definition differ from the
previous definition of pmember o

(#t #t)) as expected.

(run (q)
(pmember o tofu (a b tofu d tofu)))
( #t q))

Now what is the value of


(run (l )
(pmember o tofu l ))
12

42

89

((tofu))
(tofu 0 ! 1 )
( 0 tofu))
( 0 tofu 1 ! 2 )
( 0 1 tofu))
( 0 1 tofu 2 ! 3 )
( 0 1 2 tofu))
( 0 1 2 tofu 3 ! 4 )
( 0 1 2 3 tofu))
( 0 1 2 3 tofu 4 ! 5 )
( 0 1 2 3 4 tofu))
( 0 1 2 3 4 tofu 5 ! 6 )).

Chapter 3

How can we characterize this list of values?

90

All of the odd positions are proper lists.

Why are the odd positions proper lists?

91

Because in the second conde line the cdr of l


is the empty list.

Why are the even positions improper lists?

92

Because in the third conde line the cdr of l


is a pair.

How can we redefine pmember o so that the


lists in the odd and even positions are
swapped?

93

We merely swap the first two conde lines of


the simplified definition.

Now what is the value of

94

(run (l )
(pmember o tofu l ))
12

Seeing Old Friends in New Ways

(define pmember o
(lambda (x l )
(conde
((eq-car o l x )
(fresh (a d )
(cdr o l (a ! d ))))
((eq-car o l x ) (cdr o l ()))
(else
(fresh (d )
(cdr o l d )
(pmember o x d ))))))

((tofu 0 ! 1 )
(tofu))
( 0 tofu 1 ! 2 )
( 0 tofu))
( 0 1 tofu 2 ! 3 )
( 0 1 tofu))
( 0 1 2 tofu 3 ! 4 )
( 0 1 2 tofu))
( 0 1 2 3 tofu 4 ! 5 )
( 0 1 2 3 tofu))
( 0 1 2 3 4 tofu 5 ! 6 )
( 0 1 2 3 4 tofu))).

43

Consider the definition of first-value, which


takes a list of values l and returns a list that
contains the first value in l .

95

(define first-value
(lambda (l )
(run1 (y)
(member o y l ))))

If l is the empty list or not a list,


(first-value l ) returns (), whereas with car
there is no meaning. Also, instead of
returning the first value, it returns the list of
the first value.

Given that its argument is a list, how does


first-value differ from car
What is the value of

96

(pasta)).

(first-value (pasta e fagioli)))


What value is associated with y in

97

pasta.

(first-value (pasta e fagioli)))


Consider this variant of member o .

98

(define memberrev o
(lambda (x l )
(conde
((null o l ) #u)
(#s
(fresh (d )
(cdr o l d )
(memberrev o x d )))
(else (eq-car o l x )))))

Clearly, #s corresponds to else. The (eq-car o l x ) is now


the last question, so we can insert an else to improve clarity.
We havent swapped the expressions in the second conde
line of memberrev o , but we could have, since we can add or
remove #s from a conde line without affecting the line.

How does it differ from the definition of


member o in frame 54?
How can we simplify this definition?

What is the value of

We have swapped the second conde line with


the third conde line .

99

100

By removing a conde line that is guaranteed


to fail.
(fagioli e pasta)).

(run (x )
(memberrev o x (pasta e fagioli))))

44

Chapter 3

Define reverse-list, which reverses a list,


using the definition of memberrev o .

101

Here it is.
(define reverse-list
(lambda (l )
(run (y)
(memberrev o y l ))))

= Now go make yourself a peanut butter and marmalade sandwich. =

This space reserved for

MARMALADE STAINS!

Seeing Old Friends in New Ways

45

Chapter 4

Members Only

Consider this very simple function.

(tofu d peas e)).

(define mem
(lambda (x l )
(cond
((null? l ) #f)
((eq-car? l x ) l )
(else (mem x (cdr l ))))))
What is the value of
(mem tofu (a b tofu d peas e)))

What is the value of

#f.

(mem tofu (a b peas d peas e)))

What value is associated with out in

(tofu d peas e)).

(run (out)
( (mem tofu (a b tofu d peas e))) out))

What is the value of

(peas e)).

(mem peas
(mem tofu (a b tofu d peas e))))

What is the value of

(mem tofu
(mem tofu (a b tofu d tofu e))))

What is the value of


(mem tofu
(cdr (mem tofu (a b tofu d tofu e)))))

Members Only

(tofu d tofu e)),


because the value of
(mem tofu (a b tofu d tofu e))) is
(tofu d tofu e)), and because the value of
(mem tofu (tofu d tofu e))) is
(tofu d tofu e)).

(tofu e)),
because the value of
(mem tofu (a b tofu d tofu e))) is
(tofu d tofu e)), the value of
(cdr (tofu d tofu e))) is (d tofu e)), and the
value of (mem tofu (d tofu e))) is (tofu e)).

47

Here is memo .
(define memo
(lambda (x l out)
(conde
((null o l ) #u)
((eq-car o l x ) ( l out))
(else
(fresh (d )
(cdr o l d )
(memo x d out))))))

The list?, lol?, and member? definitions from


the previous chapter have only Booleans as
their values, but mem, on the other hand,
does not. Because of this we need an
additional variable, which here we call out,
that holds memo s value.

How does memo differ from list o , lol o , and


member o
Which expression has been unnested?

(mem x (cdr l )).

The Second Commandment


To transform a function whose value is not a
Boolean into a function whose value is a goal, add
an extra argument to hold its value, replace cond
with conde , and unnest each question and answer.

In a call to memo from run1 , how many


times does out get an association?
What is the value of

10

At most once.

((tofu d tofu e))).

(run (out)
(memo tofu (a b tofu d tofu e)) out))
1

What is the value of


(run (out)
(fresh (x )
(memo tofu (a b x d tofu e)) out)))
1

48

11

((tofu d tofu e))), which would be correct if x


were tofu.

Chapter 4

What value is associated with r in

12

tofu.

(run (r )
(memo r
(a b tofu d tofu e))
(tofu d tofu e))))

What value is associated with q in

13

(run (q)
(memo tofu (tofu e)) (tofu e)))
( #t q))

What is the value of

14

(run (q)
(memo tofu (tofu e)) (tofu)))
( #t q))

What value is associated with x in

15

(run (x )
(memo tofu (tofu e)) (x e))))

What is the value of

16

(run (x )
(memo tofu (tofu e)) (peas x )))

What is the value of

17

#t,
since (tofu e)), the last argument to memo ,
is the right value.

(),
since (tofu)), the last argument to memo , is
the wrong value.

tofu,
when the value associated with x is tofu,
then (x e)) is (tofu e)).

(),
because there is no value that, when
associated with x , makes (peas x ) be
(tofu e)).

((tofu d tofu e)) (tofu e))).

(run (out)
(fresh (x )
(memo tofu (a b x d tofu e)) out)))

Members Only

49

18

What is the value of


(run (z )
(fresh (u)
(memo tofu (a b tofu d tofu e ! z ) u)))
12

How do we get the first two

s?

Where do the other ten lists come from?

0
0

(tofu ! 0 )
( 0 tofu ! 1 )
( 0 1 tofu ! 2 )
( 0 1 2 tofu ! 3 )
( 0 1 2 3 tofu ! 4 )
( 0 1 2 3 4 tofu ! 5 )
( 0 1 2 3 4 5 tofu ! 6 )
( 0 1 2 3 4 5 6 tofu ! 7 )
( 0 1 2 3 4 5 6 7 tofu ! 8 )
( 0 1 2 3 4 5 6 7 8 tofu ! 9 )).

19

The first 0 corresponds to finding the first


tofu. The second 0 corresponds to finding
the second tofu.

20

In order for
(memo tofu (a b tofu d tofu e ! z ) u)
to succeed, there must be a tofu in z . So
memo creates all the possible lists with tofu
as one element of the list. Thats very
interesting!

How can memo be simplified?

21

The first conde line always fails, so it can be


removed.
(define memo
(lambda (x l out)
(conde
((eq-car o l x ) ( l out))
(else
(fresh (d )
(cdr o l d )
(memo x d out))))))

50

Chapter 4

Remember rember.

22

Of course, its an old friend.

(define rember
(lambda (x l )
(cond
((null? l ) ())
((eq-car? l x ) (cdr l ))
(else
(cons (car l )
(rember x (cdr l )))))))

What is the value of

23

(a b d peas e)).

(rember peas (a b peas d peas e)))


Consider rember o .

24

Yes, just like rember.

(define rember o
(lambda (x l out)
(conde
((null o l ) ( () out))
((eq-car o l x ) (cdr o l out))
(else
(fresh (res)
(fresh (d )
(cdr o l d )
(rember o x d res))
(fresh (a)
(car o l a)
(cons o a res out)))))))
Is rember o recursive?
Why are there three freshes in
(fresh (res)
(fresh (d )
(cdr o l d )
(rember o x d res))
(fresh (a)
(car o l a)
(cons o a res out)))

Members Only

25

Because d is only mentioned in (cdr o l d )


and (rember o x d res); a is only mentioned
in (car o l a) and (cons o a res out); but res
is mentioned throughout.

51

Rewrite

26

(fresh (res)
(fresh (d )
(cdr o l d )
(rember o x d res))
(fresh (a)
(car o l a)
(cons o a res out)))

(fresh (a d res)
(cdr o l d )
(rember o x d res)
(car o l a)
(cons o a res out)).

using only one fresh.

How might we use cons o in place of the car o


and the cdr o

27

How does the first cons o differ from the


second one?

28

But, can appearances be deceiving?

29

What is the value of

30

(run (out)
(fresh (y)
(rember o peas (a b y d peas e)) out)))
1

52

(fresh (a d res)
(cons o a d l )
(rember o x d res)
(cons o a res out)).

The first cons o , (cons o a d l ), appears to


associate values with the variables a and d .
In other words, it appears to take apart a
cons pair, whereas (cons o a res out) appears
to be used to build a cons pair.

Indeed they can.

((a b d peas e))),


because y is a variable and can take on
values. The car o within the (eq-car o l x )
associates y with peas, forcing y to be
removed from the list. Of course we can
associate with y a value other than peas.
That will still cause
(rember o peas (a b y d peas e)) out) to
succeed, but run1 produces only one value.

Chapter 4

What is the value of

31

(run (out)
(fresh (y z )
(rember o y (a b y d z e)) out)))

((b a
(a b
(a b
(a b
(a b
(a b
(a b

e))
e))
)
0 e)
)
0 e)
d
e)
)
0
e d 0)
d 1 e))).
0

d
d
d
d

0
0

32

It looks like b and a have been swapped, and


y has disappeared.

No. Why does b come first?

33

The b comes first because the a has been


removed.

Why does the list still contain a

34

In order to remove the a, y gets associated


with a. The y in the list is then replaced
with its value.

Why is

35

It looks like y has disappeared.

No. Has the b in the original list been


removed?

36

Yes.

Why does the list still contain a b

37

In order to remove the b, y gets associated


with b. The y in the list is then replaced
with its value.

Why is

38

Why is
(b a d

e))

the first value?

(a b d

e))

the second value?

(a b d

e))

Is it for the same reason that (a b d


the second value?

e)) is

the third value?

Members Only

53

Not quite. Has the b in the original list been


removed?

39

No,
but the y has been removed.

Why is

40

Because the d has been removed from the


list.

Why does the list still contain a d

41

In order to remove the d, y gets associated


with d. Also the y in the list is replaced with
its value.

Why is

42

Because the z has been removed from the


list.

(a b d

e))

the fourth value?

(a b

d e))

the fifth value?

Why does the list contain

43
0

44

Why is
(a b e d

When (car l ) is y, (car o l a) associates the


fresh variable y with the fresh variable a. In
order to remove the y, y gets associated with
z . Since z is also a fresh variable, the a, y,
and z co-refer.

Because the e has been removed from the list.

the sixth value?

Why does the list contain

45
0

Why dont z and y co-refer?

54

46

When (car l ) is z , (car o l a) associates the


fresh variable z with the fresh variable a.

Because we are within a run , we get to


pretend that (eq-car o l x ) fails when (car l )
is z and x is y. Thus z and y no longer
co-refer.

Chapter 4

47

Why is
(a b

e))

Because we have not removed anything from


the list.

the seventh value?

Why does the list contain

and

48
1

What is the value of

49

(run (r )
(fresh (y z )
(rember o y (y d z e)) (y d e)))
( (y z ) r )))

50

Why is

51

Why is

When y is d and z is d, then


(rember o d (d d d e)) (d d e)))

(d d))
the second value?

succeeds.
52

Why is
0

When y is d and z is d, then


succeeds.

the first value?

((d d))
(d d))
( 0 0)
(e e))).

(rember o d (d d d e)) (d d e)))

(d d))

When (car l ) is y, (car o l a) associates the


fresh variable y with the fresh variable a.
When (car l ) is z , (car o l a) associates the
fresh variable z with a new fresh variable a.
Also the y and z in the list are replaced
respectively with their reified values.

As long as y and z are the same, y can be


anything.

the third value?

How is
(d d))
the first value?

Members Only

53

rember o removes y from the list (y d z e)),


yielding the list (d z e)); (d z e)) is the same
as out, (y d e)), only when both y and z are
the value d.

55

How is

54

Next, rember o removes d from the list


(y d z e)), yielding the list (y z e)); (y z e)) is
the same as out, (y d e)), only when z is d.
Also, in order to remove the d, y gets
associated with d.

55

Next, rember o removes z from the list


(y d z e)), yielding the list (y d e)); (y d e)) is
always the same as out, (y d e)). Also, in
order to remove the z , y gets associated with
z , so they co-refer.

56

Next, rember o removes e from the list


(y d z e)), yielding the list (y d z ); (y d z ) is
the same as out, (y d e)), only when z is e.
Also, in order to remove the e, y gets
associated with e.

(d d))
the second value?

How is
(

the third value?

How is
(e e))
the fourth value?

What is the value of

57

(run (w )
(fresh (y z out)
(rember o y (a b y d z ! w ) out)))
13

0
0
0
0
0

()
( 0 ! 1)
( 0)
( 0 1 ! 2)
( 0 1)
( 0 1 2 ! 3)
( 0 1 2)
( 0 1 2 3 ! 4 )).

Why is
0

the first value?

58

When y is a, out becomes (b y d z ! w ),


which makes
(rember o y (a b y d z ! w ) (b y d z ! w ))
succeed for all values of w .

56

Chapter 4

How is

59

rember o removes a from l , while ignoring the


fresh variable w .

60

This is the same as in the previous frame,


except that rember o removes b from the
original l , y from the original l , and d from
the original l , respectively.

61

Next, rember o removes z from l . When the


(eq-car o l x ) question of the second conde
line succeeds, (car l ) is z . The answer of the
second conde line, (cdr o l out), also
succeeds, associating the cdr of l (the fresh
variable w ) with the fresh variable out. The
variable out, however, is just res, the fresh
variable passed into the recursive call to
rember o .

62

Because none of the first five values in l are


removed. The (null o l ) question of the first
conde line then succeeds, associating w with
the empty list.

63

Because none of the first five values in l are


removed, and because we pretend that the
(null o l ) question of the first conde line
fails. The (eq-car o l x ) question of the
second conde line succeeds, however, and
associates w with a pair whose car is y. The
answer (cdr o l out) of the second conde line
also succeeds, associating w with a pair
whose cdr is out. The variable out, however,
is just res, the fresh variable passed into the
recursive call to rember o . During the
recursion, the car o inside the second conde
lines eq-car o associates the fresh variable y
with the fresh variable a.

the first value?

How is
0

the second, third, and fourth value?

How is
0

the fifth value?

How is
()
the sixth value?

How is
(

the seventh value?

Members Only

57

64

This is the same as the seventh value,


( 0 ! 1 ), except that the (null o l ) question of
the first conde line succeeds, associating out
(and, therefore, res) with the empty list.

65

For the same reason that ( 0 ! 1 ) is the


seventh value, except that the ninth value
performs an additional recursive call, which
results in an additional cons o .

Do the tenth and twelfth values correspond


to the eighth value?

66

Yes.

Do the eleventh and thirteenth values


correspond to the ninth value?

67

Yes.
All w of the form

How is
( 0)
the eighth value?

How is
(

the ninth value?

...

n+1

make (rember y (a b y d z ! w ) out)


succeed.
o

Here is surprise o .

68

(define surprise o
(lambda (s)
(rember o s (a b c)) (a b c)))))

Yes, (surprise o s) should succeed for all


values of s other than a, b, and c.

Are there any values of s for which


(surprise o s) should succeed?

What value is associated with r in

69

d.

(run (r )
( d r )
(surprise o r ))

What is the value of


(run (r )
(surprise o r ))

58

70

( 0 ).
When r is fresh, (surprise o r ) succeeds
and leaves r fresh.

Chapter 4

Write an expression that shows why this


definition of surprise o should not succeed
when r is fresh.

71

Here is such an expression:


(run (r )
(surprise o r )
( b r )).
If (surprise o r ) were to leave r fresh, then
( b r ) would associate r with b. But if r
were b, then (rember o r (a b c)) (a b c)))
should have failed, since removing b from the
list (a b c)) results in (a c)), not (a b c)).

And what is the value of


(run (r )
( b r )
(surprise o r ))

72

(b)),
which also makes no sense. Please pass the
aspirin!

= Now go munch on some carrots. =

This space reserved for

CARROT STAINS!

Members Only

59

Chapter 5

Double Your Fun

Ever seen append

Here it is.

No.

(a b c d e)).

(define append
(lambda (l s)
(cond
((null? l ) s)
(else (cons (car l )
(append (cdr l ) s))))))
What is the value of
(append (a b c)) (d e)))

For a different approach to append, see William F.


Clocksin. Clause and Effect. Springer, 1997, page 59.

What is the value of

(a b c)).

(append (a b c)) ())

What is the value of

(d e)).

(append () (d e)))

What is the value of

It has no meaning,
because a is neither the empty list nor a
proper list.

It has no meaning, again?

How is that possible?

(append a (d e)))

What is the value of


(append (d e)) a)

No. The value is (d e ! a)).

Double Your Fun

61

Look closely at the definition of append;


there are no questions asked about s.

Define append o .

Ouch.

(define append o
(lambda (l s out)
(conde
((null o l ) ( s out))
(else
(fresh (a d res)
(car o l a)
(cdr o l d )
(append o d s res)
(cons o a res out))))))

What value is associated with x in

10

(cake tastes yummy)).

(run (x )
(append o
(cake))
(tastes yummy))
x ))

What value is associated with x in

11

(cake with ice

tastes yummy)).

(run (x )
(fresh (y)
(append o
(cake with ice y))
(tastes yummy))
x )))

What value is associated with x in

12

(cake with ice cream !

).

(run (x )
(fresh (y)
(append o
(cake with ice cream))
y
x )))

62

Chapter 5

What value is associated with x in

13

(run (x )
(fresh (y)
(append o (cake with ice ! y)) (d t)) x )))
1

How can we show that y is associated with


the empty list?

14

(cake with ice d t)),


because the last call to null o associates y
with the empty list.

By this example
(run1 (y)
(fresh (x )
(append o (cake with ice ! y)) (d t)) x )))
which associates y with the empty list.

Redefine append o to use a single cons o in


place of the car o and cdr o (see 4:27).

15

What is the value of

16

(define append o
(lambda (l s out)
(conde
((null o l ) ( s out))
(else
(fresh (a d res)
(cons o a d l )
(append o d s res)
(cons o a res out))))))

(run (x )
(fresh (y)
(append o (cake with ice ! y)) (d t)) x )))
5

What is the value of


(run (y)
(fresh (x )
(append o (cake with ice ! y)) (d t)) x )))
5

Double Your Fun

17

((cake
(cake
(cake
(cake
(cake

with
with
with
with
with

ice d t))
ice 0 d t))
ice 0 1 d t))
ice 0 1 2 d t))
ice 0 1 2 3 d t))).

(()
( 0)
( 0 1)
( 0 1 2)
( 0 1 2 3 )).

63

Lets consider plugging in (

) for y in

18

(cake with ice

).

(cake with ice ! y)).


Then we get
(cake with ice ! (

)).

What list is this the same as?


19

Right. What is
(append (cake with ice

The fourth list in frame 16.

) (d t)))

What is the value of

20

(run (x )
(fresh (y)
(append o
(cake with ice ! y))
(d t ! y))
x )))
5

What is the value of

21

((cake
(cake
(cake
(cake
(cake

with
with
with
with
with

ice d t))
ice 0 d t 0 )
ice 0 1 d t 0 1 )
ice 0 1 2 d t 0 1
ice 0 1 2 3 d t 0

((cake with ice cream d t !

2
1

)
2

)).

)).

(run (x )
(fresh (z )
(append o
(cake with ice cream))
(d t ! z )
x )))

Why does the list contain only one value?

22

Lets try an example in which the first two


arguments are variables. What is the value
of

23

(run6 (x )
(fresh (y)
(append o x y (cake with ice d t)))))

64

Because z stays fresh.

(()
(cake))
(cake with))
(cake with ice))
(cake with ice d))
(cake with ice d t))).

Chapter 5

How might we describe these values?

24

Now lets try this variation.

25

(run (y)
(fresh (x )
(append o x y (cake with ice d t)))))
6

What is its value?

How might we describe these values?

26

Lets combine the previous two results.


What is the value of

27

(run6 (r )
(fresh (x y)
(append o x y (cake with ice d t)))
( (x y)) r )))

How might we describe these values?

28

The values include all of the prefixes of the


list (cake with ice d t)).

((cake with ice d t))


(with ice d t))
(ice d t))
(d t))
(t))
()).

The values include all of the suffixes of the


list (cake with ice d t)).

((() (cake with ice d t)))


((cake)) (with ice d t)))
((cake with)) (ice d t)))
((cake with ice)) (d t)))
((cake with ice d)) (t)))
((cake with ice d t)) ())).

Each value includes two lists that, when


appended together, form the list
(cake with ice d t)).

What is the value of

29

It has no value,
since it is still looking for the seventh
value.

30

Yes, that would make sense.

(run (r )
(fresh (x y)
(append o x y (cake with ice d t)))
( (x y)) r )))
7

Should its value be the same as if we asked


for only six values?

Double Your Fun

65

How can we change the definition of append o


so that is indeed what happens?

31

Now, using this revised definition of append o ,


what is the value of

32

Swap the last two goals of append o .


(define append o
(lambda (l s out)
(conde
((null o l ) ( s out))
(else
(fresh (a d res)
(cons o a d l )
(cons o a res out)
(append o d s res))))))

The value is in frame 27.

(run7 (r )
(fresh (x y)
(append o x y (cake with ice d t)))
( (x y)) r )))
What is the value of

33

(run (x )
(fresh (y z )
(append o x y z )))
7

What is the value of

34

(run (y)
(fresh (x z )
(append o x y z )))
7

(()
( 0)
( 0 1)
( 0 1 2)
( 0 1 2 3)
( 0 1 2 3 4)
( 0 1 2 3 4 5 )).
(

0
0
0
0
0
0
0

It should be obvious how we get the first


value. Where do the last four values come
from?

66

35

).

A new fresh variable res is passed into each


recursive call to append o . After (null o l )
succeeds, res is associated with s, which is
the fresh variable z .

Chapter 5

What is the value of

36

(run (z )
(fresh (x y)
(append o x y z )))
7

Lets combine the previous three results.


What is the value of

37

(run7 (r )
(fresh (x y z )
(append o x y z )
( (x y z ) r )))

Define swappend o , which is just append o


with its two conde lines swapped.

38

What is the value of

39

(0
( 0 ! 1)
( 0 1 ! 2)
( 0 1 2 ! 3)
( 0 1 2 3 ! 4)
( 0 1 2 3 4 ! 5)
( 0 1 2 3 4 5 ! 6 )).

((() 0 0 )
(( 0 ) 1 ( 0 ! 1 ))
(( 0 1 ) 2 ( 0 1 ! 2 ))
(( 0 1 2 ) 3 ( 0 1 2 ! 3 ))
(( 0 1 2 3 ) 4 ( 0 1 2 3 ! 4 ))
(( 0 1 2 3 4 ) 5 ( 0 1 2 3 4 ! 5 ))
(( 0 1 2 3 4 5 ) 6 ( 0 1 2 3 4 5 !

))).

Thats a snap.
(define swappend o
(lambda (l s out)
(conde
(#s
(fresh (a d res)
(cons o a d l )
(cons o a res out)
(swappend o d s res)))
(else (null o l ) ( s out)))))

It has no value.

(run (z )
(fresh (x y)
(swappend o x y z )))
1

Double Your Fun

67

Why does

40

(run1 (z )
(fresh (x y)
(swappend o x y z )))

In (swappend o d s res) the variables d , s,


and res remain fresh, which is where we
started.

have no value?

Here is lambda-limited with its auxiliary function ll.

We can redefine swappend o so that this run expression


has a value.

(define-syntax lambda-limited
(syntax-rules ()
(( n formals g)
(let ((x (var x)))
(lambda formals
(ll n x g))))))

(define swappend o
(lambda-limited 5 (l s out)
(conde
(#s
(fresh (a d res)
(cons o a d l)
(cons o a res out)
(swappend o d s res)))
(else (null o l) ( s out)))))

(define ll
(lambda (n x g)
(G (s)
(let ((v (walk x s)))
(cond
((var? v ) (g (ext-s x 1 s)))
((< v n) (g (ext-s x (+ v 1) s)))
(else (#u s)))))))
The functions var, walk, and ext-s are described in 9:6, 9:27,
and 9:29, respectively. G (see appendix) is just lambda.

Where lambda-limited is defined on the right.

Consider this definition.

41

pizza.

(define unwrap
(lambda (x )
(cond
((pair? x ) (unwrap (car x )))
(else x ))))
What is the value of
(unwrap ((((pizza))))))

What is the value of

42

pizza.

(unwrap ((((pizza pie)) with))) extra cheese)))

This might be a good time for a pizza break.

43

Good idea.

Back so soon? Hope you are not too full.

44

Not too.

68

Chapter 5

Define unwrap o .

45

Thats a slice of pizza!


(define unwrap o
(lambda (x out)
(conde
((pair o x )
(fresh (a)
(car o x a)
(unwrap o a out)))
(else ( x out)))))

What is the value of

46

(run (x )
(unwrap o (((pizza)))) x ))

(pizza
(pizza))
((pizza)))
(((pizza))))).

The first value of the list seems right. In


what way are the other values correct?

47

They represent partially wrapped versions of


the list (((pizza)))). And the last value is the
fully-wrapped original list (((pizza)))).

What is the value of

48

It has no value.

49

It has no value.

50

The recursion happens too early. Therefore


the ( x out) goal is not reached.

51

Introduce a revised definition of unwrap o ?

(run (x )
(unwrap o x pizza))
1

What is the value of


(run (x )
(unwrap o ((x )) pizza))
1

Why doesnt
(run (x )
(unwrap o ((x )) pizza))
1

have a value?
What can we do about that?

Double Your Fun

69

Yes. Lets swap the two conde lines as in


3:98.

52

What is the value of

53

(define unwrap o
(lambda (x out)
(conde
(#s ( x out))
(else
(fresh (a)
(car o x a)
(unwrap o a out))))))

(run (x )
(unwrap o x pizza))
5

What is the value of

54

(run5 (x )
(unwrap o x ((pizza)))))

What is the value of

Like this.

55

(run (x )
(unwrap o ((x )) pizza))
5

(pizza
(pizza ! 0 )
((pizza ! 0 ) ! 1 )
(((pizza ! 0 ) ! 1 ) ! 2 )
((((pizza ! 0 ) ! 1 ) ! 2 ) !

)).

(((pizza)))
(((pizza))) ! 0 )
((((pizza))) ! 0 ) ! 1 )
(((((pizza))) ! 0 ) ! 1 ) ! 2 )
((((((pizza))) ! 0 ) ! 1 ) ! 2 ) !

(pizza
(pizza ! 0 )
((pizza ! 0 ) ! 1 )
(((pizza ! 0 ) ! 1 ) ! 2 )
((((pizza ! 0 ) ! 1 ) ! 2 ) !

If you havent taken a pizza break yet, stop


and take one now! Were taking an ice cream
break.

56

Okay, okay!

Did you enjoy the pizza as much as we


enjoyed the ice cream?

57

Indubitably!

70

)).

)).

Chapter 5

Consider this definition.

58

(a b c)).

(define flatten
(lambda (s)
(cond
((null? s) ())
((pair? s)
(append
(flatten (car s))
(flatten (cdr s))))
(else (cons s ())))))
What is the value of
(flatten ((a b)) c)))
Define flatten o .

59

Here it is.
(define flatten o
(lambda (s out)
(conde
((null o s) ( () out))
((pair o s)
(fresh (a d res-a res-d )
(cons o a d s)
(flatten o a res-a)
(flatten o d res-d )
(append o res-a res-d out)))
(else (cons o s () out)))))

What value is associated with x in

60

(run (x )
(flatten o ((a b)) c)) x ))
1

What value is associated with x in

61

See 4:27.

(a b c)).
No surprises here.

(a b c)).

(run (x )
(flatten o (a (b c))) x ))
1

Double Your Fun

71

What is the value of

62

(run (x )
(flatten o (a)) x ))

The value in the previous frame contains


three lists. Which of the lists, if any, are the
same?

63

What is the value of

64

(run (x )
(flatten o ((a))) x ))

The value in the previous frame contains


seven lists. Which of the lists, if any, are the
same?

65

What is the value of

66

(run (x )
(flatten o (((a)))) x ))

72

((a))
(a ())
((a)))).
Here is a surprise!

None of the lists are the same.

((a))
(a ())
(a ())
(a () ())
((a)))
((a)) ())
(((a))))).

The second and third lists are the same.

((a))
(a ())
(a ())
(a () ())
(a ())
(a () ())
(a () ())
(a () () ())
((a)))
((a)) ())
((a)) ())
((a)) () ())
(((a))))
(((a))) ())
((((a)))))).

Chapter 5

The value in the previous frame contains


fifteen lists. Which of the lists, if any, are the
same?

67

What is the value of

68

(run (x )
(flatten o ((a b)) c)) x ))

The second, third, and fifth lists are the


same; the fourth, sixth, and seventh lists are
the same; and the tenth and eleventh lists
are the same.

((a b c))
(a b c ())
(a b (c)))
(a b () c))
(a b () c ())
(a b () (c)))
(a (b)) c))
(a (b)) c ())
(a (b)) (c)))
((a b)) c))
((a b)) c ())
((a b)) (c)))
(((a b)) c)))).

The value in the previous frame contains


thirteen lists. Which of the lists, if any, are
the same?

69

Characterize that list of lists.

70

What is the value of

71

It has no value.

72

Swap some of the conde lines?

None of the lists are the same.

Each list flattens to (a b c)). These are all


the lists generated by attempting to flatten
((a b)) c)). Remember that a singleton list
(a)) is really the same as (a ! ()), and with
that additional perspective the pattern
becomes clearer.

(run (x )
(flatten o x (a b c))))

What can we do about it?

Double Your Fun

73

Yes. Here is a variant of flatten o .

73

(define flattenrev o
(lambda (s out)
(conde
(#s (cons o s () out))
((null o s) ( () out))
(else
(fresh (a d res-a res-d )
(cons o a d s)
(flattenrev o a res-a)
(flattenrev o d res-d )
(append o res-a res-d out))))))

The last conde line of flatten o is the first


conde line of this variant (see 3:98).

How does flatten o differ from this variant?

In flatten o there is a (pair o s) test. Why


doesnt flattenrev o have the same test?

What is the value of

74

75

(run (x )
(flattenrev o ((a b)) c)) x ))

What is the value of

76

Because (cons o a d s) in the fresh


expression guarantees that s is a pair. In
other words, the (pair o s) question is
unnecessary in flatten o .

((((a b)) c)))


((a b)) (c)))
((a b)) c ())
((a b)) c))
(a (b)) (c)))
(a (b)) c ())
(a (b)) c))
(a b () (c)))
(a b () c ())
(a b () c))
(a b (c)))
(a b c ())
(a b c))).

The value in frame 68.

(reverse
(run (x )
(flattenrev o ((a b)) c)) x )))

74

Chapter 5

What is the value of

77

((a b ! c))
(a b c))).

78

Because (flattenrev o (a b ! c)) (a b c))) and


(flattenrev o (a b c)) (a b c))) both succeed.

79

It has no value.
In fact, it is still trying to determine the
third value.

(run (x )
(flattenrev o x (a b c))))
2

Why is the value


((a b ! c))
(a b c)))

What is the value of


(run (x )
(flattenrev o x (a b c))))
3

80

What is the value of


(length
(run (x )
(flattenrev o ((((a (((b)))) c)))) d)) x )))

574.
Wow!

= Now go make yourself a cashew butter and chutney sandwich. =

This space reserved for

CHUTNEY STAINS!

Double Your Fun

75

Chapter 6

The Fun Never Ends . . .

Yes.

Is there a base case?

Yes.

Can any o ever succeed?

Yes, if the goal g succeeds.

Here is another definition.

No,
because although the question of the first
conde line within any o fails, the answer of
the second conde line, (any o #u), is where
we started.

Here is an unusual definition.


(define any o
(lambda (g)
(conde
(g #s)
(else (any o g)))))
Is it recursive?

(define never o (any o #u))


Can never o ever succeed or fail?

What is the value of

Of course, the run1 expression has no value.

(run (q)
never o
( #t q))
1

What is the value of

(run1 (q)
#u
never o )
Here is a useful definition.

(),
because #u fails before never o is reached.

#t.

(define always o (any o #s))


What value is associated with q in
(run1 (q)
always o
( #t q))

The Fun Never Ends . . .

77

Compare always o to #s.

always o always can succeed any number of


times, whereas #s can succeed only once.

What is the value of

It has no value,
since run never finishes building the list
(#t #t #t ...

(run (q)
always o
( #t q))

What is the value of

10

(#t #t #t #t #t)).

(run (q)
always o
( #t q))
5

And what is the value of

11

Its the same: (#t #t #t #t #t)).

(run5 (q)
( #t q)
always o )

Here is the definition of sal o .

12

No.

(define sal o
(lambda (g)
(conde
(#s #s)
(else g))))
Is sal o recursive?

sal o stands for succeeds at least once.

What is the value of


(run (q)
(sal o always o )
( #t q))
1

78

13

(#t)),
because the first conde line of sal o
succeeds.

Chapter 6

What is the value of

14

(run (q)
(sal o never o )
( #t q))
1

What is the value of

15

It has no value,
because run never finishes determining
the second value.

16

It has no value,
because when the #u occurs, we pretend
that the first conde line of sal o fails,
which causes conde to try never o , which
neither succeeds nor fails.

17

It has no value,
because always o succeeds, followed by #u,
which causes always o to be retried, which
succeeds again, which leads to #u again,
which causes always o to be retried again,
which succeeds again, which leads to #u,
etc.

18

It has no value.
First, #f gets associated with q, then
always o succeeds once. But in the outer
( #t q) we cant associate #t with q since
q is already associated with #f. So the
outer ( #t q) fails, then always o succeeds
again, and then ( #t q) fails again, etc.

(run (q)
(sal o never o )
( #t q))

What is the value of


(run (q)
(sal o never o )
#u
( #t q))
1

What is the value of


(run (q)
always o
#u
( #t q))
1

What is the value of


(run1 (q)
(conde
(( #f q) always o )
(else (any o ( #t q))))
( #t q))

The Fun Never Ends . . .

(#t)),
because the first conde line of sal o
succeeds.

79

What is the value of

19

(run1 (q)
(condi
(( #f q) always o )
(else ( #t q)))
( #t q))

(#t)),
because after the first failure, instead of
staying on the first line we try the second
condi line.

condi is written condi and is pronounced con-deye.

What happens if we try for more values?

20

It has no value,
since the second condi line is out of values.

21

Yes, it yields as many as are requested,

(run (q)
(condi
(( #f q) always o )
(else ( #t q)))
( #t q))
2

So does this give more values?

(#t #t #t #t #t)).
always o succeeds five times, but
contributes none of the five values, since
then #f would be in the list.

(run (q)
(condi
(( #f q) always o )
(else (any o ( #t q))))
( #t q))
5

Compare condi to conde .

Are there other differences?

80

22

23

condi looks and feels like conde . condi


does not, however, wait until all the
successful goals on a line are exhausted
before it tries the next line.

Yes. A condi line that has additional values


is not forgotten. That is why there is no
value in frame 20.

Chapter 6

The Law of condi


condi behaves like conde , except
that its values are interleaved.

What is the value of

24

(tea #f cup)).

(run (r )
(condi
((teacup o r ) #s)
(( #f r ) #s)
(else #u)))
5

See 1:56.

Lets be sure that we understand the


difference between conde and condi .
What is the value of

25

(#t #t #t #t #t)).

(run5 (q)
(condi
(( #f q) always o )
(( #t q) always o )
(else #u))
( #t q))

And if we replace condi by conde , do we get


the same value?
Why does
(run (q)
(conde
(( #f q) always o )
(( #t q) always o )
(else #u))
( #t q))
5

26

No,
then the expression has no value.

27

It has no value,
because the first conde line succeeds, but
the outer ( #t q) fails. This causes the
first conde line to succeed again, etc.

have no value?

The Fun Never Ends . . .

81

28

What is the value of

It is (#t #t #t #t #t)).

(run (q)
(conde
(always o #s)
(else never o ))
( #t q))
5

And if we replace conde by condi , do we get


the same value?
And what about the value of

29

No.

30

It has no value,
because after the first condi line succeeds,
rather than staying on the same condi
line, it tries for more values on the second
condi line, but that line is never o .

31

It has no value.
First, #f is associated with q. Then
always o , the second goal of the all
expression, succeeds, so the entire all
expression succeeds. Then ( #t q) tries to
associate a value that is different from #f
with q. This fails. So always o succeeds
again, and once again the second goal,
( #t q), fails. Since always o always
succeeds, there is no value.

(run (q)
(condi
(always o #s)
(else never o ))
( #t q))
5

What is the value of


(run1 (q)
(all
(conde
(( #f q) #s)
(else ( #t q)))
always o )
( #t q))

The goals of an all must succeed for the all to succeed.

Have a slice of Key lime pie.

82

Chapter 6

Now, what is the value of

32

(run1 (q)
(alli
(conde
(( #f q) #s)
(else ( #t q)))
always o )
( #t q))

(#t)).
First, #f is associated with q. Then,
always o succeeds. Then the outer goal
( #t q) fails. This time, however, alli
moves on to the second conde line and
associates #t with q. Then always o
succeeds, as does the outer ( #t q).

alli is written alli and is pronounced all-eye.

Now, what if we want more values?

33

(run (q)
(alli
(conde
(( #f q) #s)
(else ( #t q)))
always o )
( #t q))
5

What if we swap the two conde lines?

34

(#t #t #t #t #t)).
always o succeeds ten times, with the value
associated with q alternating between #f
and #t.

Its value is the same: (#t #t #t #t #t)).

(run (q)
(alli
(conde
(( #t q) #s)
(else ( #f q)))
always o )
( #t q))
5

What does the i stand for in condi and


alli

The Fun Never Ends . . .

35

It stands for interleave.

83

Lets be sure that we understand the


difference between all and alli . What is the
value of

36

(#t #t #t #t #t)).

(run5 (q)
(all
(conde
(#s #s)
(else never o ))
always o )
( #t q))

And if we replace all by alli , do we get the


same value?

Why does

37

No,
it has no value.

38

It has no value,
because the first conde line succeeds, and
the outer ( #t q) succeeds. This yields
one value, but when we go for a second
value, we reach never o .

39

Yes,
since none of the conde lines contribute
more than one value.

(run (q)
(alli
(conde
(#s #s)
(else never o ))
always o )
( #t q))
5

have no value?

Could condi have been used instead of


conde in these last two examples?

= This is a good time to take a break. =

84

Chapter 6

This is

A BREAK

The Fun Never Ends . . .

85

Chapter 7

A Bit Too Much

Is 0 a bit?

Yes.

Is 1 a bit?

Yes.

Is 2 a bit?

No.
A bit is either a 0 or a 1.

Which bits are represented by x

0 and 1.

Consider the definition of bit-xor o .

(define bit-xor o
(lambda (x y r )
(conde
(( 0 x ) ( 0
(( 1 x ) ( 0
(( 0 x ) ( 1
(( 1 x ) ( 1
(else #u))))

y)
y)
y)
y)

(
(
(
(

0
1
1
0

When x and y are the same.

r ))
r ))
r ))
r ))

Another way to define bit-xor o is to use bit-nand o

(define bit-xor o
(lambda (x y r )
(fresh (s t u)
(bit-nand o x
(bit-nand o x
(bit-nand o s
(bit-nand o t

y
s
y
u

s)
t)
u)
r ))))

where bit-nand o is

When is 0 the value of r

(define bit-nand o
(lambda (x y r )
(conde
(( 0 x ) (
(( 1 x ) (
(( 0 x ) (
(( 1 x ) (
(else #u))))

0
0
1
1

y)
y)
y)
y)

(
(
(
(

1
1
1
0

r ))
r ))
r ))
r ))

bit-nand o is a universal binary boolean relation, since it can


be used to define all other binary boolean relations.

Demonstrate this using run .

(run (s)
(fresh (x y)
(bit-xor o x y 0)
( (x y)) s)))
which has the value
((0 0))
(1 1))).

A Bit Too Much

87

When is 1 the value of r

Demonstrate this using run .

When x and y are different.

(run (s)
(fresh (x y)
(bit-xor o x y 1)
( (x y)) s)))
which has the value
((1 0))
(0 1))).

What is the value of


(run (s)
(fresh (x y r )
(bit-xor o x y r )
( (x y r ) s)))

Consider the definition of bit-and o .


(define bit-and o
(lambda (x y r )
(conde
(( 0 x ) ( 0
(( 1 x ) ( 0
(( 0 x ) ( 1
(( 1 x ) ( 1
(else #u))))

y)
y)
y)
y)

(
(
(
(

0
0
0
1

10

((0
(1
(0
(1

0
0
1
1

0))
1))
1))
0))).

When x and y are both 1.

Another way to define bit-and o is to use bit-nand o and


bit-not o

r ))
r ))
r ))
r ))

(define bit-and o
(lambda (x y r )
(fresh (s)
(bit-nand o x y s)
(bit-not o s r ))))
where bit-not o itself is defined in terms of bit-nand o

When is 1 the value of r

Demonstrate this using run .

(define bit-not o
(lambda (x r )
(bit-nand o x x r )))

11

(run (s)
(fresh (x y)
(bit-and o x y 1)
( (x y)) s)))
which has the value
((1 1))).

88

Chapter 7

Consider the definition of half-adder o .

12

(define half-adder o
(lambda (x y r c)
(all
(bit-xor o x y r )
(bit-and o x y c))))

(run (r )
(half-adder o 1 1 r 1))

13

(run (s)
(fresh (x y r c)
(half-adder o x y r c)
( (x y r c)) s)))

Describe half-adder o .

14

Here is full-adder o .

15

(define full-adder o
(lambda (b x y r c)
(fresh (w xy wz )
(half-adder o x y w xy)
(half-adder o w b r wz )
(bit-xor o xy wz c))))
The x , y, r , and c variables serve the same
purpose as in half-adder o . full-adder o also
takes a carry-in bit, b. What value is
associated with s in
(run (s)
(fresh (r c)
(full-adder o 0 1 1 r c)
( (r c)) s)))

A Bit Too Much

half-adder o can be redefined as follows.

(define half-adder o
(lambda (x y r c)
(conde
(( 0 x ) ( 0
(( 1 x ) ( 0
(( 0 x ) ( 1
(( 1 x ) ( 1
(else #u))))

What value is associated with r in

What is the value of

0.

((0
(1
(0
(1

0
0
1
1

0
1
1
0

y)
y)
y)
y)

(
(
(
(

0
1
1
0

r)
r)
r)
r)

(
(
(
(

0
0
0
1

c))
c))
c))
c))

0))
0))
0))
1))).

Given the bits x , y, r , and c, half-adder o


satisfies x + y = r + 2 c.
(0 1)).

full-adder o can be redefined as follows.

(define full-adder o
(lambda (b x y r c)
(conde
(( 0 b) ( 0 x )
(( 1 b) ( 0 x )
(( 0 b) ( 1 x )
(( 1 b) ( 1 x )
(( 0 b) ( 0 x )
(( 1 b) ( 0 x )
(( 0 b) ( 1 x )
(( 1 b) ( 1 x )
(else #u))))

(
(
(
(
(
(
(
(

0
0
0
0
1
1
1
1

y)
y)
y)
y)
y)
y)
y)
y)

(
(
(
(
(
(
(
(

0
1
1
0
1
0
0
1

r)
r)
r)
r)
r)
r)
r)
r)

(
(
(
(
(
(
(
(

0
0
0
1
0
1
1
1

c))
c))
c))
c))
c))
c))
c))
c))

89

What value is associated with s in

16

(1 1)).

(run (s)
(fresh (r c)
(full-adder o 1 1 1 r c)
( (r c)) s)))

What is the value of

17

(run (s)
(fresh (b x y r c)
(full-adder o b x y r c)
( (b x y r c)) s)))

((0
(1
(0
(1
(0
(1
(0
(1

0
0
1
1
0
0
1
1

0
0
0
0
1
1
1
1

0
1
1
0
1
0
0
1

0))
0))
0))
1))
0))
1))
1))
1))).

Describe full-adder o .

18

Given the bits b, x , y, r , and c, full-adder o


satisfies b + x + y = r + 2 c.

What is a number ?

19

A number is an integer greater than or equal


to zero.

Is each number represented by a bit?

20

No.
Each number is represented as a list of
bits.

Which list represents the number zero?

21

Not quite. Try again.

22

Correct. Is there any number that (0))


represents?

90

23

(0))?

How about the empty list ()?

No.
Each number is represented uniquely,
therefore (0)) cannot also represent the
number zero.

Chapter 7

Which list represents the number one?

24

Which number is represented by

25

(1)),
because the value of (1)) is 1 20 , which is
the number one.

5,

(1 0 1))

Correct. Which number is represented by

26

(1 1 1))

Also correct. Which list represents 9

27

Yes. How do we represent 6

28

No. Try again.

29

Correct. Does this seem unusual?

30

How do we represent 19

31

Yes. How do we represent 17290

32

A Bit Too Much

7,

because the value of (1 0 1)) is


1 20 + 0 21 + 1 22 , which is the same as
1 + 0 + 4, which is five.

because the value of (1 1 1)) is


1 20 + 1 21 + 1 22 , which is the same as
1 + 2 + 4, which is seven.

(1 0 0 1)),
because the value of (1 0 0 1)) is
1 20 + 0 21 + 0 22 + 1 23 , which is the
same as 1 + 0 + 0 + 8, which is nine.

As the list (1 1 0))?

Then it must be (0 1 1)),


because the value of (0 1 1)) is
0 20 + 1 21 + 1 22 , which is the same as
0 + 2 + 4, which is six.

Yes, it seems very unusual.

As the list (1 1 0 0 1))?

As the list (0 1 0 1 0 0 0 1 1 1 0 0 0 0 1))?

91

Correct again. What is interesting about the


lists that represent the numbers that we have
seen?

33

They contain only 0s and 1s.

Yes. What else is interesting?

34

Every list ends with a 1.

Does every list representation of a number


end with a 1?

35

Compare the numbers represented by n and


(0 ! n))

36

If n were (1 0 1)), what would (0 ! n)) be?

37

Compare the numbers represented by n and


(1 ! n))

38

If n were (1 0 1)), what would (1 ! n)) be?

39

What is the value of

40

Yes, except for the empty list (), which


represents zero.

(0 ! n)) is twice n.
But n cannot be (), since (0 ! n)) is (0)),
which does not represent a number.

(0 1 0 1)),
since twice five is ten.

(1 ! n)) is one more than twice n,


even when n is ().

(1 1 0 1)),
since one more than twice five is eleven.

().

(build-num 0)

What is the value of

41

(0 0 1 0 0 1)).

(build-num 36)

What is the value of

42

(1 1 0 0 1)).

(build-num 19)

92

Chapter 7

Define build-num.

43

Here is one way to define it.


(define build-num
(lambda (n)
(cond
((zero? n) ())
((and (not (zero? n)) (even? n))
(cons 0
(build-num ( n 2))))
((odd? n)
(cons 1
(build-num ( ( n 1) 2)))))))

Redefine build-num, where (zero? n) is not


the question of the first cond line.

Is there anything interesting about these


definitions of build-num

44

Thats easy.
(define build-num
(lambda (n)
(cond
((odd? n)
(cons 1
(build-num ( ( n 1) 2))))
((and (not (zero? n)) (even? n))
(cons 0
(build-num ( n 2))))
((zero? n) ()))))

45

For any number n, one and only one cond


question is true.

Can we rearrange the cond lines in any


order?

A Bit Too Much

46

Thank you Edsger W. Dijkstra (19302002).

Yes.
This is called the non-overlapping
property. It appears rather frequently
throughout this and the next chapter.

93

What is the sum of (1)) and (1))

What is the sum of (0 0 0 1)) and (1 1 1))

What is the sum of (1 1 1)) and (0 0 0 1))

What is the sum of (1 1 0 0 1)) and ()

What is the sum of () and (1 1 0 0 1))

What is the sum of (1 1 1 0 1)) and (1))

Which number is represented by

47

48

49

50

51

52

(0 1)), which is just two.

(1 1 1 1)), which is just fifteen.

(1 1 1 1)), which is just fifteen.

(1 1 0 0 1)), which is just nineteen.

(1 1 0 0 1)), which is just nineteen.

(0 0 0 1 1)), which is just twenty-four.

53

It depends on what x is.

54

Two,
which is represented by (0 1)).

55

Three,
which is represented by (1 1)).

56

Two and three.

57

Four and seven,


which are represented by (0 0 1))
and (1 1 1)), respectively.

(x 1))

Which number would be represented by


(x 1))
if x were 0?
Which number would be represented by
(x 1))
if x were 1?
So which numbers are represented by
(x 1))

Which numbers are represented by


(x x 1))

94

Chapter 7

58

Eight, nine, twelve, and thirteen,


which are represented by (0 0 0 1)),
(1 0 0 1)), (0 0 1 1)), and (1 0 1 1)),
respectively.

59

Once again, eight, nine, twelve, and thirteen,


which are represented by (0 0 0 1)),
(1 0 0 1)), (0 0 1 1)), and (1 0 1 1)),
respectively.

60

Because z must be either a 0 or a 1. If z


were 0, then (x 0 y z ) would not represent
any number. Therefore z must be 1.

61

One,
which is represented by (1)), since (0)) does
not represent a number.

What does z represent?

62

Every number greater than or equal to zero.

Which numbers are represented by

63

It depends on what z is.

64

One,
since (1 ! ()) is (1)).

65

Three,
since (1 ! (1))) is (1 1)).

Which numbers are represented by


(x 0 y 1))

Which numbers are represented by


(x 0 y z )

Why do both (x 0 y 1)) and (x 0 y z )


represent the same numbers?

Which number is represented by


(x )

(1 ! z )

Which number is represented by


(1 ! z )
where z is ()

Which number is represented by


(1 ! z )
where z is (1))

A Bit Too Much

95

Which number is represented by

66

Five,
since (1 ! (0 1))) is (1 0 1)).

67

All the odd numbers?

68

All the even numbers?

(1 ! z )
where z is (0 1))

So which numbers are represented by


(1 ! z )

Right. Then, which numbers are represented


by
(0 ! z )

Not quite. Which even number is not of the


form (0 ! z )

69

For which values of z does

70

All numbers greater than zero.

Are the even numbers all the numbers that


are multiples of two?

71

Yes.

Which numbers are represented by

72

Every other even number, starting with four.

73

Every other even number, starting with two.

74

Every other odd number, starting with five.

Zero, which is represented by ().

(0 ! z )
represent numbers?

(0 0 ! z )

Which numbers are represented by


(0 1 ! z )

Which numbers are represented by


(1 0 ! z )

96

Chapter 7

75

Once again, every other odd number,


starting with five.

Why do (1 0 ! z ) and (1 0 y ! z ) represent


the same numbers?

76

Because z cannot be the empty list in


(1 0 ! z ) and y cannot be 0 when z is the
empty list in (1 0 y ! z ).

Which numbers are represented by

77

Every even number, starting with two.

78

Every odd number, starting with three.

79

Every number, starting with onein other


words, the positive numbers.

Which numbers are represented by


(1 0 y ! z )

(0 y ! z )

Which numbers are represented by


(1 y ! z )

Which numbers are represented by


(y ! z )

Consider the definition of pos o .

80

#t.

(define pos o
(lambda (n)
(fresh (a d )
( (a ! d ) n))))
What value is associated with q in
(run (q)
(pos o (0 1 1)))
( #t q))

What value is associated with q in

81

#t.

(run (q)
(pos o (1)))
( #t q))

A Bit Too Much

97

What is the value of

82

().

(run (q)
(pos o ())
( #t q))

What value is associated with r in

83

).

(run (r )
(pos o r ))

Does this mean that (pos o r ) always


succeeds when r is a fresh variable?

Which numbers are represented by

84

Yes.

85

Every number, starting with twoin other


words, every number greater than one.

(x y ! z )

Consider the definition of >1o .

86

#t.

(define >1o
(lambda (n)
(fresh (a ad dd )
( (a ad ! dd ) n))))
What value is associated with q in
(run (q)
(>1o (0 1 1)))
( #t q))

The names a, ad, and dd correspond to car, cadr , and


cddr .

What is the value of

87

(#t)).

(run (q)
(>1o (0 1)))
( #t q))

98

Chapter 7

What is the value of

88

().

(run (q)
(>1o (1)))
( #t q))

What is the value of

89

().

(run (q)
(>1o ())
( #t q))

What value is associated with r in

90

).

(run (r )
(>1o r ))

Does this mean that (>1o r ) always succeeds


when r is a fresh variable?
An n-representative is the first n bits of a
number, up to and including the rightmost 1.
If there is no rightmost 1, then the
n-representative is the empty list. What is
the n-representative of

91

92

Yes.

(0 1 1)).

(0 1 1))

What is the n-representative of

93

(0 x 1 0 y ! z )

What is the n-representative of

94

(0 0 y ! z )

What is the n-representative of


z

A Bit Too Much

95

(0 x 1)),
since everything to the right of the
rightmost 1 is ignored.

(),
since there is no rightmost 1.

().

99

96

What is the value of


(run3 (s)
(fresh (x y r )
(adder o 0 x y r )
( (x y r ) s)))

97

What is the value of


(run (s)
(fresh (x y r )
(adder o 0 x y r )
( (x y r ) s)))
3

Is ((1)) (1)) (0 1))) a ground value?

Is (

()

) a ground value?

That depends on the definition of adder o ,


which we do not see until frame 118. But we
can understand adder o : given the bit d , and
the numbers n, m, and r , adder o satisfies
d + n + m = r.

(( 0 () 0 )
(() ( 0 ! 1 ) ( 0 ! 1 ))
((1)) (1)) (0 1)))).
(adder o 0 x y r ) sums x and y to produce
r . For example, in the first value, zero
added to a number is the number. In the
second value, the sum of () and ( 0 ! 1 ) is
( 0 ! 1 ). In other words, the sum of zero
and a positive number is the positive
number.

98

Yes.

99

No,
because it contains one or more variables.

In fact, ( 0 () 0 ) has no variables, however prior to being


reified, it contained two occurrences of the same variable.

What can we say about the three values in


frame 97?

100

The third value is ground and the other two


values are not.

Before reading the next frame,

Treat Yourself to a Hot Fudge Sundae!

100

Chapter 7

What is the value of

101

(run (s)
(fresh (x y r )
(adder o 0 x y r )
( (x y r ) s)))
22

How many of its values are ground, and how


many are not?

102

What are the nonground values?

103

A Bit Too Much

(( 0 () 0 )
(() ( 0 ! 1 ) ( 0 ! 1 ))
((1)) (1)) (0 1)))
((1)) (0 0 ! 1 ) (1 0 ! 1 ))
((0 0 ! 1 ) (1)) (1 0 ! 1 ))
((1)) (1 1)) (0 0 1)))
((0 1)) (0 1)) (0 0 1)))
((1)) (1 0 0 ! 1 ) (0 1 0 ! 1 ))
((1 1)) (1)) (0 0 1)))
((1)) (1 1 1)) (0 0 0 1)))
((1 1)) (0 1)) (1 0 1)))
((1)) (1 1 0 0 ! 1 ) (0 0 1 0 ! 1 ))
((1 0 0 ! 1 ) (1)) (0 1 0 ! 1 ))
((1)) (1 1 1 1)) (0 0 0 0 1)))
((0 1)) (0 0 0 ! 1 ) (0 1 0 ! 1 ))
((1)) (1 1 1 0 0 ! 1 ) (0 0 0 1 0 ! 1 ))
((1 1 1)) (1)) (0 0 0 1)))
((1)) (1 1 1 1 1)) (0 0 0 0 0 1)))
((0 1)) (1 1)) (1 0 1)))
((1)) (1 1 1 1 0 0 ! 1 ) (0 0 0 0 1 0 ! 1 ))
((1 1 0 0 ! 1 ) (1)) (0 0 1 0 ! 1 ))
((1)) (1 1 1 1 1 1)) (0 0 0 0 0 0 1)))).

Eleven values are ground and eleven values


are not.

(( 0 () 0 )
(() ( 0 ! 1 ) ( 0 ! 1 ))
((1)) (0 0 ! 1 ) (1 0 ! 1 ))
((0 0 ! 1 ) (1)) (1 0 ! 1 ))
((1)) (1 0 0 ! 1 ) (0 1 0 ! 1 ))
((1)) (1 1 0 0 ! 1 ) (0 0 1 0 ! 1 ))
((1 0 0 ! 1 ) (1)) (0 1 0 ! 1 ))
((0 1)) (0 0 0 ! 1 ) (0 1 0 ! 1 ))
((1)) (1 1 1 0 0 ! 1 ) (0 0 0 1 0 ! 1 ))
((1)) (1 1 1 1 0 0 ! 1 ) (0 0 0 0 1 0 ! 1 ))
((1 1 0 0 ! 1 ) (1)) (0 0 1 0 ! 1 ))).

101

What interesting property do these eleven


values possess?

104

The width of r is the same as the width of


the wider of x and y.

The width of a number n can be defined as


(define width
(lambda (n)
(cond
((null? n) 0)
((pair? n) (+ (width (cdr n)) 1))
(else 1))))

What is another interesting property that


these eleven values possess?

105

Variables appear in r , and in either x or y,


but not in both.

What is another interesting property that


these eleven values possess?

106

Except for the first value, r always ends with


! 1 as does the wider of x and y.
0

What is another interesting property that


these eleven values possess?

107

The n-representative of r is equal to the sum


of the n-representatives of x and y.
In the ninth value, for example, the sum of
(1)) and (1 1 1)) is (0 0 0 1)).

Describe the third value.

108

Huh?

Here x is (1)) and y is (0 0 ! 1 ), a positive


even number. Adding x to y yields the odd
numbers greater than one. Is the fifth value
the same as the seventh?

109

Almost,
since x + y = y + x.

Does each value have a corresponding value


in which x and y are swapped?

110

No.
For example, the first two values do not
correspond to any other values.

102

Chapter 7

What is the corresponding value for the


tenth value?

111

((1 1 1 1 0 0 ! 1 ) (1)) (0 0 0 0 1 0 ! 1 )).


However, this is the nineteenth nonground
value, and we have presented only the first
eleven.

Describe the seventh value.

112

Frame 75 shows that (1 0 0 ! 1 ) represents


every other odd number, starting at five.
Incrementing each of those numbers by one
produces every other even number, starting
at six, which is represented by (0 1 0 ! 1 ).

Describe the eighth value.

113

The eighth value is like the third value, but


with an additional leading 0. In other words,
each number is doubled.

Describe the 198th value, which has the


value ((0 0 1)) (1 0 0 0 ! 1 ) (1 0 1 0 ! 1 )).

114

(1 0 0 0 ! 1 ) represents every fourth odd


number, starting at nine. Incrementing each
of those numbers by four produces every
fourth odd number, starting at thirteen,
which is represented by (1 0 1 0 ! 1 ).

What are the ground values of frame 101?

115

What interesting property do these values


possess?

116

A Bit Too Much

(((1)) (1)) (0 1)))


((1)) (1 1)) (0 0 1)))
((0 1)) (0 1)) (0 0 1)))
((1 1)) (1)) (0 0 1)))
((1)) (1 1 1)) (0 0 0 1)))
((1 1)) (0 1)) (1 0 1)))
((1)) (1 1 1 1)) (0 0 0 0 1)))
((1 1 1)) (1)) (0 0 0 1)))
((1)) (1 1 1 1 1)) (0 0 0 0 0 1)))
((0 1)) (1 1)) (1 0 1)))
((1)) (1 1 1 1 1 1)) (0 0 0 0 0 0 1)))).

The width of r is one greater than the width


of the wider of x and y.

103

What is another interesting property of these


values?

117

Here are adder o and gen-adder o .

118

Each list cannot be created from any list in


frame 103, regardless of which values are
chosen for the variables there. This is an
example of the non-overlapping property
described in frame 46.

A carry bit.

(define adder o
(lambda (d n m r )
(condi
(( 0 d ) ( () m) ( n r ))
(( 0 d ) ( () n) ( m r )
(pos o m))
(( 1 d ) ( () m)
(adder o 0 n (1)) r ))
(( 1 d ) ( () n) (pos o m)
(adder o 0 (1)) m r ))
(( (1)) n) ( (1)) m)
(fresh (a c)
( (a c)) r )
(full-adder o d 1 1 a c)))
(( (1)) n) (gen-adder o d n m r ))
(( (1)) m) (>1o n) (>1o r )
(adder o d (1)) n r ))
((>1o n) (gen-adder o d n m r ))
(else #u))))
(define gen-adder o
(lambda (d n m r )
(fresh (a b c e x y z )
( (a ! x ) n)
( (b ! y)) m) (pos o y)
( (c ! z ) r ) (pos o z )
(alli
(full-adder o d a b c e)
(adder o e x y z )))))
What is d

What are n, m, and r

104

119

See 10:26 for why gen-adder o requires alli instead of all.

They are numbers.

Chapter 7

What value is associated with s in

120

(0 1 0 1)).

(run (s)
(gen-adder o 1 (0 1 1)) (1 1)) s))

What are a, b, c, d , and e

121

They are bits.

What are n, m, r , x , y, and z

122

They are numbers.

123

Because in the first call to gen-adder o from


adder o , n can be (1)).

In the definition of gen-adder o , (pos o y) and


(pos o z ) follow ( (b ! y)) m) and
( (c ! z ) r ), respectively. Why isnt there a
(pos o x )
What about the other call to gen-adder o
from adder o

124

Describe gen-adder o .

125

What is the value of

126

(run (s)
(fresh (x y)
(adder o 0 x y (1 0 1)))
( (x y)) s)))

Describe the values produced by


(run (s)
(fresh (x y)
(adder o 0 x y (1 0 1)))
( (x y)) s)))

A Bit Too Much

127

The (>1o n) call that precedes the call to


gen-adder o is the same as if we had placed a
(pos o x ) following ( (a ! x ) n). But if we
were to use (pos o x ) in gen-adder o , then it
would fail for n being (1)).
Given the bit d , and the numbers n, m, and
r , gen-adder o satisfies d + n + m = r,
provided that n is positive and m and r are
greater than one.
(((1 0 1)) ())
(() (1 0 1)))
((1)) (0 0 1)))
((0 0 1)) (1)))
((1 1)) (0 1)))
((0 1)) (1 1)))).
The values are the pairs of numbers that sum
to five.

105

We can define +o using adder o .

128

(define +o
(lambda (n m k )
(adder o 0 n m k )))

(run (s)
(fresh (x y)
(+o x y (1 0 1)))
( (x y)) s))).

Use +o to generate the pairs of numbers that


sum to five.
What is the value of

129

(run (s)
(fresh (x y)
(+o x y (1 0 1)))
( (x y)) s)))

Now define o using +o .

Here is an expression that generates the pairs


of numbers that sum to five:

130

(((1 0 1)) ())


(() (1 0 1)))
((1)) (0 0 1)))
((0 0 1)) (1)))
((1 1)) (0 1)))
((0 1)) (1 1)))).

That is easy.
(define o
(lambda (n m k )
(+o m k n)))

What is the value of

131

((1 1))).

(run (q)
(o (0 0 0 1)) (1 0 1)) q))

What is the value of

132

(()).

(run (q)
(o (0 1 1)) (0 1 1)) q))

What is the value of


(run (q)
(o (0 1 1)) (0 0 0 1)) q))

133

().
Eight cannot be subtracted from six, since
we do not represent negative numbers.

= Now go make yourself a baba ghanoush pita wrap. =


106

Chapter 7

This space reserved for

BABA GHANOUSH STAINS!

A Bit Too Much

107

Chapter 8

Just a Bit More

What is the value of

(run (t)
(fresh (x y r )
(o x y r )
( (x y r ) t)))
34

It is difficult to see patterns when looking at


all thirty-four values. Would it be easier to
examine only the nonground values?

Just a Bit More

((() 0 ())
(( 0 ! 1 ) () ())
((1)) ( 0 ! 1 ) ( 0 ! 1 ))
(( 0 1 ! 2 ) (1)) ( 0 1 ! 2 ))
((0 1)) ( 0 1 ! 2 ) (0 0 1 ! 2 ))
((1 0 ! 1 ) (0 1)) (0 1 0 ! 1 ))
((0 0 1)) ( 0 1 ! 2 ) (0 0 0 1 ! 2 ))
((1 1)) (1 1)) (1 0 0 1)))
((0 1 0 ! 1 ) (0 1)) (0 0 1 0 ! 1 ))
((1 0 ! 1 ) (0 0 1)) (0 0 1 0 ! 1 ))
((0 0 0 1)) ( 0 1 ! 2 ) (0 0 0 0 1 ! 2 ))
((1 1)) (1 0 1)) (1 1 1 1)))
((0 1 1)) (1 1)) (0 1 0 0 1)))
((1 1)) (0 1 1)) (0 1 0 0 1)))
((0 0 1 0 ! 1 ) (0 1)) (0 0 0 1 0 ! 1 ))
((1 1)) (1 1 1)) (1 0 1 0 1)))
((0 1 0 ! 1 ) (0 0 1)) (0 0 0 1 0 ! 1 ))
((1 0 ! 1 ) (0 0 0 1)) (0 0 0 1 0 ! 1 ))
((0 0 0 0 1)) ( 0 1 ! 2 ) (0 0 0 0 0 1 ! 2 ))
((1 0 1)) (1 1)) (1 1 1 1)))
((0 1 1)) (1 0 1)) (0 1 1 1 1)))
((1 0 1)) (0 1 1)) (0 1 1 1 1)))
((0 0 1 1)) (1 1)) (0 0 1 0 0 1)))
((1 1)) (1 0 0 1)) (1 1 0 1 1)))
((0 1 1)) (0 1 1)) (0 0 1 0 0 1)))
((1 1)) (0 0 1 1)) (0 0 1 0 0 1)))
((0 0 0 1 0 ! 1 ) (0 1)) (0 0 0 0 1 0 ! 1 ))
((1 1)) (1 1 0 1)) (1 0 0 0 0 1)))
((0 1 1)) (1 1 1)) (0 1 0 1 0 1)))
((1 1 1)) (0 1 1)) (0 1 0 1 0 1)))
((0 0 1 0 ! 1 ) (0 0 1)) (0 0 0 0 1 0 ! 1 ))
((1 1)) (1 0 1 1)) (1 1 1 0 0 1)))
((0 1 0 ! 1 ) (0 0 0 1)) (0 0 0 0 1 0 ! 1 ))
((1 0 ! 1 ) (0 0 0 0 1)) (0 0 0 0 1 0 ! 1 ))).

Yes,
thanks.

109

What are the first eighteen nonground


values?

The value associated with p in

(run (p)
(o (0 1)) (0 0 1)) p))

((() 0 ())
(( 0 ! 1 ) () ())
((1)) ( 0 ! 1 ) ( 0 ! 1 ))
(( 0 1 ! 2 ) (1)) ( 0 1 ! 2 ))
((0 1)) ( 0 1 ! 2 ) (0 0 1 ! 2 ))
((1 0 ! 1 ) (0 1)) (0 1 0 ! 1 ))
((0 0 1)) ( 0 1 ! 2 ) (0 0 0 1 ! 2 ))
((0 1 0 ! 1 ) (0 1)) (0 0 1 0 ! 1 ))
((1 0 ! 1 ) (0 0 1)) (0 0 1 0 ! 1 ))
((0 0 0 1)) ( 0 1 ! 2 ) (0 0 0 0 1 ! 2 ))
((0 0 1 0 ! 1 ) (0 1)) (0 0 0 1 0 ! 1 ))
((0 1 0 ! 1 ) (0 0 1)) (0 0 0 1 0 ! 1 ))
((1 0 ! 1 ) (0 0 0 1)) (0 0 0 1 0 ! 1 ))
((0 0 0 0 1)) ( 0 1 ! 2 ) (0 0 0 0 0 1 ! 2 ))
((0 0 0 1 0 ! 1 ) (0 1)) (0 0 0 0 1 0 ! 1 ))
((0 0 1 0 ! 1 ) (0 0 1)) (0 0 0 0 1 0 ! 1 ))
((0 1 0 ! 1 ) (0 0 0 1)) (0 0 0 0 1 0 ! 1 ))
((1 0 ! 1 ) (0 0 0 0 1)) (0 0 0 0 1 0 ! 1 ))).
The fifth nonground value
((0 1)) (

) (0

)).

is (0 0 0 1)). To which nonground value does


this correspond?

Describe the fifth nonground value.

The product of two and a number greater


than one is twice the number greater than
one.

Describe the sixth nonground value.

The product of an odd number, three or


greater, and two is twice the odd number.

It is even,
since the first bit of (0 1

Is the product of (1
even?

) and (0 1)) odd or

Is there a nonground value that shows that


the product of three and three is nine?

110

) is 0.

No.

Chapter 8

Is there a ground value that shows that the


product of three and three is nine?

Yes,
the first ground value
((1 1)) (1 1)) (1 0 0 1)))
shows that the product of three and three
is nine.

Here is the definition of o .

10

(define o
(lambda (n m p)
(condi
(( () n) ( () p))
((pos o n) ( () m) ( () p))
(( (1)) n) (pos o m) ( m p))
((>1o n) ( (1)) m) ( n p))
((fresh (x z )
( (0 ! x ) n) (pos o x )
( (0 ! z ) p) (pos o z )
(>1o m)
(o x m z )))
((fresh (x y)
( (1 ! x ) n) (pos o x )
( (0 ! y)) m) (pos o y)
(o m n p)))
((fresh (x y)
( (1 ! x ) n) (pos o x )
( (1 ! y)) m) (pos o y)
(odd-o x n m p)))
(else #u))))

The first condi line says that the product of


zero and a number is zero. The second line
says that the product of a positive number
and zero is also equal to zero.

Describe the first and second condi lines.


Why isnt (( () m) ( () p)) the second
condi line?

Describe the third and fourth condi lines.

Just a Bit More

11

12

To avoid producing two values in which both


n and m are zero. In other words, we enforce
the non-overlapping property.
The third condi line says that the product
of one and a positive number is the number.
The fourth line says that the product of a
number greater than one and one is the
number.
111

Describe the fifth condi line.

13

The fifth condi line says that the product of


an even positive number and a number
greater than one is an even positive number,
using the equation n m = 2 ( n2 m).

Why do we use this equation?

14

In order for the recursive call to have a value,


one of the arguments to o must shrink.
Dividing n by two clearly shrinks n.

How do we divide n by two?

15

With ( (0 ! x ) n), where x is not ().

Describe the sixth condi line.

Describe the seventh condi line.

Here is odd-o .
(define odd-o
(lambda (x n m p)
(fresh (q)
(bound-o q p n m)
(o x m q)
(+o (0 ! q)) m p))))

16

17

18

This one is easy. The sixth condi line says


that the product of an odd positive number
and an even positive number is the same as
the product of the even positive number and
the odd positive number.

This one is also easy. The seventh condi line


says that the product of an odd number
greater than one and another odd number
greater than one is the result of
(odd-o x n m p), where x is n1
2 .

We know that x is n1
2 . Therefore,

m)
+ m.
n m = 2 ( n1
2

If we ignore bound-o , what equation


describes the work done in odd-o

112

Chapter 8

Here is a hypothetical definition of bound-o .

19

(define bound-o
(lambda (q p n m)
#s))

Using the hypothetical definition of bound-o ,


what value would be associated with t in

20

(run1 (t)
(fresh (n m)
(o n m (1)))
( (n m)) t)))

Now what would be the value of

((1)) (1))).
This value is contributed by the third
condi line of o .

21

It would have no value,


because run would never finish
determining the second value.

22

Clearly.

(run (t)
(fresh (n m)
(o n m (1)))
( (n m)) t)))
2

Here is bound-o .

Okay, so this is not the final definition of


bound-o .

(define bound-o
(lambda (q p n m)
(conde
((null o q) (pair o p))
(else
(fresh (x y z )
(cdr o q x )
(cdr o p y)
(condi
((null o n)
(cdr o m z )
(bound-o x y z ()))
(else
(cdr o n z )
(bound-o x y z m))))))))
Is this definition recursive?

Just a Bit More

113

What is the value of

23

(run (t)
(fresh (n m)
(o n m (1)))
( (n m)) t)))
2

What value is associated with p in

24

(run (p)
(o (1 1 1)) (1 1 1 1 1 1)) p))

If we replace a 1 by a 0 in

(1 0 0 1 1 1 0 1 1)),
which contains nine bits.

25

Yes,
because (1 1 1)) and (1 1 1 1 1 1)) represent
the largest numbers of lengths three and
six, respectively. Of course the rightmost 1
in each number cannot be replaced by a 0.

26

Yes, it is.

( (1 1 1)) (1 1 1 1 1 1)) p),


o

is nine still the maximum length of p

Here is the definition of =l o .

(((1)) (1)))),
because bound-o fails when the product of
n and m is larger than p, and since the
length of n plus the length of m is an
upper bound on the length of p.

(define =l o
(lambda (n m)
(conde
(( () n) ( () m))
(( (1)) n) ( (1)) m))
(else
(fresh (a x b y)
( (a ! x ) n) (pos o x )
( (b ! y)) m) (pos o y)
(=l o x y))))))
Is this definition recursive?

What value is associated with t in


(run (t)
(fresh (w x y)
(=l o (1 w x ! y)) (0 1 1 0 1)))
( (w x y)) t)))

114

27

( 2 1))),
1
since y is ( 2 1)), the length of (1 w x ! y))
is the same as the length of (0 1 1 0 1)).

Chapter 8

What value is associated with b in

28

1,

(run (b)
(=l o (1)) (b))))

What value is associated with n in

29

(run (n)
(=l o (1 0 1 ! n)) (0 1 1 0 1))))

What is the value of

30

(run (t)
(fresh (y z )
(=l o (1 ! y)) (1 ! z ))
( (y z ) t)))
5

What is the value of

31

(run (t)
(fresh (y z )
(=l o (1 ! y)) (0 ! z ))
( (y z ) t)))

What is the value of


(run (t)
(fresh (y z )
(=l o (1 ! y)) (0 1 1 0 1 ! z ))
( (y z ) t)))
5

Just a Bit More

1)),
because if n were ( 0 1)), then the length of
(1 0 1 ! n)) would be the same as the
length of (0 1 1 0 1)).

((() ())
((1)) (1)))
(( 0 1)) ( 1 1)))
(( 0 1 1)) ( 2 3 1)))
(( 0 1 2 1)) ( 3 4 5 1)))),
because each y and z must be the same
length in order for (1 ! y)) and (1 ! z ) to
be the same length.

Why isnt (() ()) the first value?

because if b were associated with 0, then


(b)) would have become (0)), which does
not represent a number.

32

33

(((1)) (1)))
(( 0 1)) ( 1 1)))
(( 0 1 1)) ( 2 3 1)))
(( 0 1 2 1)) ( 3 4 5 1)))
(( 0 1 2 3 1)) ( 4 5 6 7 1)))).

Because if z were (), then (0 ! z ) would not


represent a number.

((( 0 1 2 1)) ())


(( 0 1 2 3 1)) (1)))
(( 0 1 2 3 4 1)) ( 5 1)))
(( 0 1 2 3 4 5 1)) ( 6 7 1)))
(( 0 1 2 3 4 5 6 1)) ( 7 8 9 1)))),
because the shortest z is (), which forces y
to be a list of length four. Thereafter, as y
grows in length, so does z .

115

Here is the definition of <l o .

34

(define <l o
(lambda (n m)
(conde
(( () n) (pos o m))
(( (1)) n) (>1o m))
(else
(fresh (a x b y)
( (a ! x ) n) (pos o x )
( (b ! y)) m) (pos o y)
(<l o x y))))))

In the first conde line, ( () m) is replaced


by (pos o m). In the second line, ( (1)) m)
is replaced by (>1o m). This guarantees that
n is shorter than m.

How does this definition differ from the


definition of =l o

What is the value of

35

(run (t)
(fresh (y z )
(<l o (1 ! y)) (0 1 1 0 1 ! z ))
( (y z ) t)))
8

((() 0 )
((1)) 0 )
(( 0 1)) 1 )
(( 0 1 1)) 2 )
(( 0 1 2 1)) ( 3 ! 4 ))
(( 0 1 2 3 1)) ( 4 5 ! 6 ))
(( 0 1 2 3 4 1)) ( 5 6 7 ! 8 ))
(( 0 1 2 3 4 5 1)) ( 6 7 8 9 !

10

))).

Why does z remain fresh in the first four


values?

36

The variable y is associated with a list that


represents a number. If the length of this list
is at most three, then (1 ! y)) is shorter than
(0 1 1 0 1 ! z ), regardless of the value
associated with z .

What is the value of

37

It has no value.
Clearly the first two conde lines fail. In
the recursive call, x and y are associated
with the same fresh variable, which is
where we started.

(run (n)
(<l o n n))
1

116

Chapter 8

Define !l o using =l o and <l o .

38

Is this correct?
(define !l o
(lambda (n m)
(conde
((=l o n m) #s)
((<l o n m) #s)
(else #u))))

It looks like it might be correct. What is the


value of

39

(run8 (t)
(fresh (n m)
(!l o n m)
( (n m)) t)))

What value is associated with t in

40

((() ())
((1)) (1)))
(( 0 1)) ( 1 1)))
(( 0 1 1)) ( 2 3 1)))
(( 0 1 2 1)) ( 3 4 5 1)))
(( 0 1 2 3 1)) ( 4 5 6 7 1)))
(( 0 1 2 3 4 1)) ( 5 6 7 8 9 1)))
(( 0 1 2 3 4 5 1)) ( 6 7 8 9 10

11

1))))

(() ()).

(run (t)
(fresh (n m)
(!l o n m)
(o n (0 1)) m)
( (n m)) t)))
1

What is the value of


(run (t)
(fresh (n m)
(!l o n m)
(o n (0 1)) m)
( (n m)) t)))
2

Just a Bit More

41

It has no value,
because the first conde line of !l o always
succeeds, which means that n and m are
always the same length. Therefore
(o n (0 1)) m) succeeds only when n is ().

117

How can we redefine !l o so that

42

(run2 (t)
(fresh (n m)
(!l o n m)
(o n (0 1)) m)
( (n m)) t)))

(define !l o
(lambda (n m)
(condi
((=l o n m) #s)
((<l o n m) #s)
(else #u))))

has a value?

What is the value of

43

(run (t)
(fresh (n m)
(!l o n m)
(o n (0 1)) m)
( (n m)) t)))
10

Now what is the value of

44

(run (t)
(fresh (n m)
(!l o n m)
( (n m)) t)))
15

Do these values include all of the values


produced in frame 39?

118

Lets use condi .

45

((() ())
((1)) (0 1)))
((0 1)) (0 0 1)))
((1 1)) (0 1 1)))
((0 0 1)) (0 0 0 1)))
((1 0 1)) (0 1 0 1)))
((0 1 1)) (0 0 1 1)))
((0 0 0 1)) (0 0 0 0 1)))
((1 0 1 1)) (0 1 0 1 1)))
((0 1 0 1)) (0 0 1 0 1)))).

((() ())
(() ( 0 " 1 ))
((1)) (1)))
((1)) ( 0 1 " 2 ))
(( 0 1)) ( 1 1)))
(( 0 1)) ( 1 2 3 " 4 ))
(( 0 1 1)) ( 2 3 1)))
(( 0 1 1)) ( 2 3 4 5 " 6 ))
(( 0 1 2 1)) ( 3 4 5 1)))
(( 0 1 2 1)) ( 3 4 5 6 7 " 8 ))
(( 0 1 2 3 1)) ( 4 5 6 7 1)))
(( 0 1 2 3 1)) ( 4 5 6 7 8 9 " 10 ))
(( 0 1 2 3 4 1)) ( 5 6 7 8 9 1)))
(( 0 1 2 3 4 1)) ( 5 6 7 8 9 10 11 " 12 ))
(( 0 1 2 3 4 5 1)) ( 6 7 8 9 10 11 1)))).

Yes.

Chapter 8

Here is the definition of <o .

46

(define <o
(lambda (n m)
(condi
((<l o n m) #s)
((=l o n m)
(fresh (x )
(pos o x )
(+o n x m)))
(else #u))))

That is easy.
(define !o
(lambda (n m)
(condi
(( n m) #s)
((<o n m) #s)
(else #u))))

Define !o using <o .


What value is associated with q in

47

(run (q)
(<o (1 0 1)) (1 1 1)))
( #t q))

What is the value of

48

(run (q)
(<o (1 1 1)) (1 0 1)))
( #t q))

What is the value of

49

(run (q)
(<o (1 0 1)) (1 0 1)))
( #t q))

What is the value of

50

(run6 (n)
(<o n (1 0 1))))

What is the value of


(run (m)
(<o (1 0 1)) m))
6

Just a Bit More

51

#t,
since five is less than seven.

(),
since seven is not less than five.

(),
since five is not less than five. But if we
were to replace <o with !o , the value
would be (#t)).

(() (0 0 1)) (1)) ( 0 1))),


since ( 0 1)) represents the numbers two
and three.

((

"

) (0 1 1)) (1 1 1))),
since ( 0 1 2 3 " 4 ) represents all the
numbers greater than seven.
0

119

What is the value of

52

It has no value,
since <o calls <l o .

53

((() ( 0 ! 1 ) () ())
((1)) (1)) (1)) ())
((0 1)) (1 1)) () (0 1)))
((0 1)) (1)) (0 1)) ())
((1)) ( 0 1 ! 2 ) () (1)))
(( 0 1)) ( 0 1)) (1)) ())
((0 0 1)) (1 0 1)) () (0 0 1)))
((0 0 1)) ( 0 1)) (0 1)) ())
(( 0 1)) ( 1 2 3 ! 4 ) () ( 0 1)))
((1 1)) (0 1)) (1)) (1)))
((0 0 1)) (0 1 1)) () (0 0 1)))
((1 1)) (1)) (1 1)) ())
(( 0 1 1)) ( 2 3 4 5 ! 6 ) () ( 0
(( 0 1 1)) ( 0 1 1)) (1)) ())
((1 0 1)) (0 1 1)) () (1 0 1)))).

(run (n)
(<o n n))

What is the value of


(run (t)
(fresh (n m q r )
(o n m q r )
( (n m q r ) t)))
15

1)))

o divides n by m, producing a quotient q


and remainder r .
List all of the values that contain variables.

Does the third value (( 0 1)) (


represent two ground values?

1)) (1)) ())

Do the fourth and fifth values in frame 54


each represent two ground values?

120

54

((() ( 0 ! 1 ) () ())
((1)) ( 0 1 ! 2 ) () (1)))
(( 0 1)) ( 0 1)) (1)) ())
((0 0 1)) (1 0 1)) () (0 0 1)))
((0 0 1)) ( 0 1)) (0 1)) ())
(( 0 1)) ( 1 2 3 ! 4 ) () ( 0 1)))
(( 0 1 1)) ( 2 3 4 5 ! 6 ) () ( 0
(( 0 1 1)) ( 0 1 1)) (1)) ())).

55

Yes.
(( 0 1)) ( 0 1)) (1)) ())
represents the two values
((0 1)) (0 1)) (1)) ()) and
((1 1)) (1 1)) (1)) ()).

56

Yes.

1)))

Chapter 8

Does the eighth value in frame 54,


((

1)) (

57

Yes.
(( 0 1 1)) ( 0 1 1)) (1)) ())
represents the four values
((0 0 1)) (0 0 1)) (1)) ()),
((1 0 1)) (1 0 1)) (1)) ()),
((0 1 1)) (0 1 1)) (1)) ()), and
((1 1 1)) (1 1 1)) (1)) ()).

58

Yes.

59

Yes.
(() ( 0 ! 1 ) () ())
represents the values
(() (1)) () ())
(() (0 1)) () ())
(() (1 1)) () ())
(() (0 0 1)) () ())
(() (1 0 1)) () ())
(() (0 1 1)) () ())
(() (1 1 1)) () ())
(() (0 0 0 1)) () ())
(() (1 0 0 1)) () ())
(() (0 1 0 1)) () ())
(() (1 1 0 1)) () ())
(() (0 0 1 1)) () ())
(() (1 0 1 1)) () ())
...

60

No,
since it is impossible to write every ground
value that is represented by
(() ( 0 ! 1 ) () ()).

61

No.

1)) (1)) ()),

represent four ground values?

So is (( 0 1 1)) ( 0 1 1)) (1)) ()) just


shorthand notation?

Does the first value in frame 54,


(() (

) () ()),

represent ground values?

Is (() ( 0 !
notation?

) () ()) just shorthand

Is it possible to write every ground value


that is represented by the second, sixth, and
seventh values in frame 54?

Just a Bit More

121

How do the first, second, sixth, and seventh


values in frame 54 differ from the other
values in that frame?

62

Define o .

63

With which three cases do the three condi


lines correspond?

Describe the first condi line.

According to the standard definition of


division, division by zero is undefined and
the remainder r must always be less than the
divisor m. Does the first condi line enforce
both of these restrictions?

122

They each contain an improper list whose


last cdr is a variable.

(define o
(lambda (n m q r )
(condi
(( () q) ( n r ) (<o n m))
(( (1)) q) ( () r ) ( n m)
(<o r m))
((<o m n) (<o r m)
(fresh (mq)
(!l o mq n)
(o m q mq)
(+o mq r n)))
(else #u)))).

64

65

66

The cases in which the dividend n is less


than, equal to, or greater than the divisor m,
respectively.

The first condi line divides a number n by a


number m greater than n. Therefore the
quotient is zero, and the remainder is equal
to n.

Yes.
The divisor m is greater than the dividend
n, which means that m cannot be zero.
Also, since m is greater than n and n is
equal to r, we know that m is greater than
the remainder r. By enforcing the second
restriction, we automatically enforce the
first.

Chapter 8

In the second condi line the dividend and


divisor are equal, so the quotient obviously
must be one. Why, then, is the (<o r m)
goal necessary?

67

Describe the first two goals in the third


condi line.

68

Describe the last three goals in the third


condi line.

69

Because this goal enforces both of the


restrictions given in the previous frame.

The goal (<o m n) ensures that the divisor


is less than the dividend, while the goal
(<o r m) enforces the restrictions in
frame 66.

The last three goals perform division in terms


of multiplication and addition. The equation
n
= q with remainder r
m
can be rewritten as
n = m q + r.
That is, if mq is the product of m and q,
then n is the sum of mq and r. Also, since r
cannot be less than zero, mq cannot be
greater than n.

Why does the third goal in the last condi


line use !l o instead of <o

What is the value of


(run (m)
(fresh (r )
(o (1 0 1)) m (1 1 1)) r )))

Just a Bit More

70

71

Because !l o is a more efficient


approximation of <o . If mq is less than or
equal to n, then certainly the length of the
list representing mq cannot exceed the length
of the list representing n.

(),
since it fails.

123

Why is () the value of

72

(run (m)
(fresh (r )
(o (1 0 1)) m (1 1 1)) r )))

How is () the value of

73

(run (m)
(fresh (r )
(o (1 0 1)) m (1 1 1)) r )))

Why do we need the first two condi lines,


given that the third condi line seems so
general? Why dont we just remove the first
two condi lines and remove the (<o m n)
goal from the third condi line, giving us a
simpler definition of o

74

We are trying to find a number m such that


dividing five by m produces seven. Of course,
no such m exists.

The third condi line of o ensures that m is


less than n when q is greater than one.
Therefore o can stop looking for possible
values of m when m reaches four.

Unfortunately, our improved definition of


o has a problemthe expression
(run (m)
(fresh (r )
(o (1 0 1)) m (1 1 1)) r )))

no longer has a value.

(define
(lambda (n m q r )
(fresh (mq)
(<o r m)
(!l o mq n)
(o m q mq)
(+o mq r n))))
o

Why doesnt the expression


(run (m)
(fresh (r )
(o (1 0 1)) m (1 1 1)) r )))
have a value when we use the new definition
of o

124

75

Because the new o does not ensure that m


is less than n when q is greater than one.
Therefore o will never stop trying to find
an m such that dividing five by m produces
seven.

Chapter 8

Hold on! Its going to get subtle!

Here is an improved definition of o which is


more sophisticated than the ones given in
frames 63 and 74. All three definitions
implement division with remainder, which
means that (o n m q r ) satisfies
n = m q + r with 0 ! r < m.
(define o
(lambda (n m q r )
(condi
(( r n) ( () q) (<o n m))
(( (1)) q) (=l o n m) (+o r m n)
(<o r m))
(else
(alli
(<l o m n)
(<o r m)
(pos o q)
(fresh (nh nl qh ql qlm qlmr rr rh )
(alli
(split o n r nl nh )
(split o q r ql qh )
(conde
(( () nh )
( () qh )
(o nl r qlm)
(o ql m qlm))
(else
(alli
(pos o nh )
(o ql m qlm)
(+o qlm r qlmr )
(o qlmr nl rr )
(split o rr r () rh )
(o nh m qh rh )))))))))))

Does the redefined o use any new helper


functions?

Just a Bit More

76

Yes,
the new o relies on split o .
(define split o
(lambda (n r l h)
(condi
(( () n) ( () h) ( () l ))
((fresh (b n
)
( (0 b ! n
) n)
( () r )
( (b ! n
) h)
( () l )))
((fresh (
n)
( (1 ! n
) n)
( () r )
( n
h)
( (1)) l )))
((fresh (b n
a r)
( (0 b ! n
) n)
( (a ! r) r )
( () l )
(split o (b ! n
) r () h)))
((fresh (
n a r)
( (1 ! n
) n)
( (a ! r) r )
( (1)) l )
(split o n
r () h)))
((fresh (b n
a r
l)
( (b ! n
) n)
( (a ! r) r )
( (b !
l)) l )
(pos o
l)
(split o n
r
l h)))
(else #u))))

125

What does split o do?

77

The call (split o n () l h) moves the lowest


bit of n, if any, into l , and moves the
remaining bits of n into h; (split o n (1)) l h)
moves the two lowest bits of n into l and
moves the remaining bits of n into h; and
(split o n (1 1 1 1)) l h),
(split o n (0 1 1 1)) l h), or
(split o n (0 0 0 1)) l h) move the five lowest
bits of n into l and move the remaining bits
into h; and so on.

What else does split o do?

78

Why is split o s definition so complicated?

79

How does split o ensure that (0)) is not


constructed?

What is the value of this expression when


using the original definition of o , as defined
in frame 63?
(run3 (t)
(fresh (y z )
(o (1 0 ! y)) (0 1)) z ())
( (y z ) t)))

126

The lowest bit of a positive number n is the car of n.

Since split o is a relation, it can construct n


by combining the lower-order bits of l with
the higher-order bits of h, inserting padding
bits as specified by the length of r .

Because split o must not allow the list (0)) to


represent a number. For example,
(split o (0 0 1)) () () (0 1))) should succeed,
but (split o (0 0 1)) () (0)) (0 1))) should not.

80

By removing the rightmost zeros after


splitting the number n into its lower-order
bits and its higher-order bits.

81

It has no value.
We cannot divide an odd number by two
and get a remainder of zero. The old
definition of o never stops looking for
values of y and z that satisfy the division
relation, even though no such values exist.
With the latest definition of o as defined
in frame 76, however, the expression fails
immediately.

Chapter 8

Here is log o and its two helper functions.


log o

(define
(lambda (n b q r )
(condi
(( (1)) n) (pos o b) ( () q) ( () r ))
(( () q) (<o n b) (+o r (1)) n))
(( (1)) q) (>1o b) (=l o n b) (+o r b n))
(( (1)) b) (pos o q) (+o r (1)) n))
(( () b) (pos o q) ( r n))
(( (0 1)) b)
(fresh (a ad dd)
(pos o dd)
( (a ad ! dd)) n)
(exp2 o n () q)
(fresh (s)
(split o n dd r s))))
((fresh (a ad add ddd)
(conde
(( (1 1)) b))
(else ( (a ad add ! ddd)) b))))
(<l o b n)
(fresh (bw1 bw nw nw1 ql1 ql s)
(exp2 o b () bw1 )
(+o bw1 (1)) bw )
(<l o q n)
(fresh (q1 bwq1 )
(+o q (1)) q1 )
(o bw q1 bwq1 )
(<o nw1 bwq1 ))
(exp2 o n () nw1 )
(+o nw1 (1)) nw )
(o nw bw ql1 s)
(+o ql (1)) ql1 )
(conde
(( q ql ))
(else (<l o ql q)))
(fresh (bql qh s qdh qd)
(repeated-mul o b ql bql)
(o nw bw1 qh s)
(+o ql qdh qh )
(+o ql qd q)
(conde
(( qd qdh))
(else (<o qd qdh)))
(fresh (bqd bq1 bq)
(repeated-mul o b qd bqd)
(o bql bqd bq)
(o b bq bq1 )
(+o bq r n)
(<o n bq1 )))))
(else #u))))

Just a Bit More

82

(define exp2 o
(lambda (n b q)
(condi
(( (1)) n) ( () q))
((>1o n) ( (1)) q)
(fresh (s)
(split o n b s (1)))))
((fresh (q1 b2 )
(alli
( (0 ! q1 ) q)
(pos o q1 )
(<l o b n)
(append o b (1 ! b)) b2 )
(exp2 o n b2 q1 ))))
((fresh (q1 nh b2 s)
(alli
( (1 ! q1 ) q)
(pos o q1 )
(pos o nh )
(split o n b s nh )
(append o b (1 ! b)) b2 )
(exp2 o nh b2 q1 ))))
(else #u))))
(define repeated-mul o
(lambda (n q nq)
(conde
((pos o n) ( () q) ( (1)) nq))
(( (1)) q) ( n nq))
((>1o q)
(fresh (q1 nq1 )
(+o q1 (1)) q)
(repeated-mul o n q1 nq1 )
(o nq1 n nq)))
(else #u))))

127

Guess what log o does?

83

It builds a split-rail fence.

Not quite. Try again.

84

It implements the logarithm relation:


(log o n b q r ) holds if n = bq + r.

Are there any other conditions that the


logarithm relation must satisfy?

85

There had better be!


Otherwise, the relation would always hold
if q = 0 and r = n 1, regardless of the
value of b.

Give the complete logarithm relation.

86

Does the logarithm relation look familiar?

87

Yes.
The logarithm relation is similar to the
division relation, but with exponentiation
in place of multiplication.

In which ways are log o and o similar?

88

Both log o and o are relations that take four


arguments, each of which can be fresh
variables. The o relation can be used to
define addition, multiplication, and
subtraction. The log o relation is equally
flexible, and can be used to define
exponentiation, to determine exact discrete
logarithms, and even to determine discrete
logarithms with a remainder. The log o
relation can also find the base b that
corresponds to a given n and q.

What value is associated with r in

89

(run (r )
(log o (0 1 1 1)) (0 1)) (1 1)) r ))

128

(log o n b q r ) holds if n = bq + r, where


0 r and q is the largest number that
satisfies the relation.

(0 1 1)),
since 14 = 23 + 6.

Chapter 8

What is the value of

90

(((1)) ( 0 1 ! 2 ) (1 1 0 0 0 0 1)))
(() ( 0 1 ! 2 ) (0 0 1 0 0 0 1)))
((0 1)) (0 1 1)) (0 0 1)))
((0 0 1)) (1 1)) (0 0 1)))
((1 0 1)) (0 1)) (1 1 0 1 0 1)))
((0 1 1)) (0 1)) (0 0 0 0 0 1)))
((1 1 1)) (0 1)) (1 1 0 0 1)))
((0 0 0 1)) (0 1)) (0 0 1)))),
since
68 = 1n + 67 where n is greater than one,
68 = 0n + 68 where n is greater than one,
68 = 26 + 4,
68 = 43 + 4,
68 = 52 + 43,
68 = 62 + 32,
68 = 72 + 19, and
68 = 82 + 4.

91

Thats easy.

(run (s)
(fresh (b q r )
(log o (0 0 1 0 0 0 1)) b q r )
(>1o q)
( (b q r ) s)))
8

Define expo using log o .

(define expo
(lambda (b q n)
(log o n b q ())))

What value is associated with t in


(run (t)
(expo (1 1)) (1 0 1)) t))

92

(1 1 0 0 1 1 1 1)),
which is the same as (build-num 243).

= Time for a banquet; youve earned it. =

THIS IS A NAPKIN!

Just a Bit More

129

Chapter 9

Under the Hood

What is the essence of our style of


definitions?

No. Their job is to manage the order of


values. Try again.

How about car o , cdr o , cons o , null o , eq o , and


pair o ?

Not quite, but closer. One more try.

Well, each of those six definitions rely on ,


so it must be the essence.

But, what about #s and #u

They too are simple goals, but is the


simplest goal that can succeed for some
values and fail for others.

Yes. The definition of relies on unify,


which we are about to discuss.

Okay, lets begin.

Thats easy.

Here are three variables u, v , and w .

conde and condi ?

(define u (var u))

(define x (var x))

(define v (var v))

(define y (var y))

(define w (var w))

(define z (var z))

Define the variables x , y, and z .

Each invocation of var (var is implemented as vector) is


given a symbol and creates a different fresh variable (a
nonempty vector). var? (var? is implemented as vector?)
determines if its argument had been created by var. Prologs
anonymous variable (see page 2 of William F. Clocksin.
Clause and Effect. Springer, 1997.) can be defined as an
identifier macro that expands to (var (quote )). For
discussion of identifier macros, see pages 193 and 204 of
R. Kent Dybvig. The Scheme Programming Language third
ed. MIT Press, 2003; and pages 47 and 48 of Matthias
Felleisen, Robert Bruce Findler, Matthew Flatt, and Shriram
Krishnamurthi. Building little languages with macros.
Dr. Dobbs Journal. April, 2004.

Under the Hood

As a reminder, (define x (var x)) is written as


(define x (var (quote x))).

131

What is

(z ! a))

It is our way of representing an association.


The lhs (left-hand side) of an association
must be a variable. The rhs (right-hand side)
of an association may be any value.

What is the value of

lhs is car and rhs is cdr.

b.

(rhs (z ! b)))
What is the value of

The variable w .

(rhs (z ! w ))
What is the value of

10

The list (x e y)).

(rhs (z ! (x e y))))
What is

11

((z ! a)) (x ! w ) (y ! z ))

It is our way of representing a substitution ,


a list of associations.

Most of this chapter is about substitutions and unification.


Our unify is inspired by Franz Baader and Wayne Snyder.
Unification theory, Chapter 8 of Handbook of Automated
Reasoning, edited by John Alan Robinson and Andrei
Voronkov. Elsevier Science and MIT Press, 2001.

Is

12

Not for us,


since we do not permit associations like
(x ! x ) in which its lhs is the same as its
rhs.

13

It represents a substitution that does not


contain any associations.

((z ! a)) (x ! x ) (y ! z ))
a substitution?

Here is empty-s.
(define empty-s ())
What does it represent?

132

Chapter 9

What is the value of

14

a,

(walk z ((z ! a)) (x ! w ) (y ! z )))

What is the value of

15

a,

(walk y ((z ! a)) (x ! w ) (y ! z )))

What is the value of

The fresh variable w ,


because we walk from x to the rhs of its
association, which is w .

17

The fresh variable w ,


because w is not the lhs of any association.

18

It has no value,
because we never stop walking. The
substitution ((x ! y)) (z ! x ) (y ! z )) is
said to be circular.

(walk w ((z ! a)) (x ! w ) (y ! z )))

What is the value of


(walk x ((x ! y)) (z ! x ) (y ! z )))

What is the value of

because we walk from y to the rhs of its


association, which is z , and we walk from z
to the rhs of its association, which is a.

16

(walk x ((z ! a)) (x ! w ) (y ! z )))

What is the value of

because we walk from z to the rhs of its


association, which is a.

19

(walk w ((x ! y)) (w ! b)) (z ! x ) (y ! z )))

b,

The substitution
((x ! y)) (w ! b)) (z ! x ) (y ! z )) is
circular, but the walk still terminates.

If x is a variable and s is a substitution, does


(walk x s) always have a value?

20

No. See frame 18.

If x is a variable and s is a substitution built


by unify, does (walk x s) always have a
value?

21

Yes.

Under the Hood

133

If a walk has a value, what are the two


possible types of values that it might have?

22

It could be a fresh variable, or it could be a


value that is not a variable.

The value of the expression below is b. What


are the values of the walks of u, v , and w

23

They are also b,


since each walk leads to x , and we know
where x leads.

24

They are also z ,


since each walk leads to x , and we know
where x leads.

(walk x
((y ! b)) (x ! y)) (v ! x ) (w ! x ) (u ! w )))
The value of the expression below is z . What
are the values of the walks of u, v , and w
(walk x
((y ! z ) (x ! y)) (v ! x ) (w ! x ) (u ! w )))
What is the value of

25

The list (x e x ).

(walk u ((x ! b)) (w ! (x e x )) (u ! w )))


Why isnt (b e b)) the value?

Here is the definition of walk.


(define walk
(lambda (v s)
(cond
((var? v )
(cond
((assq v s)
(lambda (a)
(walk (rhs a) s)))
(else v )))
(else v ))))
Is walk recursive?

134

26

The job of walk is to find either a fresh


variable or a non-variable value. In this case
it finds the list (x e x ), which is a
non-variable value. This is a subtle point,
because one could imagine a different version
of walk (frame 47) that would return the
value (b e b)).

27

Yes.

These two expressions are equivalent.

(cond
((assq v s) f )
(else v ))

(let ((a (assq v s)))


(cond
(a (f a))
(else v )))

walk relies on assq, a standard function that we use to find


an association in a substitution.
We could revise fresh (and run) so that it would mark
(by associating a variable with itselfsee frame 12) where in
the substitution we have introduced a fresh variable. We
could then recognize this pair with (eq? (lhs a) (rhs a)), thus
avoiding a recursion and the need to search the entire
substitution.

Chapter 9

When does the recursion happen?

28

When v is the lhs of an association in s.

Consider the definition of ext-s, which


extends a substitution.

29

It has no value,
since the extended substitution is the same
as the one in frame 18.

30

The fresh variable y.

31

e.

32

The fresh variable z .

(define ext-s
(lambda (x v s)
(cons (x ! v ) s)))
What is the value of
(walk x (ext-s x y ((z ! x ) (y ! z ))))

What is the value of


(walk y ((x ! e))))

What is the value of


(walk y (ext-s y x ((x ! e)))))

What is the value of


(walk x ((y ! z ) (x ! y))))

What is the value of

33

b.

(walk x (ext-s z b ((y ! z ) (x ! y)))))

What is the value of

34

w.

35

It is either #f or it is a new substitution. The


new substitution includes the associations of
s and perhaps other associations.

(walk x (ext-s z w ((y ! z ) (x ! y)))))

What is the value of


(unify v w s)
for all values v and w and for all
substitutions s

Under the Hood

135

Here is unify.

36

(define unify
(lambda (v w s)
(let ((v (walk v s))
(w (walk w s)))
(cond
((eq? v w ) s)
((var? v ) (ext-s v w s))
((var? w ) (ext-s w v s))
((and (pair? v ) (pair? w ))
(cond
((unify (car v ) (car w ) s)
(lambda (s)
(unify (cdr v ) (cdr w ) s)))
(else #f)))
((equal? v w ) s)
(else #f)))))

We let-bind v (and w ) to a possibly different


value. Thus, we know that the new binding
of v (and w ) is either to a fresh variable or to
a non-variable value.

Our very simple representation of variables (frame 6)


makes it unsafe to pass vectors, other than variables, as the
first two arguments of unify. We could, however, define
variables in many other ways, but it would unnecessarily
complicate the definitions of var and var?. Nevertheless, the
reader should not hesitate to experiment with refined
definitions of var and var?.

What is the first thing that happens in unify


What is a simple way to improve unify

37

We could determine if v is the same as w


before let-binding v and w .

What is another way to improve unify

38

If we have two variables, we can walk one of


them, but while it is being walked, we can
see if we meet the other. Then, we know that
the two variables unify. This generalizes the
improvement in the previous frame.

39

If v and w are the same, we do not extend


the substitution. Conveniently, this works
whether or not v and w are fresh variables.

What is the purpose of the eq? test?

We are using eq? primarily for comparing two fresh


variables, but we also benefit from the eq? test on some
non-variable values. Furthermore, although we use no
effects, our definitions are not purely functional, since we
rely on eq? to distinguish two variables (nonempty vectors)
that were created at different times. This effect, however,
could be avoided by including a birthdate variable in the
substitution. Each time we would create variables, we would
then extend the substitution with birthdate and the
associated value of birthdate appropriately incremented.

136

Chapter 9

Explain why the next cond line uses var?

40

Because if v is a variable it must be fresh ,


since it has been walked.

This behavior is necessary in order for to satisfy The


Law of Fresh.

And what about the next cond line?

41

Because if w is a variable it must be fresh,


since it has been walked.

The answer of this cond line could be replaced by


(unify w v s), because for a value w and a substitution s,
(walk (walk w s) s) = (walk w s).

What happens when both v and w are pairs?

What is the purpose of the ((equal? v w ) s)


cond line?

What is the value of

42

We unify the car of v with the car of w . If


they successfully unify, we get a new
substitution, which we then use to unify the
cdr of v with the cdr of w .

43

This one is easy. If either v or w is a pair,


and the other is not, then clearly no
substitution exists that can make them
equal. Also, the equal? works for other kinds
of values.

44

(walk x
((y ! (a z c))) (x ! y)) (z ! a))))

What is the value of


(walk x
((y ! (z w c))) (x ! y)) (z ! a))))

Under the Hood

45

(a a c)).
The walked value of x is (a z c)). Then the
walk*ed values of each value in the list are
used to create a new list.

(a w c)).
The walked value of x is (z w c)). Then
the walk*ed values of each value in the list
are used to create a new list.

137

What is the value of

46

(walk y
((y ! (w z c))) (v ! b)) (x ! v ) (z ! x )))

Here is walk .

47

(define walk
(lambda (v s)
(let ((v (walk v s)))
(cond
((var? v ) v )
((pair? v )
(cons
(walk (car v ) s)
(walk (cdr v ) s)))
(else v )))))

(w b c)).
The walked value of y is (w z c)). Then
the walk*ed values of each value in the list
are used to create a new list.

Yes, and its also useful.

Here is project (pronounced proh-ject).

(define-syntax project
(syntax-rules ()
(( (x . . . ) g . . . )
(G (s)
(let ((x (walk x s)) . . . )
((all g . . . ) s))))))
where G (see appendix) is just lambda. project is
syntactically like fresh, but it binds diffferent values to the
lexical variables. project binds walk*ed values, whereas
fresh binds variables using var. For example, the value of
(run (q)
( #f q)
(project (q)
( (not (not q)) q)))

Is walk recursive?

is (#f)
); without projecting q, its value would be (), since q,
which is represented using a vector (frame 6), is considered
to be nonfalse when passed as an argument to not.

How does walk differ from walk if its first


argument is a fresh variable?

48

It doesnt.
If v is a fresh variable, then only the first
cond line of walk is ever considered.
Thus walk and walk behave the same if v
is fresh.

How does walk differ from walk if its first


argument is a nonfresh variable?

49

If its first argument is nonfresh, then the


second cond line of walk must be
considered. Then, if the walked v is a pair,
walk constructs a new pair of the walk of
each value in v , whereas the walked value is
just v . Finally, if the walked value is not a
pair, then walk and walk behave the same.

What property holds with a variable that has


been walked?

50

We know that if the walked variable is itself


a variable, then it must be fresh.

138

Chapter 9

What property holds with a value that has


been walk*ed?

51

Here is the definition of reify-s, whose first


argument is assumed to have been walk*ed
and whose second argument starts out as
empty-s. The result of an invocation of
reify-s is called a reified-name substitution.

52

(define reify-s
(lambda (v s)
(let ((v (walk v s)))
(cond
((var? v )
(ext-s v (reify-name (size-s s)) s))
((pair? v ) (reify-s (cdr v )
(reify-s (car v ) s)))
(else s)))))

(reify-s v empty-s) returns a reified-name


substitution in which each variable in v is
associated with its reified name.

Here is reify-name.

(define reify-name
(lambda (n)
(string!symbol
(string-append " " "." (number!string n)))))
The functions string!symbol, string-append, and
number!string are standard; and size-s is length, which is
also standard.

Describe (reify-s v empty-s).


What is the value of

We know that any variable that appears in


the resultant value must be fresh.

53

).

).

(let ((r (w x y))))


(walk r (reify-s r empty-s)))
What is the value of

54

(let ((r (walk (x y z ) empty-s)))


(walk r (reify-s r empty-s)))

What is the value of

55

).

(let ((r (u (v (w x ) y)) x )))


(walk r (reify-s r empty-s)))
What is the value of
(let ((s ((y ! (z w c w )) (x ! y)) (z ! a)))))
(let ((r (walk x s)))
(walk r (reify-s r empty-s))))

Under the Hood

56

(a

c 0 ),
0
since r s fresh variable w is replaced by the
reified name 0 (see frame 45).

139

If every nonfresh variable has been removed


from a value and every fresh variable has
been replaced by a reified name, what do we
know?

57

Consider the definition of reify, where it is


assumed that its only argument has been
walk*ed.

58

(define reify
(lambda (v )
(walk v (reify-s v empty-s))))
What is the value of
(let ((s ((y ! (z w c w )) (x ! y)) (z ! a)))))
(reify (walk x s)))

Here are ext-s , a new way


to extend a

substitution, and occurs , which it uses.

59

We know that there are no variables in the


resultant value.

(a

c 0 ),
0
since this is just a restatement of frame 56.
Within run, (reify (walk x s)) transforms
the value associated with x by first
removing all nonfresh variables. This is
done by (walk x s), which returns a value
whose variables are fresh. The call to reify
then transforms the walk*ed value,
replacing each fresh variable with its
reified name.

We use ext-s where we used ext-s


in unify,
so here is the definition of unify .

(define ext-s
(lambda (x v s)
(cond

((occurs x v s) #f)
(else (ext-s x v s)))))

(define occurs
(lambda (x v s)
(let ((v (walk v s)))
(cond
((var? v ) (eq? v x ))
((pair? v )
(or

(occurs x (car v ) s)
(occurs x (cdr v ) s)))
(else #f)))))

(define unify
(lambda (v w s)
(let ((v (walk v s))
(w (walk w s)))
(cond
((eq? v w ) s)
((var? v ) (ext-s v w s))
((var? w ) (ext-s w v s))
((and (pair? v ) (pair? w ))
(cond
((unify (car v ) (car w ) s)
(lambda
(s)
(unify (cdr v ) (cdr w ) s)))
(else #f)))
((equal? v w ) s)
(else #f)))))

Where might we want to use ext-s

140

Chapter 9

Why might we want to use ext-s

What is the value of

60

Because we might want to avoid creating a


circular substitution that if passed to walk
might lead to no value.

61

It has no value.

(run1 (x )
( (x ) x ))

What is the value of

62

(run (q)
(fresh (x )
( (x ) x )
( #t q)))
1

What is the value of

63

(run1 (q)
(fresh (x y)
( (x ) y)
( (y)) x )
( #t q)))

What is the value of


1
(x )
(run

(x ) x ))

64

(#t)).
Although the substitution is circular, x is
not reached by the walk of q from within
run.

(#t)).
Although the substitution is circular,
neither x nor y is reached by the walk of q
from within run.

(),

where is the
same as , except that it
relies on unify instead of unify.

Here is .

(define
(lambda (v w )
(G (s)
(cond

((unify v w s) #s)
(else (#u s))))))
where #s and #u are defined in the appendix, and G is just
lambda.

Under the Hood

141

65

What is the value of

It has no value.

(run (x )
(fresh (y z )
( x z )
( (a b z ) y)
( x y)))
1

66

What is the value of

().

(run (x )
(fresh (y z )
( x z )
((a b z ) y)
( x y)))
1

What is the substitution when (


in the previous frame?

When should we use

So, why indeed does


(run (x )
( (x ) x ))
1

x y) fails

67

((y ! (a b z )) (z ! x )).
y) fails because
( x
(occurs x y ((y
! (a b z )) (z ! x )))
returns #t. occurs first finds
ys
association, (a b z ). occurs then searches
(a b z ) and at each step makes sure that
the rhs is walked if it is a variable. When z
is walked, walk returns the fresh variable
x , which means that we have an occurrence
of x in y.

68

When we want to avoid creating a circular


(frame 61) substitution.

69

It has no value because run uses walk (see


frame 58) on x and the circular substitution.
This call of walk , however, has no value.

have no value?

142

Chapter 9

What is the substitution generated by

70

((x ! (x ))), which is a circular substitution.

(run (x )
( (x ) x ))
1

= The end, sort of. Time for vacation. =

This space reserved for

PALM TREES!

Under the Hood

143

Chapter 10

Thin Ice

Does

No,
because the question of the first conda
line is the goal #u, so conda tries the
second line.

Yes,
because the question of the first conda
line is the goal #u, so conda tries the
second line.

No,
because the question of the first conda
line is the goal #s, so conda tries the
answer of the first line.

Yes,
because the question of the first conda
line is the goal #s, so conda tries the
answer of the first line.

(cond
(#u #s)
(else #u))
a

succeed?

conda is written conda and is pronounced con-day.


conda is like the so-called soft-cut (also known as
if-then-else) and is described on page 45 of William F.
Clocksin. Clause and Effect. Springer, 1997.

Does
(cond
(#u #s)
(else #s))
a

succeed?
Does
(cond
(#s #u)
(else #s))
a

succeed?
Does
(conda
(#s #s)
(else #u))
succeed?

What is the value of

(olive)),
because ( olive x ) succeeds; therefore, the
answer of the first conda line is #s. The #s
preserves the association of x to olive.

Thin Ice

145

(run (x )
(conda
(( olive x ) #s)
(( oil x ) #s)
(else #u)))

The Law of conda


If the question of a conda line succeeds, pretend that the remaining
conda lines have been replaced by
a single (else #u).

What does the a stand for in conda

What is the value of

(run (x )
(conda
(( virgin x ) #u)
(( olive x ) #s)
(( oil x ) #s)
(else #u)))
What is the value of

(run (q)
(fresh (x y)
( split x )
( pea y)
(conda
(( split x ) ( x y))
(else #s)))
( #t q))

What value is associated with q in


(run (q)
(fresh (x y)
( split x )
( pea y)
(conda
(( x y) ( split x ))
(else #s)))
( #t q))

146

It stands for a single line, since at most a


single line can succeed.
(),
because ( virgin x ) succeeds, but the
answer of the first conda line fails. We
cannot pretend that ( virgin x ) fails
because we are within neither a conde nor
a condi .

().
( split x ) succeeds, since x is already
associated with split. ( x y) fails,
however, since x and y are associated with
different values.

#t.
( x y) fails, since x and y are associated
with different values. The question of the
first conda line fails, therefore we try the
second conda line, which succeeds.

Chapter 10

Why does the value change when we switch


the order of ( split x ) and ( x y) within
the first conda line?

10

Consider the definition of not-pasta o .

11

(define not-pasta o
(lambda (x )
(conda
(( pasta x ) #u)
(else #s))))

Because only if the question of a conda line


fails do we consider the remaining conda
lines. If the question succeeds, it is as if the
remaining conda lines have been replaced by
a single (else #u).

(spaghetti)),
because x starts out fresh, but the
question (not-pasta o x ) associates x with
pasta, but then fails. Since (not-pasta o x )
fails, we try ( spaghetti x ).

What is the value of


(run (x )
(conda
((not-pasta o x ) #u)
(else ( spaghetti x ))))

Then, what is the value of


(run (x )
( spaghetti x )
(conda
((not-pasta o x ) #u)
(else ( spaghetti x ))))

12

(),
because (not-pasta o x ) succeeds, which
shows the risks involved when using
conda . We cant allow a fresh variable to
become nonfresh as part of a conda
question.

The Third Commandment


If prior to determining the question of a conda
line a variable is fresh, it must remain fresh in the
question of that line.

Thin Ice

147

What is the value of

13

(run (q)
(conda
(always o #s)
(else #u))
( #t q))

What is the value of

14

(run (q)
(condu
(always o #s)
(else #u))
( #t q))

It has no value,
since run never finishes building the list
of #ts.

(#t)),
because condu is like conda , except that
the successful question, here always o ,
succeeds only once.

condu is written condu and is pronounced cond-you.


condu corresponds to committed-choice of Mercury
(so-called once), which is described in Fergus Henderson,
Thomas Conway, Zoltan Somogyi, and David Jeffery. The
Mercury language reference manual. University of
Melbourne Technical Report 96/10, 1996. Mercury was the
first language to effectively combine and extensively use
soft-cuts (frame 1) and committed choice, avoiding the cut of
Prolog. See Lee Naish. Pruning in logic programming.
University of Melbourne Technical Report 95/16, 1995.

What is the value of

15

It has no value,
since run never finishes building the list
of #ts.

16

It stands for uni-, because the successful


question of a condu line succeeds only once.

(run (q)
(condu
(#s always o )
(else #u))
( #t q))

What does the u stand for in condu

148

Chapter 10

17

What is the value of


(run1 (q)
(conda
(always o #s)
(else #u))
#u
( #t q))

18

What is the value of


(run (q)
(condu
(always o #s)
(else #u))
#u
( #t q))
1

It has no value, since always o keeps


succeeding after the outer #u fails.

(),
because condu s successful question
succeeds only once.

The Law of condu


condu behaves like conda , except
that a successful question succeeds only once.

Here is once o .
(define once o
(lambda (g)
(condu
(g #s)
(else #u))))

19

(tea)).
The first conde line of teacup o succeeds.
Since once o s goal can succeed only once,
there are no more values. But, this breaks
The Third Commandment.

What is the value of


(run (x )
(once o (teacup o x )))

Thin Ice

149

What is the value of

20

(run (q)
(once o (sal o never o ))
#u)
1

What is the value of

21

().
The first conde line of sal o succeeds. This
is followed by #u, which fails. Since once o s
goal can succeed only once, this avoids
never o , so the run fails. This use of once o
obeys The Third Commandment.

(tea cup #f)).

(run (r )
(conde
((teacup o r ) #s)
(( #f r ) #s)
(else #u)))

What is the value of

22

(run (r )
(conda
((teacup o r ) #s)
(( #f r ) #s)
(else #u)))

And, what is the value of

23

(run (r )
( #f r )
(conda
((teacup o r ) #s)
(( #f r ) #s)
(else #u)))

What is the value of


(run (r )
( #f r )
(condu
((teacup o r ) #s)
(( #f r ) #s)
(else #u)))

150

24

(tea cup)),
breaking The Third Commandment.

(#f)),
since this value is included in frame 21.

(#f)).
conda and condu often lead to fewer
values than a similar expression that uses
conde . Knowing that helps determine
whether to use conda or condu , or the
more general conde or condi .

Chapter 10

Lets do a bit more arithmetic.

25

Here is bump o .

26

(define bump o
(lambda (n x )
(conde
(( n x ) #s)
(else
(fresh (m)
(o n (1)) m)
(bump o m x ))))))

Okay.

((1 1 1))
(0 1 1))
(1 0 1))
(0 0 1))
(1 1))
(0 1))
(1))
()).

What is the value of


(run (x )
(bump o (1 1 1)) x ))

Here is gen&test o .

27

(define gen&test o
(lambda (op i j k )
(once o
(fresh (x y z )
(op x y z )
( i x )
( j y)
( k z )))))

#t ,
because four plus three is seven, but there
is more.

What value is associated with q in


(run (q)
(gen&test o +o (0 0 1)) (1 1)) (1 1 1)))
( #t q))

What values are associated with x , y, and z


after the call to (op x y z ), where op is +o

Thin Ice

28
0

, (), and

, respectively.

151

What happens next?

What happens after ( i x ) succeeds?

What happens after ( j y) fails?

What happens next?

What happens after ( i x ) fails?

29

30

31

32

33

What happens next?

34

What happens the eighty-second time that


(op x y z ) is called?

35

What happens next?

36

152

( i x ) succeeds,
since i is associated with (0 0 1)) and x is
fresh. As a result, x is associated with
(0 0 1)).

( j y) fails,
since j is associated with (1 1)) and y is
associated with ().

(op x y z ) is tried again, and this time


associates x with (), and both y and z with
( 0 ! 1 ).

( i x ) fails,
since i is still associated with (0 0 1)) and x
is associated with ().

(op x y z ) is tried again and this time


associates both x and y with (1)), and z with
(0 1)).

( i x ) fails,
since i is still associated with (0 0 1)) and x
is associated with (1)).

(op x y z ) associates both x and z with


(0 0 0 ! 1 ), and y with (1 1)).

( i x ) succeeds,
associating x , and therefore z , with
(0 0 1)).

Chapter 10

What happens after ( i x ) succeeds?

What happens after ( j y) succeeds?

37

38

( j y) succeeds,
since both j and y are associated with
(1 1)).

( k z ) succeeds,
since both k and z are associated with
(0 0 1)).

What values are associated with x , y, and z


after the call to (op x y z ) is made in the
body of gen&test o

39

x , y, and z are not associated with any


values, since they are fresh.

What is the value of

40

It has no value.

41

Never.

(run (q)
(gen&test o +o (0 0 1)) (1 1)) (0 1 1))))
1

Can (op x y z ) fail when x , y, and z are


fresh?

Why doesnt
(run1 (q)
(gen&test o +o (0 0 1)) (1 1)) (0 1 1))))
have a value?

Thin Ice

42

(op x y z ) generates various associations for


x y, and z , and then tests ( i x ), ( j y),
and ( k z ) if the given triple of values i , j ,
and k is present among the generated triple
x , y, and z . All the generated triples x , y,
and z satisfy, by definition, the relation op,
+o in our case. If the triple of values i , j ,
and k is so chosen that i + j is not equal to
k , and our definition of +o is correct, then
that triple of values cannot be found among
those generated by +o . (op x y z ) will
continue to generate associations, and the
tests ( i x ), ( j y), and ( k z ) will
continue to reject them. So this run1
expression will have no value.

153

Here is enumerate o .

43

(define enumerate o
(lambda (op r n)
(fresh (i j k )
(bump o n i )
(bump o n j )
(op i j k )
(gen&test o op i j k )
( (i j k ) r ))))
What is the value of
(run (s)
(enumerate o +o s (1 1))))

(((1 1)) (1 1)) (0 1 1)))


((1 1)) (0 1)) (1 0 1)))
((1 1)) (1)) (0 0 1)))
((1 1)) () (1 1)))
((0 1)) (1 1)) (1 0 1)))
((0 1)) (0 1)) (0 0 1)))
((0 1)) (1)) (1 1)))
((0 1)) () (0 1)))
((1)) (1 1)) (0 0 1)))
((1)) (0 1)) (1 1)))
((1)) (1)) (0 1)))
((1)) () (1)))
(() (1 1)) (1 1)))
(() (0 1)) (0 1)))
(() (1)) (1)))
(() () ())).

Describe the values in the previous frame.

44

What is true about the value in frame 43?

45

All such triples?

46

It seems so.

Can we be certain without counting and


analyzing the values? Can we be sure just by
looking at the values?

47

Thats confusing.

154

The values are arranged into four groups of


four values. Within the first group, the first
value is always (1 1)); within the second
group, the first value is always (0 1)); etc.
Then, within each group, the second value
ranges from (1 1)) to (), consecutively. And
the third value, of course, is the sum of first
two values.

It appears to contain all triples (i j k ) where


i + j = k with i and j ranging from () to
(1 1)).

Chapter 10

Okay, suppose one of the triples were


missing. For example, suppose
((0 1)) (1 1)) (1 0 1))) were missing.

48

But how could that be? We know


(bump o n i ) associates i with the numbers
within the range () through n. So if we try it
enough times, we eventually get all such
numbers. The same is true for (bump o n j ).
So, we definitely will determine (op i j k )
when i is (0 1)) and j is (1 1)), which will
then associate k with (1 0 1)). We have
already seen that.

Then what happens?

49

Then we will try to find if


(gen&test o +o i j k ) can succeed, where i is
(0 1)), j is (1 1)), and k is (1 0 1)).

At least once?

50

Yes,
since we are interested in only one value.
We first determine (op x y z ), where x , y,
and z are fresh. Then we see if that result
matches ((0 1)) (1 1)) (1 0 1))). If not, we
try (op x y z ) again, and again.

What if such a triple were found?

51

Then gen&test o would succeed, producing


the triple as the result of enumerate o . Then,
because the fresh expression in gen&test o is
wrapped in a once o , we would pick a new
pair of i -j values, etc.

What if we were unable to find such a triple?

52

Then the run expression would have no


value.

Why would it have no value?

53

Thin Ice

If no result of (op x y z ) matches the desired


triple, then, as in frame 40, we would keep
trying (op x y z ) forever.

155

So can we say that

54

(run (s)
(enumerate o +o s (1 1))))

Yes, thats clear.


If one triple were missing, we would have
no value at all!

produces all such triples (i j k ) where


i + j = k with i and j ranging from ()
through (1 1)), just by glancing at the value?

So what does enumerate o determine?

55

What is the value of

56

It determines that (op x y z ) with x , y, and


z being fresh eventually generates all triples
where x + y = z. At least, enumerate o
determines that for numbers x and y being
() through some n.

(((1 1 1)) (1 1 1)) (0 1 1 1)))).

(run (s)
(enumerate o +o s (1 1 1))))
1

How does this definition of gen-adder o differ


from the one in 7:118?

57

The definition in chapter 7 has an alli ,


whereas this definition uses all.

(define gen-adder o
(lambda (d n m r )
(fresh (a b c e x y z )
( (a ! x ) n)
( (b ! y)) m) (pos o y)
( (c ! z ) r ) (pos o z )
(all
(full-adder o d a b c e)
(adder o e x y z )))))

What is the value of

58

It has no value.

(run1 (q)
(gen&test o +o (0 1)) (1 1)) (1 0 1))))
using the second definition of gen-adder o

156

Chapter 10

59

Why doesnt
(run1 (q)
(gen&test o +o (0 1)) (1 1)) (1 0 1))))

When using all instead of alli , things can get


stuck.

have a value?

Where does the second definition of


gen-adder o get stuck?

60

If a, b, c, d , x , y, and z are all fresh, then


(full-adder o d a b c e) finds such bits where
d + a + b = c + 2 e and (adder o e x y z ) will
find the rest of the numbers. But there are
several ways to solve this equation. For
example, both 0 + 0 + 0 = 0 + 2 0 and
0 + 1 + 0 = 1 + 2 0 work. Because
(adder o e x y z ) keeps generating new x , y,
and z forever, we never get a chance to
explore other values. Because
(full-adder o d a b c e) is within an all, not
an alli , the (full-adder o d a b c e) gets stuck
on its first value.

Good. Lets see if it is true. Redo the effort


of frame 103 and frame 115 but using the
second definition of gen-adder o . What do we
discover?

61

Some things are missing like


((1)) (1 1 0 0 ! 1 ) (0 0 1 0 !
and ((0 1)) (1 1)) (1 0 1))).

If something is missing because we are using


the second definition of gen-adder o , can we
predict the value of

62

Of course, we know that it has no value.

63

Yes, of course.

))

(run (q)
(enumerate o +o q (1 1 1))))

Can log o and o also be enumerated?

= Get ready to connect the wires. =

Thin Ice

157

Appendix A

Connecting the Wires

A goal g is a function that maps a substitution s to an ordered sequence s of zero or more


substitutions. (For clarity, we notate lambda as G when creating such a function g.) Because
the sequence of substitutions may be infinite, we represent it not as a list but a stream.
Streams contain either zero, one, or more substitutions.1 We use (mzero) to represent the
empty stream of substitutions. For example, #u maps every substitution to (mzero). If a is
a substitution, then (unit a) represents the stream containing just a. For instance, #s maps
every substitution s to just (unit s). The goal created by an invocation of the operator
maps a substitution s to either (mzero) or to a stream containing a single (possibly extended)
substitution, depending on whether that goal fails or succeeds. To represent a stream containing
multiple substitutions, we use (choice a f ), where a is the first substitution in the stream, and
where f is a function of zero arguments. Invoking the function f produces the remainder of the
stream, which may or may not be empty. (For clarity, we notate lambda as F when creating
such a function f .)
When we use the variable a rather than s for substitutions, it is to emphasize that this
representation of streams works for other kinds of data, as long as a datum is never #f or a pair
whose cdr is a functionin other words, as long as the three cases above are never represented
in overlapping ways. To discriminate among the cases we define the macro case .
The second case is redundant in this representation: (unit a) can be represented as
(choice a (F () #f)). We include unit, which avoids building and taking apart pairs and
invoking functions, because many goals never return multiple substitutions. run converts a
stream of substitutions s to a list of values using map .
Two streams can be merged either by concatenating them using mplus (also known as streamappend) or by interleaving them using mplusi . The only difference between the definitions mplus
and mplusi lies in the recursive case: mplusi swaps the two streams; mplus does not.
Given a stream s and a goal g, we can feed each value in s to the goal g to get a
new stream, then merge all these new streams together using either mplus or mplusi . When
using mplus, this operation is called monadic2 bind, and it is used to implement the conjunction
all. When using mplusi , this operation is called bind i , and it is used to implement the fair
conjunction alli . The operators all and alli are like and, since they are short-circuiting: the
false value short-circuits and, and any failed goal short-circuits all and alli . Also, the let in the
third clause of all-aux ensures that (all e), (alli e), (all e #s), and (alli e #s) are equivalent
to e, even if the expression e has no value. The addition of the superfluous second clause allows
all-aux expressions to expand to simpler code.
To take the disjunction of goals we define conde , and to take the fair disjunction we define
condi . They combine successive question-answer lines using mplus and mplusi , respectively.
Two stranger kinds of disjunction are conda and condu . When a question g0 succeeds, both
conda and condu skip the remaining lines. However, condu chops off every substitution after
the first produced by g0 , whereas conda leaves the stream produced by g0 intact.
1 See Philip L. Wadler. How to replace failure by a list of successes: a method for exception handling, backtracking, and pattern matching in lazy functional languages. Functional Programming Languages and Computer
Architecture, Lecture Notes in Computer Science 201, Springer, pages 113128; J. Michael Spivey and Silvija
Seres. Combinators for logic programming. The Fun of Programming. Palgrave; and Mitchell Wand and Dale
Vaillancourt. Relating Models of Backtracking. Ninth International Conference on Functional Programming.
2004, pages 5465.
2 See Eugenio Moggi. Notions of computation and monads. Information and Computation 93(1):5592, 1991;
Philip L. Wadler. The essence of functional programming. Nineteenth Symposium on Principles of Programming
Languages. 1992, pages 114; and Ralf Hinze. Deriving backtracking monad transformers. Fifth International
Conference on Functional Programming. 2000, pages 186197.

Connecting the Wires

159

(define-syntax run
9 : 6, 13, 47, 58
(syntax-rules ()
(( n
(x ) g . . . )
(let ((n n
) (x (var x)))
(if (or (not n) (> n 0))

(map n
(lambda (s)
(reify (walk x s)))
((all g . . . ) empty-s))
())))))

(define-syntax mzero
(syntax-rules ()
(( ) #f)))
(define-syntax unit
(syntax-rules ()
(( a) a)))
(define-syntax choice
(syntax-rules ()
(( a f ) (cons a f ))))

(define-syntax case
(syntax-rules ()
(( e on-zero ((
a) on-one) ((a f ) on-choice))

(let ((a e))


(cond

((not a ) on-zero)
((not (and

(pair? a )

(procedure? (cdr a ))))

(let ((
a a ))
on-one))

(else (let ((a (car a )) (f (cdr a )))


on-choice)))))))

(define map

(lambda (n p a )

(case a
()
((a)
(cons (p a) ()))
((a f )
(cons (p a)
(cond

((not n) (map n p (f )))

((> n 1) (map ( n 1) p (f )))


(else ())))))))

(define-syntax all
(syntax-rules ()
(( g . . . ) (all-aux bind g . . . ))))

(define #s (G (s) (unit s)))


(define #u (G (s) (mzero)))
(define
(lambda (v w )
(G (s)
(cond
((unify v w s) #s)
(else (#u s))))))
(define-syntax fresh
(syntax-rules ()
(( (x . . . ) g . . . )
(G (s)
(let ((x (var x)) . . . )
((all g . . . ) s))))))
(define-syntax conde
(syntax-rules ()
(( c . . . ) (cond-aux if e c . . . ))))

160

9 : 27, 36

(define-syntax alli
(syntax-rules ()
(( g . . . ) (all-aux bind i g . . . ))))
(define-syntax condi
(syntax-rules ()
(( c . . . ) (cond-aux if i c . . . ))))

9:6
(define-syntax conda
(syntax-rules ()
(( c . . . ) (cond-aux if a c . . . ))))
(define-syntax condu
(syntax-rules ()
(( c . . . ) (cond-aux if u c . . . ))))

Appendix A

(define mplus

(lambda (a f )

(case a
(f )
((a) (choice a f ))
((a f0 ) (choice a
(F () (mplus (f0 ) f )))))))

(define mplusi

(lambda (a f )

(case a
(f )
((a) (choice a f ))
((a f0 ) (choice a
(F () (mplusi (f ) f0 )))))))

(define bind

(lambda (a g)

(case a
(mzero)
((a) (g a))
((a f ) (mplus (g a)
(F () (bind (f ) g)))))))

(define bind i

(lambda (a g)

(case a
(mzero)
((a) (g a))
((a f ) (mplusi (g a)
(F () (bind i (f ) g)))))))

(define-syntax cond-aux
(syntax-rules (else)
(( ifer ) #u)
(( ifer (else g . . . )) (all g . . . ))
(( ifer (g . . . )) (all g . . . ))
(( ifer (g0 g . . . ) c . . . )
(ifer g0
(all g . . . )
(cond-aux ifer c . . . )))))

(define-syntax all-aux
(syntax-rules ()
(( bnd) #s)
(( bnd g) g)
(( bnd g0 g . . . )
(let ((
g g0 ))
(G (s)
(bnd (
g s)
(G (s) ((all-aux bnd g . . . ) s))))))))

if e

(define-syntax if i
(syntax-rules ()
(( g0 g1 g2 )
(G (s)
(mplusi ((all g0 g1 ) s) (F () (g2 s)))))))

(define-syntax
(syntax-rules ()
(( g0 g1 g2 )
(G (s)
(mplus ((all g0 g1 ) s) (F () (g2 s)))))))

(define-syntax if a
(syntax-rules ()
(( g0 g1 g2 )
(G (s)

(let ((s (g0 s)))



(case s
(g2 s)
((s) (g1 s))

((s f ) (bind s g1 ))))))))

Connecting the Wires

(define-syntax if u
(syntax-rules ()
(( g0 g1 g2 )
(G (s)

(let ((s (g0 s)))



(case s
(g2 s)
((s) (g1 s))
((s f ) (g1 s))))))))

161

Appendix B

Welcome to the Club

Here is a small collection of entertaining and illuminating books.


Carroll, Lewis. The Annotated Alice: The Definitive Edition. W. W. Norton &
Company, New York, 1999. Introduction and notes by Martin Gardner.
Hein, Piet. Grooks. The MIT Press, 1960.
Hofstadter, Douglas R. G
odel, Escher, Bach: an Eternal Golden Braid. Basic Books,
Inc., 1979.
Nagel, Ernest, and James R. Newman. G
odels Proof. New York University Press, 1958.
Smullyan, Raymond. To Mock a Mockingbird. Alfred A. Knopf, Inc., 1985.
Suppes, Patrick. Introduction to Logic. Van Nostrand Co., 1957.

Welcome to the Club

163

Index
Italic page numbers refer to definitions.

+o (+o), ix, 106


o (-o), 106
o (*o), ix, 111
o (/o), 122
simplified, incorrect version, 124
sophisticated version using split o , 125
!l o (<=lo), 117
using condi instead of conde , 118
o
! (<=o), 119
<l o (<lo), 116
<o (<o), 119
(==), ix, 4, 159, 160
(==-check), 141
(=>), 134
=l o (=lo), 114
>1o (>1o), 98
#s (succeed), ix, 3, 159, 160
#u (fail), ix, 3, 159, 160
F , 159
G , 159
adder o , 104
all, 82, 159, 160
alli (alli), 159, 160
all-aux, 159, 161
always o , 77
and macro, ix
anonymous variable, 131
answer (of a cond line), 10
any o , 77
append, 61
append o , 62
Index

swapping last two goals, 66


using cons o , 63
arithmetic, ix
arithmetic operators
+o , ix, 106
o , 106
o , ix, 111
o , 122
simplified, incorrect version, 124
sophisticated version using split o , 125
!l o , 117
using condi instead of conde , 118
!o , 119
<l o , 116
<o , 119
=l o , 114
>1o , 98
adder o , 104
build-num, 93
shows non-overlapping property, 93
expo , 129
gen-adder o , 104
using all instead of alli , 156
log o , ix, 127
pos o , 97
associate (a value with a variable), 4
association, 132
assq, 134
Baader, Franz, 132
bind, 159, 161
bind i (bindi), 161
165

birthdate, 136
bit operators
bit-and o , 88
bit-nand o , 87
bit-not o , 88
bit-xor o , 87
full-adder o , 89
half-adder o , 89
bit-and o , 88
bit-nand o , 87
bit-not o , 88
bit-xor o , 87
Boole, George, 4
Boolean value, 4
bound-o (bound-*o), 113
hypothetical definition, 113
build-num, 93
shows non-overlapping property, 93
bump o , 151
car, 17
car o , 17, 18
Carroll, Lewis, 163
carry bit, 104
case (case-inf), 159, 160
cdr, 19
cdr o , 19
choice, 159, 160
Clocksin, William F., 11, 61, 131, 145
Commandments
The First Commandment, 28
The Second Commandment, 48
The Third Commandment, 147
committed-choice, 148
cond macro, ix
(=>), 134
conda (conda), 145, 159, 160
conda -line answer, 145
conda -line question, 145
conde (conde), ix, 11, 159, 160
conde -line answer, 11
conde -line question, 11
condi (condi), 80, 159, 160
condu (condu), 148, 159, 160
cond-aux, 161
conjunction, 159. See also all
fair, 159 (see also alli )
166

cons o , 20, 21
continuation-passing style (CPS), 19
Conway, Thomas, 148
co-refer, 9
cut operator, 148
Dijkstra, Edsger W., 93
discrete logarithm. See log o
disjunction, 159. See also conde
fair, 159 (see also condi )
Dybvig, R. Kent, 131
empty-s, 132
enumerate o , 154
eq-car?, 36
eq-car o , 36
eq?, 22, 136, 140
used to distinguish between variables, 136
eq o , 23
exp2 o (help function for log o ), 127
expo , 129
ext-s,135
ext-s (ext-s-check), 140
fail (#u), ix, 3, 159, 160
fair conjuction, 159. See also alli
fair disjunction, 159. See also condi
Felleisen, Matthias, 131
Findler, Robert Bruce, 131
The First Commandment, 28
first-value, 44
Flatt, Matthew, 131
flatten, 71
flatten o , 71
flattenrev o , 74
food, x
fresh, ix, 6, 160
fresh variable, 6
full-adder o , 89
functional programming, ix
functions (as values), ix, 3
Gardner, Martin, 163
gen&test o , 151
gen-adder o , 104
using all instead of alli , 156
goal, 3, 159
Index

ground value, 100


half-adder o , 89
Haskell, x
Hein, Piet, 163
Henderson, Fergus, 148
Herbrand, Jacques, 10
Hofstadter, Douglas R., 163
identifier macro, 131
identity, 38
if a (ifa), 161
if e (ife), 161
if i (ifi), 161
if u (ifu), 161
implementation
,159, 160
, 141
#s, 159, 160
#u, 159, 160
all, 159, 160
all-aux, 159, 161
alli , 159, 160
bind, 159, 161
bind i , 161
case , 159, 160
choice, 159, 160
cond-aux, 161
conda , 159, 160
conde , 159, 160
condi , 159, 160
condu , 159, 160
empty-s, 132
ext-s,135
ext-s , 140
fresh, 160
if a , 161
if e , 161
if i , 161
if u , 161
lhs, 132
map , 159, 160
mplus, 159, 161
mplusi , 159, 161
mzero,
159, 160
occurs , 140
reify, 140
Index

reify-name, 7, 17, 139


reify-s, 139
rhs, 132
run, 159, 160
size-s, 139
unify,136
unify , 140
unit, 159, 160
var, 131
var?, 131
walk, 133, 134
walk , 138
Jeffery, David, 148
Krishnamurthi, Shriram, 131
Lambda the Ultimate, 3
lambda-limited, 68
The Law of , 7
The Law of conda , 146
The Law of conde , 12
The Law of condi , 81
The Law of condu , 149
The Law of Fresh, 7
length, 139
let macro, ix
lexical variable, 138
lhs, 132
list-of-lists?. See lol?
list?, 27
list o , 27
listof o , 35
ll (help function for lambda-limited), 68
logic programming, ix
log o , ix, 127
lol?, 30
lol o , 30
lot o , 33
using listof o and twins o , 35
macros
LATEX, x
identifier, 131
Scheme, ix
map (map-inf), 159, 160
mem, 47
167

memo , 48
simplified definition, 50
member?, 36
member o , 36
memberrev o , 44
Mercury, 148
soft-cut operator, 148
Moggi, Eugenio, 159
monadic operation, 159
mplus, 159, 161
mplusi (mplusi), 159, 161
mzero, 159, 160
n-representative, 99
Nagel, Ernest, 163
Naish, Lee, 148
never o , 77
Newman, James R., 163
non-overlapping property, 93
notational conventions, ix
not-pasta o , 147
no value (for an expression), 29
null?, 21
null o , 22
number!string, 139

occurs (occurs-check), 140


odd-o (odd-*o), 112
once o , 149, 151
pair o , 24
pmember o , 40
with additional conde line, 41
testing that cdr is not the empty list, 42
swapping first and second conde lines, 43
o
pos , 97
programming languages
Haskell, x
Mercury, 148
soft-cut operator, 148
Prolog, ix
cut operator, 148
anonymous variable, 131
Scheme, ix
macros, ix
project, 138
Prolog, ix
168

cut operator, 148


anonymous variable, 131
proper list, 27
punctuation, ix
question (of a cond line), 10
refresh (a variable), 11
reified
name, 8
variable, 8
reify, 140
reify-name, 7, 17, 139
reify-s, 139
relational programming, ix
relations
partitioning into unnamed functions, x
rember, 51
rember o , 51
redefined using cons o , 52
repeated-mul o (help function for log o ), 127
reverse-list, 45
rhs, 132
Robinson, John Alan, 132
run, 12, 159, 160
run (run #f), 4
sal o , 78
Scheme, ix
macros, ix
The Second Commandment, 48
Seres, Silvija, 159
share, 9
short-circuit operators, 159
size-s, 139
Skolem, Thoralf Albert, 8
SLATEX, x
Smullyan, Raymond, 163
Snyder, Wayne, 132
soft-cut operator, 11, 145, 148
Somogyi, Zoltan, 148
Spivey, J. Michael, 159
split o (help function for o ), 125
stream, 159
stream-append, 159
string-append, 139
string!symbol, 139
Index

substitution, 132, 159


reified name, 139
succeed (#s), ix, 3, 159, 160
superscripts. See notational conventions
Suppes, Patrick, 163
surprise o , 58
swappend o , 67
using lambda-limited, 68
teacup o , 14
The Little LISPer, 3
The Little Schemer, ix, 3
The Third Commandment, 147
twin, 31
twins o , 32
without using cons o , 33
unification, 132
unify, 4, 136. See also
improvements
to, 136

unify (unify-check), 140. See also


unit, 159, 160
unnamed functions, x
unnesting a goal, 19

Index

unwrap, 68
unwrap o , 69
with swapped conde lines, 70
Vaillancourt, Dale, 159
value of a run/run expression, 5
var, 131, 136
var?, 131, 136
variable
anonymous, 131
fresh, 6
lexical, 138
reified, 8
vector, 131
vector (cannot pass to unify), 136
vector?, 131
Voronkov, Andrei, 132
Wadler, Philip L., 159
walk, 133, 134
walk (walk*), 138
Wand, Mitchell, 159
width (of a number), 102

169

You might also like