100% found this document useful (5 votes)
55 views

AI algorithms data structures and idioms in Prolog Lisp and Java 6th Edition George F. Luger 2024 scribd download

algorithms

Uploaded by

kuitaroeyen
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (5 votes)
55 views

AI algorithms data structures and idioms in Prolog Lisp and Java 6th Edition George F. Luger 2024 scribd download

algorithms

Uploaded by

kuitaroeyen
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 81

Download the full version of the ebook at

https://ebookultra.com

AI algorithms data structures and idioms in


Prolog Lisp and Java 6th Edition George F.
Luger

https://ebookultra.com/download/ai-algorithms-
data-structures-and-idioms-in-prolog-lisp-and-
java-6th-edition-george-f-luger/

Explore and download more ebook at https://ebookultra.com


Recommended digital products (PDF, EPUB, MOBI) that
you can download immediately if you are interested.

Data Structures and Algorithms in Java 6th Edition Michael


T. Goodrich

https://ebookultra.com/download/data-structures-and-algorithms-in-
java-6th-edition-michael-t-goodrich/

ebookultra.com

Artificial Intelligence Structures and Strategies for


Complex Problem Solving 6th Edition George F. Luger

https://ebookultra.com/download/artificial-intelligence-structures-
and-strategies-for-complex-problem-solving-6th-edition-george-f-luger/

ebookultra.com

Data Structures and Algorithms in Java 4th Edition Michael


T. Goodrich

https://ebookultra.com/download/data-structures-and-algorithms-in-
java-4th-edition-michael-t-goodrich/

ebookultra.com

Learning F Functional Data Structures and Algorithms 1st


Edition Masood

https://ebookultra.com/download/learning-f-functional-data-structures-
and-algorithms-1st-edition-masood/

ebookultra.com
Artificial Intelligence Structures and Strategies for
Complex Problem Solving 5th Edition George F. Luger

https://ebookultra.com/download/artificial-intelligence-structures-
and-strategies-for-complex-problem-solving-5th-edition-george-f-luger/

ebookultra.com

Java Collections An Introduction to Abstract Data Types


Data Structures and Algorithms 1st Edition David A. Watt

https://ebookultra.com/download/java-collections-an-introduction-to-
abstract-data-types-data-structures-and-algorithms-1st-edition-david-
a-watt/
ebookultra.com

Growing Algorithms and Data Structures 4th Edition David


Scuse

https://ebookultra.com/download/growing-algorithms-and-data-
structures-4th-edition-david-scuse/

ebookultra.com

Data Structures Algorithms In Go 1st Edition Hemant Jain

https://ebookultra.com/download/data-structures-algorithms-in-go-1st-
edition-hemant-jain/

ebookultra.com

Learning JavaScript Data Structures and Algorithms 2nd


Edition Loiane Groner

https://ebookultra.com/download/learning-javascript-data-structures-
and-algorithms-2nd-edition-loiane-groner/

ebookultra.com
AI algorithms data structures and idioms in Prolog Lisp
and Java 6th Edition George F. Luger Digital Instant
Download
Author(s): George F. Luger, William A. Stubblefield
ISBN(s): 9780136070474, 0136070477
Edition: 6
File Details: PDF, 2.27 MB
Year: 2009
Language: english
Luger_all_wcopyright_COsfixed.pd2 2 5/15/2008 6:34:39 PM
AI Algorithms, Data Structures, and
Idioms in Prolog, Lisp, and Java

Luger_all_wcopyright_COsfixed.pd1 1 5/15/2008 6:34:39 PM


Luger_all_wcopyright_COsfixed.pd2 2 5/15/2008 6:34:39 PM
AI Algorithms, Data Structures, and
Idioms in Prolog, Lisp, and Java

George F. Luger
William A. Stubblefield

Luger_all_wcopyright_COsfixed.pd3 3 5/15/2008 6:34:39 PM


Executive Editor Michael Hirsch
Acquisitions Editor Matt Goldstein
Editorial Assistant Sarah Milmore
Managing Editor Jeff Holcomb
Digital Assets Manager Marianne Groth
Senior Media Producer Bethany Tidd
Marketing Manager Erin Davis
Senior Author Support/
Technology Specialist Joe Vetere
Senior Manufacturing Buyer Carol Melville
Text Design, Composition, and Illustrations George F Luger
Cover Design Barbara Atkinson
Cover Image © Tom Barrow

Many of the designations used by manufacturers and sellers to distinguish their products are claimed as
trademarks. Where those designations appear in this book, and Addison-Wesley was aware of a
trademark claim, the designations have been printed in initial caps or all caps.

Copyright © 2009 Pearson Education, Inc. All rights reserved. No part of this publication may be
reproduced, stored in a retrieval system, or transmitted, in any form or by any means, electronic,
mechanical, photocopying, recording, or otherwise, without the prior written permission of the publisher.
Printed in the United States of America. For information on obtaining permission for use of material in this
work, please submit a written request to Pearson Education, Inc., Rights and Contracts Department, 501
Boylston Street, Suite 900, Boston, MA 02116, fax (617) 671-3447, or online at
http://www.pearsoned.com/legal/permissions.htm.

ISBN-13: 978-0-13-607047-4
ISBN-10: 0-13-607047-7

1 2 3 4 5 6 7 8 9 10—OPM—12 11 10 09 08

Luger_copyright.pdf 1 5/15/2008 6:02:23 PM


Contents
Preface ix

Part I Language Idioms and the Master Programmer 1


Chapter 1 Idioms, Patterns, and Programming 3
1.1 Introduction: Idioms and Patterns 3
1.2 Selected Examples of Language Idioms 6
1.3 A Brief History of Three Programming Paradigms 11
1.4 A Summary of Our Task 15

Part II Programming in Prolog 17


Chapter 2 Prolog: Representation 19
2.1 Introduction: Logic-Based Representation 19
2.2 Prolog Syntax 20
2.3 Creating, Changing, and Tracing a Prolog Computation 24
2.4 Lists and Recursion in Prolog 25
2.5 Structured Representation and Inheritance Search 28
Exercises 32

Chapter 3 Abstract Data Types and Search 33


3.1 Introduction 33
3.2 Using cut to Control Search in Prolog 36
3.3 Abstract Data Types (ADTs) in Prolog 38
Exercises 42

Chapter 4 Depth- Breadth-, and Best-First Search 43


4.1 Production System Search in Prolog 43
4.2 A Production System Solution of the FWGC Problem 46
4.3 Designing Alternative Search Strategies 52
Exercises 58

Chapter 5 Meta-Linguistic Abstraction, Types, and Meta-Interpreters 59


5.1 Meta-Interpreters, Types, and Unification 59
5.2 Types in Prolog 61
5.3 Unification, Variable Binding, and Evaluation 64
Exercises 68
v

Luger_all_wcopyright_COsfixed.pd5 5 5/15/2008 6:34:39 PM


vi Contents

Chapter 6 Three Meta-Interpreters: Prolog in Prolog, EXSHELL, and a


Planner 59
6.1 An Introduction to Meta-Interpreters: Prolog in Prolog 69
6.2 A Shell for a Rule-Based System 73
6.3 A Prolog Planner 82
Exercises 85

Chapter 7 Machine Learning Algorithms in Prolog 87


7.1 Machine Learning: Version Space Search 87
7.2 Explanation Based Learning in Prolog 100
Exercises 106

Chapter 8 Natural Language Processing in Prolog 107


8.1 Natural Language Understanding 107
8.2 Prolog Based Semantic Representation 108
8.3 A Context-Free Parser in Prolog 111
8.4 Probabilistic Parsers in Prolog 114
8.5 A Context-Sensitive Parser in Prolog 119
8.6 A Recursive Descent Semantic Net Parser 120
Exercises 123

Chapter 9 Dynamic Programming and the Earley Parser 125


9.1 Dynamic Programming Revisited 125
9.2 The Earley Parser 126
9.3 The Earley Parser in Prolog 134
Exercises 139

Chapter 10 Prolog: Final Thoughts 141


10.1 Towards a Procedural Semantics 141
10.2 Prolog and Automated Reasoning 144
10.3 Prolog Idioms, Extensions, and References 145

Part III Programming in Lisp 149


Chapter 11 S-Expressions, the Syntax of Lisp 151
11.1 Introduction to Symbol Expressions 151
11.2 Control of Lisp Evaluation 154
11.3 Programming in Lisp: Creating New Functions 156
11.4 Program Control: Conditionals and Predicates 157
Exercises 160

Luger_all_wcopyright_COsfixed.pd6 6 5/15/2008 6:34:39 PM


Contents vii

Chapter 12 Lists and Recursive Search 161

12.1 Functions, Lists, and Symbolic Computing 161


12.2 Lists as Recursive Structures 163
12.3 Nested Lists, Structure, and car/cdr Recursion 166
Exercises 168

Chapter 13 Variables, Datratypes, and Search 171


13.1 Variables and Datatypes 171
13.2 Search: The Farmer, Wolf, Goat, and Cabbage Problem 177
Exercises 182

Chapter 14 Higher-Order Functions and Flexible Search 185


14.1 Higher-Order Functions and Abstraction 185
14.2 Search Strategies in Lisp 189
Exercises 193

Chapter 15 Unification and Embedded Languages in Lisp 195


15.1 Introduction 195
15.2 Interpreters and Embedded Languages 203
Exercises 205

Chapter 16 Logic programming in Lisp 207


16.1 A Simple Logic Programming Language 207
16.2 Streams and Stream Processing 209
16.3 A Stream-Based logic Programming Interpreter 211
Exercises 217

Chapter 17 Lisp-shell: An Expert System Shell in Lisp 219


17.1 Streams and Delayed Evaluation 219
17.2 An Expert System Shell in Lisp 223
Exercises 232

Chapter 18 Semantic Networks, Inheritance, and CLOS 233


18.1 Semantic nets and Inheritance in Lisp 233
18.2 Object-Oriented Programming Using CLOS 237
18.3 CLOS Example: A Thermostat Simulation 244
Exercises 250

Chapter 19 Machine Learning in Lisp 251


19.1 Learning: The ID3 Algorithm 251
19.2 Implementing ID3 259

Luger_all_wcopyright_COsfixed.pd7 7 5/15/2008 6:34:39 PM


viii Contents

Exercises 266

Chapter 20 Lisp: Final Thoughts 267

Part IV Programming in Java 269


Chapter 21 Java, Representation and Object-Oriented Programming 273
21.1 Introduction to O-O Representation and Design 273
21.2 Object Orientation 274
21.3 Classes and Encapsulation 275
21.4 Polymorphism 276
21.5 Inheritance 277
21.6 Interfaces 280
21.7 Scoping and Access 282
21.8 The Java Standard Library 283
21.9 Conclusions: Design in Java 284
Exercises 285

Chapter 22 Problem Spaces and Search 287


21.1 Abstraction and Generality in Java 287
21.2 Search Algorithms 288
21.3 Abstracting Problem States 292
21.4 Traversing the Solution Space 295
21.5 Putting the Framework to Use 298
Exercises 303

Chapter 23 Java Representation for Predicate Calculus and Unification 305


23.1 Introduction to the Task 305
23.2 A Review of the Predicate Calculus and Unification 307
23.3 Building a Predicate Calculus Problem Solver in Java 310
23.4 Design Discussion 320
23.5 Conclusions: Mapping Logic into Objects 322
Exercises 323

Chapter 24 A Logic-Based Reasoning System 325


24.1 Introduction 325
24.2 Reasoning in Logic as Searching an And/Or Graph 325
24.3 The Design of a Logic-Based Reasoning System 329
24.4 Implementing Complex Logic Expressions 330
24.5 Logic-Based Reasoning as And/Or Graph Search 335
24.6 Testing the Reasoning System 346

Luger_all_wcopyright_COsfixed.pd8 8 5/15/2008 6:34:40 PM


Contents ix

24.7 Design Discussion 348


Exercises 350

Chapter 25 An Expert System Shell 351


25.1 Introduction: Expert Systems 351
25.2 Certainty Factors and the Unification Problem Solver 352
25.3 Adding User Interactions 358
25.4 Design Discussion 360
Exercises 361

Chapter 26 Case Studies: JESS and other Expert System Shells in Java 363
26.1 Introduction 363
26.2 JESS 363
26.3 Other Expert system Shells 364
26.4 Using Open Source Tools 365

Chapter 27 ID3: Learning from Examples 367


27.1 Introduction to Supervised Learning 367
27.2 Representing Knowledge as Decision Trees 367
27.3 A Decision Tree Induction program 370
27.4 ID3: An Information Theoretic Tree Induction Algorithm 385
Exercises 388

Chapter 28 Genetic and Evolutionary Computing 389


28.1 Introduction 389
28.2 The Genetic Algorithm: A First Pass 389
28.3 A GA Java Implementation in Java 393
28.4 Conclusion: Complex Problem Solving and Adaptation 401
Exercises 401

Chapter 29 Case Studies: Java Machine Learning Software Available on the


Web 403
29.1 Java Machine Learning Software 403

Chapter 30 The Earley Parser: Dynamic Programming in Java 405


30.1 Chart Parsing 405
30.2 The Earley Parser: Components 406
30.3 The Earley Parser: Java Code 408
30.4 The Completed Parser 414
30.5 Generating Parse Trees from Charts and Grammar Rules 419
Exercises 422

Luger_all_wcopyright_COsfixed.pd9 9 5/15/2008 6:34:40 PM


x Contents

Chapter 31 Case Studies: Java Natural Language Tools on the Web 423
31.1 Java Natural Language Processing Software 423
31.2 LingPipe from the University of Pennsylvania 423
31.3 The Stanford Natural Language Processing Group Software 425
31.4 Sun’s Speech API 426

Part V Model Building and the Master Programmer 429

Chapter 32 Conclusion: The Master Programmer 431


32.1 Paradigm-Based Abstractions and Idioms 431
32.2 Programming as a Tool for Exploring Problem Domains 433
32.3 Programming as a Social Activity 434
32.4 Final Thoughts 437

Bibliography 439

Index 443

Luger_all_wcopyright_COsfixed.pd10 10 5/15/2008 6:34:40 PM


Preface
What we have to learn to do
We learn by doing…

- Aristotle, Ethics

Why Another Writing a book about designing and implementing representations and
Programming search algorithms in Prolog, Lisp, and Java presents the authors with a
Language number of exciting opportunities.
Book?
The first opportunity is the chance to compare three languages that give
very different expression to the many ideas that have shaped the evolution
of programming languages as a whole. These core ideas, which also
support modern AI technology, include functional programming, list
processing, predicate logic, declarative representation, dynamic binding,
meta-linguistic abstraction, strong-typing, meta-circular definition, and
object-oriented design and programming. Lisp and Prolog are, of course,
widely recognized for their contributions to the evolution, theory, and
practice of programming language design. Java, the youngest of this trio, is
both an example of how the ideas pioneered in these earlier languages
have shaped modern applicative programming, as well as a powerful tool
for delivering AI applications on personal computers, local networks, and
the world wide web.
The second opportunity this book affords is a chance to look at Artificial
Intelligence from the point of view of the craft of programming. Although
we sometimes are tempted to think of AI as a theoretical position on the
nature of intelligent activity, the complexity of the problems AI addresses
has made it a primary driver of progress in programming languages,
development environments, and software engineering methods. Both Lisp
and Prolog originated expressly as tools to address the demands of
symbolic computing. Java draws on object-orientation and other ideas that
can trace their roots back to AI programming. What is more important, AI
has done much to shape our thinking about program organization, data
structures, knowledge representation, and other elements of the software
craft. Anyone who understands how to give a simple, elegant formulation
to unification-based pattern matching, logical inference, machine learning
theories, and the other algorithms discussed in this book has taken a large
step toward becoming a master programmer.
The book’s third, and in a sense, unifying focus lies at the intersection of
these points of view: how does a programming language’s formal structure
interact with the demands of the art and practice of programming to

xi

Luger_all_wcopyright_COsfixed.pd11 11 5/15/2008 6:34:40 PM


xii Preface

create the idioms that define its accepted use. By idiom, we mean a set of
conventionally accepted patterns for using the language in practice.
Although not the only way of using a language, an idiom defines patterns
of use that have proven effective, and constitute a common understanding
among programmers of how to use the language. Programming language
idioms do much to both enable, as well as support, ongoing
communication and collaboration between programmers.
These, then, are the three points of view that shape our discussion of AI
programming. It is our hope that they will help to make this book more
than a practical guide to advanced programming techniques (although it is
certainly that). We hope that they will communicate the intellectual depth
and pleasure that we have found in mastering a programming language
and using it to create elegant and powerful computer programs.
The Design of There are five sections of this book. The first, made up of a single chapter,
this Book lays the conceptual groundwork for the sections that follow. This first
chapter provides a general introduction to programming languages and
style, and asks questions such as “What is a master programmer?” What is a
programming language idiom?,” and “How are identical design patterns
implemented in different languages?” Next, we introduce a number of
design patterns specific to supporting data structures and search strategies
for complex problem solving. These patterns are discussed in a “language
neutral” context, with pointers to the specifics of the individual
programming paradigms presented in the subsequent sections of our
book. The first chapter ends with a short historical overview of the
evolution of the logic-based, functional, and object-oriented approaches to
computer programming languages.
Part II of this book presents Prolog. For readers that know the rudiments
of first-order predicate logic, the chapters of Part II can be seen as a
tutorial introduction to Prolog, the language for programming in logic.
For readers lacking any knowledge of the propositional and predicate
calculi we recommend reviewing an introductory textbook on logic.
Alternatively, Luger (2005, Chapter 2) presents a full introduction to both
the propositional and predicate logics. The Luger introduction includes a
discussion, as well as a pseudo code implementation, of unification, the
pattern-matching algorithm at the heart of the Prolog engine.
The design patterns that make up Part II begin with the “flat” logic-based
representation for facts, rules, and goals that one might expect in any
relational data base formalism. We next show how recursion, supported by
unification-based pattern matching, provides a natural design pattern for
tree and graph search algorithms. We then build a series of abstract data
types, including sets, stacks, queues, and priority queues that support
patterns for search. These are, of course, abstract structures, crafted for
the specifics of the logic-programming environment that can search across
state spaces of arbitrary content and complexity. We then build and
demonstrate the “production system” design pattern that supports rule
based programming, planning, and a large number of other AI
technologies. Next, we present structured representations, including

Luger_all_wcopyright_COsfixed.pd12 12 5/15/2008 6:34:40 PM


Preface xiii

semantic networks and frame systems in Prolog and demonstrate


techniques for implementing single and multiple inheritance
representation and search. Finally, we show how the Prolog design
patterns presented in Part II can support the tasks of machine learning
and natural language understanding.
Lisp and functional programming make up Part III. Again, we present the
material on Lisp in the form of a tutorial introduction. Thus, a
programmer with little or no experience in Lisp is gradually introduced to
the critical data structures and search algorithms of Lisp that support
symbolic computing. We begin with the (recursive) definition of symbol-
expressions, the basic components of the Lisp language. Next we present
the “assembly instructions” for symbol expressions, including car, cdr, and
cons. We then assemble new patterns for Lisp with cond and defun.
Finally, we demonstrate the creation and/or evaluation of symbol
expressions with quote and eval. Of course, the ongoing discussion of
variables, binding, scope, and closures is critical to building more complex
design patterns in Lisp.
Once the preliminary tools and techniques for Lisp are presented, we
describe and construct many of the design patterns seen earlier in the
Prolog section. These include patterns supporting breadth-first, depth-
first, and best-first search as well as meta-interpreters for rule-based
systems and planning. We build and demonstrate a recursion-based
unification algorithm that supports a logic interpreter in Lisp as well as a
stream processor with delayed evaluation for handling potentially infinite
structures. We next present data structures for building semantic networks
and object systems. We then present the Common Lisp Object system
(CLOS) libraries for building object and inheritance based design patterns.
We close Part III by building design patterns that support decision-tree
based machine learning.
Java and its idioms are presented in Part IV. Because of the complexities
of the Java language, Part IV is not presented as a tutorial introduction to
the language itself. It is expected that the reader has completed at least an
introductory course in Java programming, or at the very least, has seen
object-oriented programming in another applicative language such as
C++, C#, or Objective C. But once we can assume a basic understanding
of Java tools, we do provide a tutorial introduction to many of the design
patterns of the language.
The first chapter of Part IV, after a brief overview of the origins of Java,
goes through many of the features of an object-oriented language that will
support the creation of design patterns in that environment. These
features include the fundamental data structuring philosophy of
encapsulation, polymorphism, and inheritance. Based on these concepts
we briefly address the analysis, iterative design, programming and test
phases for engineering programs. After the introductory chapter we begin
pattern building in Java, first considering the representation issue and how
to represent predicate calculus structures in Java. This leads to building

Luger_all_wcopyright_COsfixed.pd13 13 5/15/2008 6:34:41 PM


xiv Preface

patterns that support breadth-first, depth-first, and best-first search. Based


on patterns for search, we build a production system, a pattern that
supports the rule-based expert system. Our further design patterns
support the application areas of natural language processing and machine
learning. An important strength that Java offers, again because of its
object-orientation and modularity is the use of public domain (and other)
libraries available on the web. We include in the Java section a number of
web-supported AI algorithms, including tools supporting work in natural
language, genetic and evolutionary programming (a-life), natural language
understanding, and machine learning (WEKA).
The final component of the book, Part V, brings together many of the
design patterns introduced in the earlier sections. It also allows the authors
to reinforce many of the common themes that are, of necessity,
distributed across the various components of the presentation, We
conclude with general comments supporting the craft of programming.
Using this Book This book is designed for three primary purposes. The first is as a
programming language component of a general class in Artificial
Intelligence. From this viewpoint, the authors see as essential that the AI
student build the significant algorithms that support the practice of AI.
This book is designed to present exactly these algorithms. However, in the
normal lecture/lab approach taken to teaching Artificial Intelligence at the
University level, we have often found that it is difficult to cover more than
one language per quarter or semester course. Therefore we expect that the
various parts of this material, those dedicated to either Lisp, Prolog, or
Java, would be used individually to support programming the data
structures and algorithms presented in the AI course itself. In a more
advanced course in AI it would be expected that the class cover more than
one of these programming paradigms.
The second use of this book is for university classes exploring
programming paradigms themselves. Many modern computer science
departments offer a final year course in comparative programming
environments. The three languages covered in our book offer excellent
examples on these paradigms. We also feel that a paradigms course should
not be based on a rapid survey of a large number of languages while doing
a few “finger exercises” in each. Our philosophy for a paradigms course is
to get the student more deeply involved in fewer languages, and these
typically representing the declarative, functional, and object-oriented
approaches to programming. We also feel that the study of idiom and
design patterns in different environments can greatly expand the skill set
of the graduating student. Thus, our philosophy of programming is built
around the language idioms and design patterns presented in Part I and
summarized in Part V. We see these as an exciting opportunity for
students to appreciate the wealth and diversity of modern computing
environments. We feel this book offers exactly this opportunity.
The third intent of this book is to offer the professional programmer the
chance to continue their education through the exploration of multiple

Luger_all_wcopyright_COsfixed.pd14 14 5/15/2008 6:34:41 PM


Preface xv

programming idioms, patterns, and paradigms. For these readers we also


feel the discussion of programming idioms and design patterns presented
throughout our book is important. We are all struggling to achieve the
status of the master programmer.
We have built each chapter in this book to reflect the materials that would
be covered in either one or two classroom lectures, or about an hour’s
effort, if the reader is going through this material by herself. There are a
small number of exercises at the end of most chapters that may be used to
reinforce the main concepts of that chapter. There is also, near the end of
each chapter, a summary statement of the core concepts covered.
Acknowledg- First, we must thank several decades of students and colleagues at the
ments University of New Mexico. These friends not only suggested, helped
design, and tested our algorithms but have also challenged us to make
them better.
Second, we owe particular thanks to colleagues who wrote algorithms and
early drafts of chapters. These include Stan Lee, (PhD student at UNM)
for the Prolog chapter on Earley parsing, Breanna Ammons (MS in CS at
UNM) for the Java version of the Earley parser and along with Robert
Spurlock (CS undergraduate at UNM) the web-based NLP chapter, Paul
DePalma (Professor of CS at Gonzaga University) for the Java Genetic
Algorithms chapter, and Chayan Chakrabarti (MS in CS at UNM) for the
web-based machine learning chapter in Java
Third, there are several professional colleagues that we owe particular
debts. These include David MacQueen, University of Chicago, one of the
creators of SML, Manuel Hermenegildo, The Prince of Asturias Endowed
Chair of Computer Science at UNM and a designer of Ciao Prolog, Paul
De Palma, Professor of Computer Science at Gonzaga University, and
Alejandro Cdebaca, our friend and former student, who helped design
many of the algorithms of the Java chapters.
Fourth, we thank our friends at Pearson Education who have supported
our various creative writing activities over the past two decades. We
especially acknowledge our editors Alan Apt, Karen Mossman, Keith
Mansfield, Owen Knight, Simon Plumtree, and Matt Goldstein, along with
their various associate editors, proof readers, and web support personnel.
We also thank our wives, children, family, and friends; all those that have
made our lives not just survivable, but intellectually stimulating and
enjoyable.
Finally, to our readers; we salute you: the art, science, and practice of
programming is great fun, enjoy it!

GL
BS
July 2008
Albuquerque

Luger_all_wcopyright_COsfixed.pd15 15 5/15/2008 6:34:41 PM


xvi Preface

Luger_all_wcopyright_COsfixed.pd16 16 5/15/2008 6:34:41 PM


PART I: Language Idioms and the
Master Programmer

all good things - trout as well as eternal salvation - come by grace and grace comes by art and art does not
come easy…

- Norman Maclean, (1989) A River Runs Through It

Language and In defining a programming language idiom, an analogy with natural


Idioms
language use might help. If I ask a friend, “Do you know what time it is?”
or equivalently “Do you have a watch?”, I would be surprised if she simply
said “yes” and turned away. These particular forms for asking someone for
the time of day are idiomatic in that they carry a meaning beyond their
literal interpretation. Similarly, a programming language idiom consists of
those patterns of use that good programmers accept as elegant, expressive
of their design intent, and that best harness the language’s power. Good
idiomatic style tends to be specific to a given language or language
paradigm: the way experienced programmers organize a Prolog program
would not constitute accepted Java style.
Language idioms serve two roles. The first is to enhance communication
between programmers. As experienced programmers know, we do not
simply write code for a compiler; we also write it for each other. Writing in
a standard idiom makes it easier for other people to understand our intent,
and to maintain and/or extend our code. Second, a language’s idiom helps
us to make sure we fully use the power the language designers have
afforded us. People design a language with certain programming styles in
mind. In the case of Java, that style was object-oriented programming, and
getting full benefit of such Java features as inheritance, scoping, automatic
garbage collection, exception handling, type checking, packages, interfaces,
and so forth requires writing in an object-oriented idiom. A primary goal of
this book is to explore and give examples of good idioms in three diverse
language paradigms: the declarative (logic-based), functional, and object-
oriented.
The Master The goal of this book is to develop the idea and describe the practice of
Programmer
the master programmer. This phrase carries a decidedly working class
connotation, suggesting the kind of knowledge and effort that comes
through long practice and the transmission of tools and skills from master
to student through the musty rituals of apprenticeship. It certainly suggests
something beyond the immaculate formalization that we generally associate
with scientific disciplines. Indeed, most computer science curricula

Luger_all_wcopyright_COsfixed.pd17 17 5/15/2008 6:34:41 PM


2 Part I Introduction

downplay this craft of programming, favoring discussions of computability


and complexity, algorithms, data structures, and the software engineer’s
formalist longings. In reality, the idea of programming as a craft that
demands skill and dedication is widely accepted in practical circles. Few
major successful programming projects have existed that did not owe
significant components of that success to the craftsmanship of such
individuals.
But, what then, do master programmers know?
The foundation of a master programmer’s knowledge is a strong
understanding of the core domains of computer science. Although working
programmers may not spend much (or any) time developing and
publishing theorems, they almost always have a deep, intuitive grasp of
algorithms, data structures, logic, complexity, and other aspects of the
theory of formal systems. We could compare this to a master welder’s
understanding of metallurgy: she may not have a theoretician’s grasp of
metallic crystalline structure, but her welds do not crack. This book
presumes a strong grounding in these computer science disciplines.
Master programmers also tend to be language fanatics, exhibiting a fluency
in several programming languages, and an active interest in anything new
and unusual. We hope that our discussion of three major languages will
appeal to the craftsman’s fascination with their various tools and
techniques. We also hope that, by contrasting these three major languages
in a sort of “comparative language” discussion, we will help programmers
refine their understanding of what a language can provide, and the needs
that continue to drive the evolution of programming languages.

Luger_all_wcopyright_COsfixed.pd18 18 5/15/2008 6:34:42 PM


1 Idioms, Patterns, and Programming

Chapter This chapter introduces the ideas that we use to organize our thinking about
Objectives languages and how they shape the design and implementation of programs.
These are the ideas of language, idiom, and design pattern.

Chapter 1.1 Introduction


Contents 1.2 Selected Examples of AI Language Idioms
1.3 A Brief History of Three Programming Paradigms
1.4 A Summary of our Task

1.1 Introduction
Idioms and As with any craft, programming contains an undeniable element of
Patterns
experience. We achieve mastery through long practice in solving the
problems that inevitably arise in trying to apply technology to actual
problem situations. In writing a book that examines the implementation of
major AI algorithms in a trio of languages, we hope to support the reader’s
own experience, much as a book of musical etudes helps a young musician
with their own exploration and development.
As important as computational theory, tools, and experience are to a
programmer’s growth, there is another kind of knowledge that they only
suggest. This knowledge comes in the form of pattern languages and
idioms, and it forms a major focus of this book. The idea of pattern
languages originated in architecture (Alexander et al. 1977) as a way of
formalizing the knowledge an architect brings to the design of buildings
and cities that will both support and enhance the lives of their residents. In
recent years, the idea of pattern languages has swept the literature on
software design (Gamma, et al. 1995; Coplein & Schmidt 1995; Evans
2003), as a way of capturing a master’s knowledge of good, robust program
structure.
A design pattern describes a typical design problem, and outlines an
approach to its solution. A pattern language consists of a collection of
related design patterns. In the book that first proposed the use of pattern
languages in architecture, Christopher Alexander et al. (1977, page x) state
that a pattern
describes a problem which occurs over and over again in our environment, and
then describes the core of the solution to that problem, in such a way that you
can use this solution a million times over, without ever doing it the same way
twice.
Design patterns capture and communicate a form of knowledge that is
essential to creating computer programs that users will embrace, and that

Luger_all_wcopyright_COsfixed.pd19 19 5/15/2008 6:34:42 PM


4 Part I: Language Idioms and the Master Programmer

programmers will find to be elegant, logical, and maintainable. They


address programming and languages, not in terms of Turing completeness,
language paradigms, compiler semantics, or any of the other qualities that
constitute the core of computer science, but rather as tools for practical
problem solving. To a large extent, you can think of this book as
presenting a pattern language of the core problems of AI programming,
and examples – the patterns – of their solution.
Idioms are a form and structure for knowledge that helps us bridge the
differences between patterns as abstract descriptions of a problem and its
solutions and an understanding of how best to implement that solution in a
given programming language. A language idiom is the expression of a
design pattern in a given language. In this sense, design patterns + idioms =
quality programs.
Sample Design Consider, for example, the simple, widely used design pattern that we can
Patterns call map that applies some operator O to every element of a list L. We can
express this pattern in a pseudo code function as follows:
map(operator O, list L)
{
if (L contains no elements) quit;
h  the first element of L.
apply O to h;
map(O, L minus h);
}
This map function produces a stream of results: O applied to each element
of the list L. As our definition of pattern specifies, this describes a solution
to a recurring problem, and also fosters unlimited variations, depending on
the type of the elements that make up the list L, and the nature of the
operator, O.
Now, let us consider a fragment of Lisp code that implements this same
map pattern, where f is the mapped operator (in Lisp a function) and
list is the list:
(defun map (f list)
(cond ((null list) nil)
(t (cons (apply f (car list))
(map f (cdr list))))))
This function map, created by using the built-in Lisp defun function, not
only implements the map pattern, but also illustrates elements of the Lisp
programming idiom. These include the use of the operators car and cdr to
separate the list into its head and tail, the use of the cons operator to place
the results into a new list, and also the use of recursion to move down the
list. Indeed, this idiom of recursively working through a list is so central to
Lisp, that compiler writers are expected to optimize this sort of tail
recursive structure into a more efficient iterative implementation.
Let us now compare the Lisp map to a Java implementation that
demonstrates how idioms vary across languages:

Luger_all_wcopyright_COsfixed.pd20 20 5/15/2008 6:34:42 PM


Chapter 1 Idioms, Patterns, and the Master programmer 5

public Vector map(Vector l)


{
Vector result = new Vector();
Iterator iter = l.iterator();
while(iter.hasNext())
{
result.add(f(iter.next));
}
return result;
}
The most striking difference between the Java version and the Lisp version
is that the Java version is iterative. We could have written our list search in
a recursive form (Java supports recursion, and compilers should optimize it
where possible), but Java also offers us iterators for moving through lists.
Since the authors of Java provide us with list iterators, and we can assume
they are implemented efficiently, it makes sense to use them. The Java
idiom differs from the Lisp idiom accordingly.
Furthermore, the Java version of map creates the new variable, result.
When the iterator completes its task, result will be a vector of
elements, each the result of applying f to each element of the input list
(vector). Finally, result must be explicitly returned to the external
environment. In Lisp, however, the resulting list of mapped elements is the
result of invoking the function map (because it is returned as a direct
result of evaluating the map function).
Finally, we present a Prolog version of map. Of course in Prolog, map will
be a represented as a predicate. This predicate has three arguments, the
first the function, f, which will be applied to every element of the list that
is the second argument of the predicate. The third argument of the
predicate map is the list resulting from applying f to each element of the
second argument. The pattern [X|Y] is the Prolog list representation,
where X is the head of the list (car in Lisp) and Y is the list that is the rest
of the list (cdr in Lisp). The is operator binds the result of f applied to
H to the variable NH. As with Lisp, the map relationship is defined
recursively, although no tail recursive optimization is possible in this case.
Further clarifications of this Prolog specification are presented in Part II.
map(f, [ ], [ ]).
map(f, [H|T], [NH|NT]):-
NH is f(H), map(f, T, NT).
In the three examples above we see a very simple example of a pattern
having different idioms in each language, the eval&assign pattern. This
pattern evaluates some expression and assigns the result to a variable. In
Java, as we saw above, = simply assigns the evaluated expression on its
right-hand-side to the variable on its left. In Lisp this same activity requires
the cons of an apply of f to an element of the list. The resulting
symbol expression is then simply returned as part of the evaluated function
map. In Prolog, using the predicate representation, there are similar

Luger_all_wcopyright_COsfixed.pd21 21 5/15/2008 6:34:43 PM


6 Part I: Language Idioms and the Master Programmer

differences between assignment (based on unification with patterns such as


[H|T] and =) and evaluation (using is or making f be a goal).
Understanding and utilizing these idioms is an essential aspect of mastering
a programming language, in that they represent expected ways the language
will be used. This not only allows programmers more easily to understand,
maintain, and extend each other’s code, but also allows us to remain
consistent with the language designer’s assumptions and implementation
choices.
1.2 Selected Examples of AI Language Idioms
We can think of this book, then, as presenting some of the most important
patterns supporting Artificial Intelligence programming, and demonstrating
their implementation in the appropriate idioms of three major languages.
Although most of these patterns were introduced in this book’s companion
volume, Artificial Intelligence: Structures and Strategies for Complex Problem Solving
(Luger 2009), it is worthwhile to summarize a subset of them briefly in this
introduction.
Symbolic Artificial Intelligence rests on two basic ideas: first, representation or the use
Computing:
of symbol structures to represent problem solving knowledge (state), and
The Issue of second, search, the systematic consideration of sequences of operations on
Representation
these knowledge structures to solve complex problems. Symbolic
computing embraces a family of patterns for representing state and then
manipulating these (symbol) structures, as opposed to only performing
arithmetic calculations on states. Symbolic computing methods are the
foundation of artificial intelligence: in a sense, everything in this book rests
upon them. The recursive list-handling algorithm described above is a
fundamental symbolic computing pattern, as are the basic patterns for tree
and graph manipulation. Lisp was developed expressly as a language for
symbolic computing, and its s-expression representation (see Chapter 11)
has proved general, powerful and long-lived.
As we develop the examples of this book, pay close attention to how these
simple patterns of list, tree, and graph manipulation combine to form the
more complex, problem specific patterns described below.
Search Search in AI is also fundamental and complementary to representation (as
is emphasized throughout our book. Prolog, in fact, incorporates a form of
search directly into its language semantics. In addition to forming a
foundation of AI, search introduces many of its thorniest problems. In
most interesting problems, search spaces tend to be intractable, and much
of AI theory examines the use of heuristics to control this complexity. As
has been pointed out from the very beginnings of AI (Feigenbaum and
Feldman 1963, Newell and Simon 1976) support of intelligent search
places the greatest demands on AI programming.
Search related design patterns and problems we will examine in this book
include implementations of the basic search algorithms (breadth-first,
depth-first, and best-first), management of search history, and the recovery
of solution paths with the use of those histories.
A particularly interesting search related problem is in the representation

Luger_all_wcopyright_COsfixed.pd22 22 5/15/2008 6:34:43 PM


Chapter 1 Idioms, Patterns, and the Master programmer 7

and generation of problem states. Conceptually, AI search algorithms are


general: they can apply to any search space. Consequently, we will define
general, reusable search “frameworks” that can be applied to a range of
problem representations and operations for generating new states. How
the different programming paradigms address this issue is illuminating in
terms of their language-based idioms.
Lisp makes no syntactic distinction between functions and data structures:
both can be represented as symbol expressions (see s-expression, Chapter
11), and both can be handled identically as Lisp objects. In addition, Lisp
does not enforce strong typing on s-expressions. These two properties of
the language allow us to define a general search algorithm that takes as
parameters the starting problem state, and a list of Lisp functions, often
using the map design pattern described earlier, for producing child states.
Prolog includes a list representation that is very similar to lists in Lisp, but
differs in having built-in search and pattern matching in a language
supporting direct representation of predicate calculus rules. Implementing
a generalized search framework in Prolog builds on this language’s unique
idioms. We define the operators for generating states as rules, using pattern
matching to determine when these rules apply. Prolog offers explicit meta-
level controls that allow us to direct the pattern matching, and control its
built-in search.
Java presents its own unique idioms for generalizing search. Although Java
provides a “reflection” package that allows us to manipulate its objects,
methods, and their parameters directly, this is not as simple to do as in Lisp
or Prolog. Instead, we will use Java interface definitions to specify the
methods a state object must have at a general level, and define search
algorithms that take as states instances of any class that instantiates the
appropriate interface (see Chapters 22-24).
These three approaches to implementing search are powerful lessons in the
differences in language idioms, and the way they relate to a common set of
design patterns. Although each language implements search in a unique
manner, the basic search algorithms (breadth-, depth-, or best-first) behave
identically in each. Similarly, each search algorithm involves a number of
design patterns, including the management of problem states on a list, the
ordering of the state list to control search, and the application of state-
transition operators to a state to produce its descendants. These design
patterns are clearly present in all algorithms; it is only at the level of
language syntax, semantics, and idioms that these implementations differ.
Pattern Pattern matching is another support technology for AI programming that
Matching
spawns a number of useful design patterns. Approaches to pattern
matching can vary from checking for identical memory locations, to
comparing simple regular-expressions, to full pattern-based unification
across predicate calculus expressions, see Luger (2009, Section 2.3). Once
again, the differences in the way each language implements pattern
matching illustrate critical differences in their semantic structure and
associated idioms.
Prolog provides unification pattern matching directly in its interpreter:
unification and search on Predicate Calculus based data structures are the

Luger_all_wcopyright_COsfixed.pd23 23 5/15/2008 6:34:43 PM


8 Part I: Language Idioms and the Master Programmer

basis of Prolog semantics. Here, the question is not how to implement


pattern matching, but how to use it to control search, the flow of program
execution, and the use of variable bindings to construct problem solutions
as search progresses. In this sense, Prolog gives rise to its own very unique
language idioms.
Lisp, in contrast, requires that we implement unification pattern matching
ourselves. Using its basic symbolic computing capabilities, Lisp makes it
straightforward to match recursively the tree structures that implicitly
define predicate calculus expressions. Here, the main design problem
facing us is the management of variable bindings across the unification
algorithm. Because Lisp is so well suited to this type of implementation,
we can take its implementation of unification as a “reference
implementation” for understanding both Prolog semantics, and the Java
implementation of the same algorithm.
Unlike Lisp, which allows us to use nested s-expressions to define tree
structures, Java is a strongly typed language. Consequently, our Java
implementation will depend upon a number of user-created classes to
define expressions, constants, variables, and variable bindings. As with our
implementation of search, the differences between the Java and Lisp
implementations of pattern matching are interesting examples of the
differences between the two languages, their distinct idioms, and their
differing roles in AI programming.
Structured Although the basic symbolic structures (lists, trees, etc.) supported by all
Types and
Inheritance
these languages are at the foundation of AI programming, a major focus of
(Frames) AI work is on producing representations that reflect the way people think
about problems. This leads to more complex structures that reflect the
organization of taxonomies, similarity relationships, ontologies, and other
cognitive structures. One of the most important of these comes from
frame theory (Minsky 1975; Luger 2009, Section 7.1), and is based on
structured data types (collections of individual attributes combined in a
single object or frame), explicit relationships between objects, and the use of
class inheritance to capture hierarchical organizations of classes and their
attributes.
These representational principles have proved so effective for practical
knowledge representation that they formed the basis of object-oriented
programming: Smalltalk, the CommonLisp Object System libraries
(CLOS), C++, and Java. Just as Prolog bases its organization on predicate
calculus and search, and Lisp builds on (functional) operations on symbolic
structures, so Java builds directly on these ideas of structured
representation and inheritance.
This approach of object-oriented programming underlies a large number of
design patterns and their associated idioms (Gamma, et al. 1995; Coplein &
Schmidt 1995), as merited by the expressiveness of the approach. In this
book, we will often focus on the use of structured representations not
simply for design of program code, but also as a tool for knowledge
representation.
Meta-Linguistic Meta-linguistic abstraction is one of the most powerful ways of organizing
Abstraction programs to solve complex problems. In spite of its imposing title, the

Luger_all_wcopyright_COsfixed.pd24 24 5/15/2008 6:34:43 PM


Chapter 1 Idioms, Patterns, and the Master programmer 9

idea behind meta-linguistic abstraction is straightforward: rather than trying


to write a solution to a hard problem in an existing programming language,
use that language to create another language that is better suited to solving
the problem. We have touched on this idea briefly in this introduction in
our mention of general search frameworks, and will develop it throughout
the book (e.g., Chapters 5, 15, 26).
One example of meta-linguistic abstraction that is central to AI is the idea
of an inference engine: a program that takes a declarative representation of
domain knowledge in the form of rules, frames or some other
representation, and applies that knowledge to problems using general
inference algorithms. The commonest example of an inference engine is
found in a rule-based expert system shell. We will develop such a shell,
EXSHELL in Prolog (Chapter 6), Lisp-shell in Lisp (Chapter 17), and an
equivalent system in Java (Chapter 26), providing similar semantics in all
three language environments. This will be a central focus of the book, and
will provide an in-depth comparison of the programming idioms supported
by each of these languages.
Knowledge- This discussion of AI design patterns and language idioms has proceeded
Level Design
from simple features, such as basic, list-based symbol processing, to more
powerful AI techniques such as frame representations and expert system
shells. In doing so, we are adopting an organization parallel to the
theoretical discussion in Artificial Intelligence: Strategies and Structures for
Complex Problem Solving (Luger 2009). We are building a set of tools for
programming at what Allen Newell (1982) has called the knowledge level.

Figure 1.1 Levels of a Knowledge-Based System, adapted from Newell


(1982).
Allen Newell (1982) has distinguished between the knowledge level and the
symbol level in describing an intelligent system. As may be seen in Figure 1.1
(adapted from Newell, 1982), the symbol level is concerned with the
particular formalisms used to represent problem solving knowledge, for
example the predicate calculus. Above this symbol level is the knowledge
level concerned with the knowledge content of the program and the way in
which that knowledge is used.
The distinction between the symbol and knowledge level is reflected in the

Luger_all_wcopyright_COsfixed.pd25 25 5/15/2008 6:34:53 PM


10 Part I: Language Idioms and the Master Programmer

architectures of expert systems and other knowledge-based programs (see


Chapters 6, 15, and 25). Since the user will understand these programs in
terms of their knowledge content, these programs must preserve two
invariants: first, as just noted, there must be a knowledge-level
characterization, and second, there must be a clear distinction between this
knowledge and its control. We see this second invariant when we utilize the
production system design pattern in Chapters 6, 15, and 25. Knowledge level
concerns include questions such as: What queries will be made of the
system? What objects and/or relations are important in the domain? How
is new knowledge added to the system? Will information change over time?
How will the system need to reason about its knowledge? Does the
problem domain include missing or uncertain information?
The symbol level, just below the knowledge level, defines the knowledge
representation language, whether it be direct use of the predicate calculus
or production rules. At this level decisions are made about the structures
required to represent and organize knowledge. This separation from the
knowledge level allows the programmer to address such issues as
expressiveness, efficiency, and ease of programming, that are not relevant
to the programs higher level intent and behavior.
The implementation of the algorithm and data structure level constitutes a still
lower level of program organization, and defines an additional set of design
considerations. For instance, the behavior of a logic-based or function-
based program should be unaffected by the use of a hash table, heap, or
binary tree for implementing its symbol tables. These are implementation
decisions and invisible at higher levels. In fact, most of the techniques used
to implement representation languages for AI are common computer
science techniques, including binary trees and tables and an important
component of the knowledge-level design hypothesis is that they be hidden
from the programmer.
In thinking of knowledge level programming, we are defining a hierarchy
that uses basic programming language constructs to create more
sophisticated symbol processing languages, and uses these symbolic
languages to capture knowledge of complex problem domains. This is a
natural hierarchy that moves from machine models that reflect an
underlying computer architecture of variables, assignments and processes,
to a symbolic layer that works with more abstract ideas of symbolic
representation and inference. The knowledge level looks beyond symbolic
form to the semantics of problem solving domains and their associated
knowledge relationships.
The importance of this multi-level approach to system design cannot be
overemphasized: it allows a programmer to ignore the complexity hidden
at lower levels and focus on issues appropriate to the current level of
abstraction. It allows the theoretical foundations of artificial intelligence to
be kept free of the nuances of a particular implementation or programming
language. It allows us to modify an implementation, improving its
efficiency or porting it to another machine, without affecting its
specification and behavior at higher levels. But the AI programmer begins
addressing the problem-solving task from the programming language level.

Luger_all_wcopyright_COsfixed.pd26 26 5/15/2008 6:34:53 PM


Chapter 1 Idioms, Patterns, and the Master programmer 11

In fact, we may characterize the programmer’s ability to use design patterns


and their associated idioms as her ability to bridge and link the algorithms
and data structures afforded by different language paradigms with the
symbol level in the process of building expressive knowledge-intensive
programs.
To a large extent, then, our goal in writing this book is to give the reader
the intellectual tools for programming at the knowledge level. Just as an
experienced musician thinks past the problems of articulating individual
notes and chords on their instrument to the challenges of harmonic and
rhythmic structure in a composition, or an architect looks beyond the
layout of floor plans to ways buildings will interact with their occupants
over time, we believe the goal of a programmer’s development is to think
of computer programs in terms of the knowledge they incorporate, and the
way they engage human beings in the patterns of their work,
communication and relationships. Becoming the “master programmer” we
mentioned earlier in this introduction requires the ability to think in terms
of the human activities a program will support, and simultaneously to
understand the many levels of abstraction, algorithms, and data structures
that lie between those activities and the comparatively barren structures of
the “raw” programming language
1.3 A Brief History of Three Programming Paradigms
We conclude this chapter by giving a brief description of the origins of the
three programming languages we present. We also give a cursory
description of the three paradigms these languages represent. These details
are precursors of and an introduction to the material presented in the next
three parts of this book.
Logic Like Lisp, Prolog gains much of its power and elegance from its
Programming
in Prolog
foundations in mathematics. In the case of Prolog, those foundations are
predicate logic and resolution theorem proving. Of the three languages
presented in this book, Prolog may well seem unusual to most
programmers in that it is a declarative, rather than procedural, language. A
Prolog program is simply a statement, in first-order predicate calculus, of
the logical conditions a solution to a problem must satisfy. The declarative
semantics do not tell the computer what to do, only the conditions a
solution must satisfy. Execution of a Prolog program relies on search to
find a set of variable bindings that satisfy the conditions stated in the
particular goals required by the program. This declarative semantics makes
Prolog extremely powerful for a large class of problems that are of
particular interest to AI. These include constraint satisfaction problems,
natural language parsing, and many search problems, as will be
demonstrated in Part II.
A logic program is a set of specifications in formal logic; Prolog uses the
first-order predicate calculus. Indeed, the name itself comes from
programming in logic. An interpreter executes the program by
systematically making inferences from logic specifications. The idea of
using the representational power of the first-order predicate calculus to
express specifications for problem solving is one of the central

Luger_all_wcopyright_COsfixed.pd27 27 5/15/2008 6:34:53 PM


12 Part I: Language Idioms and the Master Programmer

contributions Prolog has made to computer science in general and to


artificial intelligence in particular. The benefits of using first-order
predicate calculus for a programming language include a clean and elegant
syntax and a well-defined semantics.
The implementation of Prolog has its roots in research on theorem proving
by J.A. Robinson (Robinson 1965), especially the creation of algorithms for
resolution refutation systems. Robinson designed a proof procedure called
resolution, which is the primary method for computing with Prolog. For a
more complete description of resolution refutation systems and of Prolog
as Horn clause refutation, see Luger (2009, Chapter 14).
Because of these features, Prolog has proved to be a useful vehicle for
investigating such experimental programming issues as automatic code
generation, program verification, and design of high-level specification
languages. As noted above, Prolog and other logic-based languages support
a declarative programming style—that is, constructing a program in terms
of high-level descriptions of a problem’s constraints—rather than a
procedural programming style—writing programs as a sequence of
instructions for performing an algorithm. This mode of programming
essentially tells the computer “what is true” and “what needs to be proven
(the goals)” rather than “how to do it.” This allows programmers to focus
on problem solving as creating sets of specifications for a domain rather
than the details of writing low-level algorithmic instructions for “what to
do next.”
The first Prolog program was written in Marseille, France, in the early
1970s as part of a project in natural language understanding (Colmerauer,
Kanoui et al. 1973, Roussel 1975, Kowalski 1979). The theoretical
background for the language is discussed in the work of Kowalski, Hayes,
and others (Hayes 1977, Kowalski 1979, Kowalski 1979, Lloyd 1984). The
major development of the Prolog language was carried out from 1975 to
1979 at the Department of Artificial Intelligence of the University of
Edinburgh. The people at Edinburgh responsible for the first “road
worthy” implementation of Prolog were David H.D. Warren and Fernando
Pereira. They produced the first Prolog interpreter robust enough for
delivery to the general computing community. This product was built using
the “C” language on the DEC-system 10 and could operate in both
interpretive and compiled modes (Warren, Pereira, et al. 1979).
Further descriptions of this early code and comparisons of Prolog with
Lisp may be found in Warren et al. (Warren, Pereira, et al. 1977). This
“Warren and Pereira” Prolog became the early standard. The book
Programming in Prolog (Clocksin and Mellish 1984, now in its fifth edition)
was created by two other researchers at the Department of Artificial
Intelligence, Bill Clocksin and Chris Mellish. This book quickly became the
chief vehicle for delivering Prolog to the computing community. We use
this standard, which has come to be known as Edinburgh Prolog. In fact,
all the Prolog code in this book may be run on the public domain
interpreter SWI-Prolog (to find, Google on swi-prolog).
Functional Lisp was arguably the first programming language to ground its semantics
Programming
in Lisp
in mathematical theory: the theory of partial recursive functions (McCarthy

Luger_all_wcopyright_COsfixed.pd28 28 5/15/2008 6:34:54 PM


Chapter 1 Idioms, Patterns, and the Master programmer 13

1960, Church 1941). In contrast to most of its contemporaries, which


essentially presented the architecture of the underlying computer in a
higher-level form, this mathematical grounding has given Lisp unusual
power, durability and influence. Ideas such as list-based data structures,
functional programming, and dynamic binding, which are now accepted
features of mainstream programming languages can trace their origins to
earlier work in Lisp. Meta-circular definition, in which compilers and
interpreters for a language are written in a core version of the language
itself, was the basis of the first, and subsequent Lisp implementations. This
approach, still revolutionary after more than fifty years, replaces
cumbersome language specifications with an elegant, formal, public,
testable meta-language kernel that supports the continued growth and
refinement of the language.
Lisp was first proposed by John McCarthy in the late 1950s. The language
was originally intended as an alternative model of computation based on
the theory of recursive functions. In an early paper, McCarthy (McCarthy
1960) outlined his goals: to create a language for symbolic rather than
numeric computation, to implement a model of computation based on the
theory of recursive functions (Church 1941), to provide a clear definition
of the language’s syntax and semantics, and to demonstrate formally the
completeness of this computational model. Although Lisp is one of the
oldest computing languages still in active use (along with FORTRAN and
COBOL), the careful thought given to its original design and the
extensions made to the language through its history have kept it in the
vanguard of programming languages. In fact, this programming model has
proved so effective that a number of other languages have been based on
functional programming, including SCHEME, SML-NJ, FP, and OCAML.
In fact, several of these newer languages, e.g., SCHEME and SML-NJ,
have been designed specifically to reclaim the semantic clarity of the earlier
versions of Lisp.
The list is the basis of both programs and data structures in Lisp: Lisp is an
acronym for list processing. Lisp provides a powerful set of list-handling
functions implemented internally as linked pointer structures. Lisp gives
programmers the full power and generality of linked data structures while
freeing them, with real-time garbage collection, from the responsibility for
explicitly managing pointers and pointer operations.
Originally, Lisp was a compact language, consisting of functions for
constructing and accessing lists (car, cdr, cons), defining new functions
(defun), detecting equality (eq), and evaluating expressions (quote,
eval). The only means for building program control were recursion and a
single conditional. More complicated functions, when needed, were
defined in terms of these primitives. Through time, the best of these new
functions became part of the language itself. This process of extending the
language by adding new functions led to the development of numerous
dialects of Lisp, often including hundreds of specialized functions for data
structuring, program control, real and integer arithmetic, input/output
(I/O), editing Lisp functions, and tracing program execution. These
dialects are the vehicle by which Lisp has evolved from a simple and
elegant theoretical model of computing into a rich, powerful, and practical

Luger_all_wcopyright_COsfixed.pd29 29 5/15/2008 6:34:54 PM


14 Part I: Language Idioms and the Master Programmer

environment for building large software systems. Because of the


proliferation of early Lisp dialects, the Defense Advanced Research
Projects Agency in 1983 proposed a standard dialect for the language,
known as Common Lisp.
Although Common Lisp has emerged as the lingua franca of Lisp dialects,
a number of simpler dialects continue to be widely used. One of the most
important of these is SCHEME, an elegant rethinking of the language that
has been used both for AI development and for teaching the fundamental
concepts of computer science. The dialect we use throughout the
remainder of our book is Common Lisp. All our code may be run on a
current public domain interpreter built by Carnegie Mellon University,
called CMUCL (Google CMUCL).
Object- Java is the third language considered in this book. Although it does not
Oriented
Programming
have Lisp or Prolog’s long historical association with Artificial Intelligence,
in Java it has become extremely important as a tool for delivering practical AI
applications. There are two primary reasons for this. The first is Java’s
elegant, dynamic implementation of object-oriented programming, a
programming paradigm with its roots in AI, that has proven its power for
use building AI programs through Smalltalk, Flavors, the Common Lisp
Object System (CLOS), and other object-oriented systems. The second
reason for Java’s importance to AI is that it has emerged as a primary
language for delivering tools and content over the world-wide-web. Java’s
ease of programming and the large amounts of reusable code available to
programmers greatly simplify the coding of complex programs involving
AI techniques. We demonstrate this in the final chapters of Part IV.
Object-oriented programming is based on the idea that programs can be
best modularized in terms of objects: encapsulated structures of data and
functionality that can be referenced and manipulated as a unit. The power
of this programming model is enhanced by inheritance, or the ability to
define sub-classes of more general objects that inherit and modify their
functionality, and the subtle control object-oriented languages provide over
the scoping of variables and functions alike.
The first language to build object-oriented representations was created in
Norway in the 1960s. Simula-67 was, appropriately, a simulation language.
Simulation is a natural application of object-oriented programming that
language objects are used to represent objects in the domain being
simulated. Indeed, this ability to easily define isomorphisms between the
representations in an object-oriented program and a simulation domain has
carried over into modern object-oriented programming style, where
programmers are encouraged to model domain objects and their
interactions directly in their code.
Perhaps the most elegant formulation of the object-oriented model is in
the Smalltalk programming language, built at Xerox PARC in the early
1970s. Smalltalk not only presented a very pure form of object-oriented
programming, but also used it as a tool for graphics programming. Many of
the ideas now central to graphics interfaces, such as manipulable screen
objects, event driven interaction, and so on, found their early
implementation in the Smalltalk language. Other, later implementations of

Luger_all_wcopyright_COsfixed.pd30 30 5/15/2008 6:34:54 PM


Chapter 1 Idioms, Patterns, and the Master programmer 15

object-programming include C++, Objective C, C#, and the Common


Lisp Object System. The success of the model has made it rare to find a
programming language that does not incorporate at least some object-
oriented ideas.
Our first introduction of object-oriented languages is with the Common
Lisp Object System in Chapter 18 of Part III. However, in Part IV, we
have chosen Java to present the use of object-oriented tools for AI
programming. Java offers an elegant implementation of object-orientation
that implements single inheritance, dynamic binding, interface definitions,
packages, and other object concepts in a language syntax that most
programmers will find natural. Java is also widely supported and
documented.
The primary reason, however, for including Java in this book is its great
success as a practical programming language for a large number and variety
of applications, most notably those on the world-wide-web. One of the
great benefits of object-oriented programming languages is that the ability
to define objects combining data and related methods in a single structure
encourages the development of reusable software objects.
Although Java is, at its core, a relatively simple language, the efforts of
thousands of programmers have led to large amounts of high-quality, often
open source, Java code. This includes code for networking, graphics,
processing html and XML, security, and other techniques for programming
on the world-wide-web. We will examine a number of public domain Java
tools for AI, such as expert system rule engines, machine learning
algorithms, and natural language parsers. In addition, the modularity and
control of the object-oriented model supports the development of large
programs. This has led to the embedding of AI techniques in larger and
indeed more ordinary programs. We see Java as an essential language for
delivering AI in practical contexts, and will discuss the Java language in this
context. In this book we refer primarily to public domain interpreters most
of which are easily web accessible.

1.4 A Summary of Our Task


We hope that in reading this introductory chapter, you have come to see
that our goal in writing this book is not simply to present basic
implementation strategies for major Artificial Intelligence algorithms.
Rather, our goal is to look at programming languages as tools for the
intellectual activities of design, knowledge modeling, and system
development.
Computer programming has long been the focus both for scientific theory
and engineering practice. These disciplines have given us powerful tools
for the definition and analysis of algorithms and for the practical
management of large and small programming projects. In writing this
book, it has been our overarching goal to provide a third perspective on
programming languages: as tools for the art of designing systems to
support people in their thinking, communication, and work.
It is in this third perspective that the ideas of idioms and patterns become

Luger_all_wcopyright_COsfixed.pd31 31 5/15/2008 6:34:55 PM


16 Part I: Language Idioms and the Master Programmer

important. It is not our goal simply to present examples of artificial


intelligence algorithms that can be reused in a narrow range of situations.
Our goal is to use these algorithms – with all their complexity and
challenges – to help programmers build a repertoire of patterns and idioms
that can serve well across a wide range of practical problem solving
situations. The examples of this book are not ends in themselves; they are
only small steps in the maturation of the master programmer. Our goal is
to see them as starting points for developing programmers’ skills. We hope
you will share our enthusiasm for these remarkable artist’s tools and the
design patterns and idioms they both enable and support.

Luger_all_wcopyright_COsfixed.pd32 32 5/15/2008 6:34:55 PM


PART II: Programming in Prolog

The only way to rectify our reasonings is to make them as tangible as those of the mathematicians, so that
we can find our error at a glance, and when there are disputes among persons we can simply say, “Let us
calculate… to see who is right.”
—Leibniz, The Art of Discovery

As an implementation of logic programming, Prolog makes many


important contributions to AI problem solving. First and foremost, is its
direct and transparent representation and interpretation of predicate
calculus expressions. The predicate calculus has been an important
representational scheme in AI from the beginning, used everywhere from
automated reasoning to robotics research. A second contribution to AI is
the ability to create meta-predicates or predicates that can constrain,
manipulate, and interpret other predicates. This makes Prolog ideal for
creating meta-interpreters or interpreters written in Prolog that can
interpret subsets of Prolog code. We will do this many times in the
following chapters, writing interpreters for expert rule systems, exshell,
interpreters for machine learning using version space search and
explanation based learning models, and deterministic and stochastic natural
language parsers.
Most importantly Prolog has a declarative semantics, a means of directly
expressing problem relationships in AI. Prolog also has built-in unification,
some high- powered techniques for pattern matching and a depth-first left
to right search. For a full description of Prolog representation, unification,
and search as well as Prolog interpreter compared to an automated
theorem prover, we recommend Luger (2009, Section 14.3) or references
mentioned in Chapter 10. We will also address many of the important
issues of Prolog and logic programming for artificial intelligence
applications in the chapters that make up Part II.
In Chapter 2 we present the basic Prolog syntax and several simple
programs. These programs demonstrate the use of the predicate calculus as
a representation language. We show how to monitor the Prolog
environment and demonstrate the use of the cut with Prolog’s built in
depth-first left-to-right search. We also present simple structured
representations including semantic nets and frames and present a simple
recursive algorithm that implements inheritance search.
In Chapter 3 we create abstract data types (ADTs) in Prolog. These ADTs
include stacks, queues, priority queues, and sets. These data types are the basis
for many of the search and control algorithms in the remainder of Part II.

17

Luger_all_wcopyright_COsfixed.pd33 33 5/15/2008 6:34:55 PM


18 Part II Programming in Prolog

In particular, they are used to build a production system in Chapter 4, which


can perform depth-first, breadth-first, and best-first or heuristic search. They also
are critical to algorithms later in Part II including building planners,
parsers, and algorithms for machine learning.
In Chapter 5 we begin to present the family of design patterns expressed
through building meta-interpreters. But first we consider a number of
important Prolog meta-predicates, predicates whose domains of interpretation
are Prolog expressions themselves. For example, atom(X) succeeds if X is
bound to an atom, that is if X is instantiated at the time of the atom(X)
test. Meta-predicates may also be used for imposing type constraints on
Prolog interpretations, and we present a small database that enforces
Prolog typing constraints.
In Chapter 6 meta-predicates are used for designing meta-interpreters in
Prolog. We begin by building a Prolog interpreter in Prolog. We extend
this interpreter to rule-based expert system processing with exshell and
then build a robot planner using add- and delete-lists along the lines of the
older STRIPS problem solver (Fikes and Nilsson 1972, Nilsson 1980).
In Chapter 7 we demonstrate Prolog as a language for machine learning,
with the design of meta-interpreters for version space search and explanation-
based learning. In Chapter 8 we build a number of natural language
parsers/generators in Prolog, including context-free, context-sensitive,
probabilistic, and a recursive descent semantic net parser.
In Chapter 9 we present the Earley parser, a form of chart parsing, an
important contribution to interpreting natural language structures. The
Earley algorithm is built on ideas from dynamic programming (Luger 2009,
Section 4.1.2 and 15.2.2) where the chart captures sub-parse components
as they are generated while the algorithm moves across the words of the
sentence. Possible parses of the sentence are retrieved from the chart after
completion of its left-to-right generation of the chart.
Part II ends with Chapter 10 where we return to the discussion of the
general issues of programming in logic, the design of meta-interpreters, and
issues related to procedural versus declarative representation for problem
solving. We end Chapter 10 presenting an extensive list of references on
the Prolog language.

Luger_all_wcopyright_COsfixed.pd34 34 5/15/2008 6:34:55 PM


2 Prolog: Representation

Chapter Prolog’s fundamental representations are described and built:


Objectives Facts
Rules
The and, or, not, and imply connectives
The environment for Prolog is presented:
The program as a data base of facts and relations between facts
Predicates are for creating and modifying this data base
Prolog’s procedural semantics is described with examples
Pattern-matching
Left-to-right depth-first search
Backtracking on variable bindings
The built-in predicates for monitoring Prolog’s execution are presented
spy and trace
The list representation and recursive search are introduced
Examples of member check and writing out lists
Representations for structured hierarchies are created in Prolog
Semantic net and frame systems
Inherited properties determined through recursive (tree) search

Chapter 2.1 Introduction: Logic-Based Representation


Contents 2.2 Syntax for Predicate Calculus Programming
2.3 Creating, Changing and Tracing a Prolog Computation
2.4 Lists and Recursion in Prolog
2.5 Structured Representations and Inheritance Search in Prolog

2.1 Introduction: Logic-Based Representation


Prolog and Prolog is a computer language that uses many of the representational
Logic
strengths of the First-Order Predicate Calculus (Luger 2009, Chapter 2).
Because Prolog has this representational power it can express general
relationships between entities. This allows expressions such as “all females
are intelligent” rather than the limited representations of the propositional
calculus: “Kate is intelligent”, “Sarah is intelligent”, “Karen is intelligent”,
and so on for a very long time!
As in the Predicate Calculus, predicates offer the primary (and only)
representational structure in Prolog. Predicates can have zero or more
arguments, where their arity is the number of arguments. Functions may
only be represented as the argument of a predicate; they cannot be a
program statement in themselves. Prolog predicates have the usual and,
or, not and implies connectives. The predicate representation along
with its connectives is presented in Section 2.2.

19

Luger_all_wcopyright_COsfixed.pd35 35 5/15/2008 6:34:56 PM


20 Part II: Programming in Prolog

Prolog also takes on many of the declarative aspects of the Predicate


Calculus in the sense that a program is simply the set of all true predicates
that describe a domain. The Prolog interpreter can be seen as a “theorem
prover” that takes the user’s query and determines whether or not it is true,
as well as what variable substitutions might be required to make the query
true. If the query is not true in the context of the program’s specifications,
the interpreter says “no.”
2.2 Prolog Syntax
Facts, Rules Although there are numerous dialects of Prolog, the syntax used
and throughout this text is that of the original Warren and Pereira C-Prolog as
Connectives
described by Clocksin and Mellish (2003). We begin with the set of
connectives that can take atomic predicates and join them with other
expressions to make more complex relationships. There are, because of the
usual keyboard conventions, a number of differences between Prolog and
predicate calculus syntax. In C-Prolog, for example, the symbol :- replaces
the  of first-order predicate calculus. The Prolog connectives include:
ENGLISH PREDICATE CALCULUS Prolog
and ^ ,
or v ;
only if  :-
not ~ not
In Prolog, predicate names and bound variables are expressed as a
sequence of alphanumeric characters beginning with an alphabetic.
Variables are represented as a string of alphanumeric characters beginning
(the first character, at least) with an uppercase alphabetic. Thus:
likes(X, susie).
or, better,
likes(Everyone, susie).
could represent the fact that “everyone likes Susie.” Note that the scope of
all variables is universal to that predicate, i.e., when a variable is used in a
predicate it is understood that it is true for all the domain elements within
its scope. For example,
likes(george, Y), likes(susie, Y).
represents the set of things (or people) liked by BOTH George and Susie.
Similarly, suppose it was desired to represent in Prolog the following
relationships: “George likes Kate and George likes Susie.” This could be
stated as:
likes(george, kate), likes(george, susie).
Likewise, “George likes Kate or George likes Susie”:
likes(george, kate); likes(george, susie).
Finally, “George likes Susie if George does not like Kate”:
likes(george, susie) :- not(likes(george, kate)).

Luger_all_wcopyright_COsfixed.pd36 36 5/15/2008 6:34:56 PM


Chapter 2 Prolog: Representation 21

These examples show how the predicate calculus connectives are expressed
in Prolog. The predicate names (likes), the number or order of parameters,
and even whether a given predicate always has the same number of
parameters are determined by the design requirements (the implicit
“semantics”) of the problem.
The form Prolog expressions take, as in the examples above, is a restricted
form of the full predicate calculus called the “Horn Clause calculus.” There
are many reasons supporting this restricted form, most important is the
power and computational efficiency of a resolution refutation system. For details
see Luger (2009, Chapter 14).
A Simple A Prolog program is a set of specifications in the first-order predicate
Prolog
Program
calculus describing the objects and relations in a problem domain. The set
of specifications is referred to as the database for that problem. The Prolog
interpreter responds to questions about this set of specifications. Queries to
the database are patterns in the same logical syntax as the database entries.
The Prolog interpreter uses pattern-directed search to find whether these
queries logically follow from the contents of the database.
The interpreter processes queries, searching the database in left to right
depth-first order to find out whether the query is a logical consequence of
the database of specifications. Prolog is primarily an interpreted language.
Some versions of Prolog run in interpretive mode only, while others allow
compilation of part or all of the set of specifications for faster execution.
Prolog is an interactive language; the user enters queries in response to the
Prolog prompt, “?-“.
Let us describe a “world” consisting of George’s, Kate’s, and Susie’s likes
and dislikes. The database might contain the following set of predicates:
likes(george, kate).
likes(george, susie).
likes(george, wine).
likes(susie, wine).
likes(kate, gin).
likes(kate, susie).
This set of specifications has the obvious interpretation, or mapping, into
the world of George and his friends. That world is a model for the database
(Luger 2009, Section 2.3). The interpreter may then be asked questions:
?- likes(george, kate).
Yes
?- likes(kate, susie).
Yes
?- likes(george, X).
X = kate
;
X = Susie
;
X = wine

Luger_all_wcopyright_COsfixed.pd37 37 5/15/2008 6:34:56 PM


22 Part II: Programming in Prolog

;
no
?- likes(george, beer).
no
Note first that in the request likes(george, X), successive user
prompts (;) cause the interpreter to return all the terms in the database
specification that may be substituted for the X in the query. They are
returned in the order in which they are found in the database: kate before
susie before wine. Although it goes against the philosophy of
nonprocedural specifications, a determined order of evaluation is a
property of most interpreters implemented on sequential machines.
To summarize: further responses to queries are produced when the user
prompts with the ; (or). This forces the rejection of the current solution
and a backtrack on the set of Prolog specifications for answers. Continued
prompts force Prolog to find all possible solutions to the query. When no
further solutions exist, the interpreter responds no.
This example also illustrates the closed world assumption or negation as failure.
Prolog assumes that “anything is false whose opposite is not provably
true.” For the query likes(george, beer), the interpreter looks for
the predicate likes(george, beer) or some rule that could
establish likes(george, beer). Failing this, the request is false.
Prolog assumes that all knowledge of the world is present in the database.
The closed world assumption introduces a number of practical and
philosophical difficulties in the language. For example, failure to include a
fact in the database often means that its truth is unknown; the closed world
assumption treats it as false. If a predicate were omitted or there were a
misspelling, such as likes(george, beeer), the response remains
no. Negation-as-failure issue is an important topic in AI research. Though
negation-as-failure is a simple way to deal with the problem of unspecified
knowledge, more sophisticated approaches, such as multi-valued logics
(true, false, unknown) and nonmonotonic reasoning (see Luger
2009, Section 9.1), provide a richer interpretive context.
The Prolog expressions just seen are examples of fact specifications. Prolog
also supports rule predicates to describe relationships between facts. We use
the logical implication :- . For rules, only one predicate is permitted on
the left-hand side of the if symbol :-, and this predicate must be a positive
literal, which means it cannot have not in front of it. All predicate calculus
expressions that contain logical implication must be reduced to this form,
referred to as Horn clause logic. In Horn clause form, the left-hand side
(conclusion) of an implication must be a single positive literal. The Horn
clause calculus is equivalent to the full first-order predicate calculus for proofs
by refutation (Luger 2009, Chapter 14).
Suppose we add to the specifications of the previous database a rule for
determining whether two people are friends. This may be defined:
friends(X, Y) :- likes(X, Z), likes(Y, Z).
This expression might be interpreted as “X and Y are friends if there exists
a Z such that X likes Z and Y likes Z.” Two issues are important here. First,

Luger_all_wcopyright_COsfixed.pd38 38 5/15/2008 6:34:56 PM


Chapter 2 Prolog: Representation 23

because neither the predicate calculus nor Prolog has global variables, the
scopes (extent of definition) of X, Y, and Z are limited to the friends
rule. Second, values bound to, or unified with, X, Y, and Z are consistent
across the entire expression. The treatment of the friends rule by the
Prolog interpreter is seen in the following example.
With the friends rule added to the set of specifications of the preceding
example, we can query the interpreter:
?- friends(george, susie).
yes
To solve this query, Prolog searches the database using the backtrack
algorithm. Briefly, backtrack examines each predicate specification in the
order that it was placed in the Prolog. If the variable bindings of the
specification satisfy the query it accepts them. If they don’t, the interpreter
goes on to the next specification. If the interpreter runs into a dead end,
i.e., no variable substitution satisfies it, then it backs up looking for other
variable bindings for the predicates it has already satisfied. For example,
using the predicate specifications of our current example, the query
friends(george, susie) is unified with the conclusion of the rule
friends(X, Y) :- likes(X, Z), likes(Y, Z), with X as
george and Y as susie. The interpreter looks for a Z such that
likes(george, Z) is true and uses the first fact, with Z as kate.
The interpreter then tries to determine whether likes(susie,
kate) is true. When it is found to be false, using the closed world
assumption, this value for Z (kate) is rejected. The interpreter backtracks
to find a second value for Z. likes(george, Z) then matches the
second fact, with Z bound to susie. The interpreter then tries to match
likes(susie, susie). When this also fails, the interpreter goes
back to the database for yet another value for Z. This time wine is found
in the third predicate, and the interpreter goes on to show that
likes(susie, wine) is true. In this case wine is the binding that
ties george and susie.
It is important to state the relationship between universal and existential
quantification in the predicate calculus and the treatment of variables in a
Prolog program. When a variable is placed in the specifications of a Prolog
database, it is universally quantified. For example, likes(susie, Y)
means, according to the semantics of the previous examples, “Susie likes
everyone.” In the course of interpreting a query, any term, or list, or
predicate from the domain of Y, may be bound to Y. Similarly, in the rule
friends(X, Y) :- likes(X, Z), likes(Y, Z), any X, Y,
and Z that meets the specifications of the expression are used.
To represent an existentially quantified variable in Prolog, we may take two
approaches. First, if the existential value of a variable is known, that value
may be entered directly into the database. Thus, likes(george,
wine) is an instance of likes(george, Z).
Second, to find an instance of a variable that makes an expression true, we
query the interpreter. For example, to find whether a Z exists such that
likes(george, Z) is true, we put this query to the interpreter. It will

Luger_all_wcopyright_COsfixed.pd39 39 5/15/2008 6:34:57 PM


24 Part II: Programming in Prolog

find whether a value of Z exists under which the expression is true. Some
Prolog interpreters find all existentially quantified values; C-Prolog requires
repeated user prompts (;), as shown previously, to get all values.
2.3 Creating, Changing, and Tracing a Prolog Computation
In building a Prolog program the database of specifications is created first.
In an interactive environment the predicate assert can be used to add
new predicates to the set of specifications. Thus:
?- assert(likes(david, sarah)).
adds this predicate to the computing specifications. Now, with the query:
?- likes(david, X).
X = sarah.
is returned. assert allows further control in adding new specifications to
the database: asserta(P) asserts the predicate P at the beginning of all
the predicates P, and assertz(P) adds P at the end of all the predicates
named P. This is important for search priorities and building heuristics. To
remove a predicate P from the database retract(P) is used. (It should
be noted that in many Prologs assert can be unpredictable in that the
exact entry time of the new predicate into the environment can vary
depending on what other things are going on, affecting both the indexing
of asserted clauses as well as backtracking.)
It soon becomes tedious to create a set of specifications using the
predicates assert and retract. Instead, the good programmer takes
her favorite editor and creates a file containing all the Prolog program’s
specifications. Once this file is created, call it myfile, and Prolog is
called, then the file is placed in the database by the Prolog command
consult. Thus:
?- consult(myfile).
yes
integrates the predicates in myfile into the database. A short form of the
consult predicate, and better for adding multiple files to the database,
uses the list notation, to be seen shortly:
?- [myfile].
yes
If there are any syntax errors in your Prolog code the consult operator
will describe them at the time it is called.
The predicates read and write are important for user/system
communication. read(X) takes the next term from the current input
stream and binds it to X. Input expressions are terminated with a “.”
write(X) puts X in the output stream. If X is unbound then an integer
preceded by an underline is printed (_69). This integer represents the
internal bookkeeping on variables necessary in a theorem-proving
environment (see Luger 2009, Chapter 14).
The Prolog predicates see and tell are used to read information from
and place information into files. see(X) opens the file X and defines the
current input stream as originating in X. If X is not bound to an available

Luger_all_wcopyright_COsfixed.pd40 40 5/15/2008 6:34:57 PM


Chapter 2 Prolog: Representation 25

file see(X) fails. Similarly, tell(X) opens a file for the output stream.
If no file X exists, tell(X) creates a file named by the bound value of X.
seen(X) and told(X) close the respective files.
A number of Prolog predicates are important in helping keep track of the
state of the Prolog database as well as the state of computing about the
database; the most important of these are listing, trace, and spy. If
we use listing(predicate_name) where predicate_name is
the name of a predicate, such as friends (above), all the clauses with
that predicate name in the database are returned by the interpreter. Note
that the number of arguments of the predicate is not indicated; in fact, all
uses of the predicate, regardless of the number of arguments, are returned.
trace allows the user to monitor the progress of the Prolog interpreter.
This monitoring is accomplished by printing to the output file every goal
that Prolog attempts, which is often more information than the user wants
to have. The tracing facilities in Prolog are often rather cryptic and take
some study and experience to understand. The information available in a
trace of a Prolog program usually includes the following:
The depth level of recursive calls (marked left to right on line).
When a goal is tried for the first time (sometimes call is used).
When a goal is successfully satisfied (with an exit).
When a goal has further matches possible (a retry).
When a goal fails because all attempts to satisfy it have failed
The goal notrace stops the exhaustive tracing.
When a more selective trace is required the goal spy is useful. This
predicate takes a predicate name as argument but sometimes is defined as a
prefix operator where the predicate to be monitored is listed after the
operator. Thus, spy member causes the interpreter to print to output all
uses of the predicate member. spy can also take a list of predicates
followed by their arities: spy[member/2, append/3] monitors
member with two arguments and append with three. nospy removes
these spy points.
2.4 Lists and Recursion in Prolog
The previous subsections presented Prolog syntax with several simple
examples. These examples introduced Prolog as an engine for computing
with predicate calculus expressions (in Horn clause form). This is
consistent with all the principles of predicate calculus inference presented
in Luger (2009, Chapter 2). Prolog uses unification for pattern matching
and returns the bindings that make an expression true. These values are
unified with the variables in a particular expression and are not bound in
the global environment.
Recursion is the primary control mechanism for Prolog programming. We
will demonstrate this with several examples. But first we consider some
simple list-processing examples. The list is a data structure consisting of
ordered sets of elements (or, indeed, lists). Recursion is the natural way to
process the list structure. Unification and recursion come together in list

Luger_all_wcopyright_COsfixed.pd41 41 5/15/2008 6:34:57 PM


26 Part II: Programming in Prolog

processing in Prolog. The set of elements of a list are enclosed by brackets,


[ ], and are separated by commas. Examples of Prolog lists are:
[1, 2, 3, 4]
[[george, kate], [allen, amy], [richard, shirley]]
[tom, dick, harry, fred]
[ ]
The first elements of a list may be separated from the tail of the list by the
bar operator, |. The tail of a list is the list with its first element removed.
For instance, when the list is [tom,dick,harry,fred], the first
element is tom and the tail is the list [dick, harry, fred]. Using
the vertical bar operator and unification, we can break a list into its
components:
If [tom, dick, harry, fred] is matched to [X | Y],
then X = tom and Y = [dick, harry, fred].
If [tom,dick,harry,fred] is matched to the pattern
[X, Y | Z], then X = tom , Y = dick , and Z =
[harry, fred].
If [tom, dick, harry, fred] is matched to [X, Y, Z |
W], then X = tom, Y = dick, Z = harry, and W =
[fred].
If [tom, dick, harry, fred] is matched to [W, X, Y,
Z | V], then W = tom, X = dick, Y = harry, Z = fred,
and V = [ ].
[tom, dick, harry, fred] will not match [V, W, X, Y,
Z | U].
[tom, dick, harry, fred] will match [tom, X |
[harry, fred]], to give X = dick.
Besides “tearing lists apart” to get at particular elements, unification can be
used to “build” the list structure. For example, if X = tom, Y =
[dick] when L unifies with [X | Y], then L will be bound to [tom,
dick]. Thus terms separated by commas before the | are all elements of
the list, and the structure after the | is always a list, the tail of the list.
Let’s take a simple example of recursive processing of lists: the member
check. We define a predicate to determine whether an item, represented by
X, is in a list. This predicate member takes two arguments, an element and
a list, and is true if the element is a member of the list. For example:
?- member(a, [a, b, c, d, e]).
yes
?- member(a, [1, 2, 3, 4]).
no
?- member(X, [a, b, c]).
X = a
;
X = b
;
X = c

Luger_all_wcopyright_COsfixed.pd42 42 5/15/2008 6:34:57 PM


Chapter 2 Prolog: Representation 27

;
no
To define member recursively, we first test if X is the first item in the list:
member(X, [X | T]).
This tests whether X and the first element of the list are identical. Not that
this pattern will match no matter what X is bound to: an atom, a list,
whatever! If the two are not identical, then it is natural to check whether X
is an element of the rest (T) of the list. This is defined by:
member(X, [Y | T]) :- member(X, T).
The two lines of Prolog for checking list membership are then:
member(X, [X | T]).
member(X, [Y | T]) :- member(X, T).
This example illustrates the importance of Prolog’s built-in order of search
with the terminating condition placed before the recursive call, that is, to be
tested before the algorithm recurs. If the order of the predicates is reversed,
the terminating condition may never be checked. We now trace
member(c,[a,b,c]), with numbering:
1: member(X, [X | T]).
2: member(X, [Y | T]) :- member(X, T).
?- member(c, [a, b, c]).
call 1. fail, since c <> a
call 2. X = c, Y = a, T = [b, c],
member(c, | [b,c])?
call 1. fail, since c <> b
call 2. X = c, Y = b, T = [c],
member(c, | [c])?
call 1. success, c = c
yes (to second call 2.)
yes (to first call 2.)
yes
Good Prolog style suggests the use of anonymous variables. These serve as an
indication to the programmer and interpreter that certain variables are used
solely for pattern-matching purposes, with the variable binding itself not
part of the computation process. Thus, when we test whether the element
X is the same as the first item in the list we usually say: member(X,
[X|_]). The use of the _ indicates that even though the tail of the list
plays a crucial part in the unification of the query, the content of the tail of
the list is unimportant. In the member check the anonymous variable
should be used in the recursive statement as well, where the value of the
head of the list is unimportant:
member(X, [X | _]).
member(X, [_ | T]) :- member(X, T).
Writing out a list one element to a line is a nice exercise for understanding
both lists and recursive control. Suppose we wish to write out the list
[a,b,c,d]. We could define the recursive command:
writelist([ ]).
writelist([H | T]) :- write(H), nl, writelist(T).

Luger_all_wcopyright_COsfixed.pd43 43 5/15/2008 6:34:58 PM


Exploring the Variety of Random
Documents with Different Content
EL PEQUEÑO VIGÍA LOMBARDO
(CUENTO MENSUAL)

Sábado 26.—En 1859, durante la guerra por el rescate de


Lombardía, pocos días después de la batalla de Solferino y San
Martino, ganada por los franceses y los italianos contra los
austríacos, en una hermosa mañana del mes de junio, una sección
de caballería de Saluzo iba, a paso lento, por estrecha senda solitaria
hacia el enemigo, explorando el campo atentamente. Mandaban la
sección un oficial y un sargento, y todos miraban a lo lejos delante
de sí, con los ojos fijos, silenciosos, preparándose para ver
blanquear a cada momento, entre los árboles, las divisiones de las
avanzadas enemigas. Llegaron así a cierta casita rústica, rodeada de
fresnos, delante de la cual sólo había un muchacho como de doce
años, que descortezaba gruesa rama con un cuchillo para
proporcionarse un bastón; en una de las ventanas de la casa
tremolaba al viento la bandera tricolor; dentro no había nadie: los
aldeanos, izada su bandera, habían escapado por miedo a los
austríacos. Apenas divisó la caballería el muchacho, tiró el bastón y
se quitó la gorra. Era un hermoso niño de aire descarado, con ojos
grandes y azules, los cabellos rubios y largos; estaba en mangas de
camisa y enseñaba el pecho desnudo. “¿Qué haces aquí?—le
preguntó el oficial, parando el caballo—. ¿Por qué no has huido con
tu familia?”. “Yo no tengo familia—respondió el muchacho—. Soy
expósito. Trabajo algo al servicio de todos. Me he quedado aquí para
ver la guerra”. “¿Has visto pasar a los austríacos?”. “No, desde hace
tres días”.

El oficial se quedó un poco pensativo; después se apeó del caballo,


y, dejando los soldados allí vueltos hacia el enemigo, entró en la
casa y se subió hasta el tejado: no se veía más que un pedazo de
campo. “Es menester subir sobre los árboles”, pensó el oficial; y
bajó. Precisamente delante de la era se alzaba un fresno altísimo y
flexible, cuya cumbre casi se mecía en las nubes. El oficial estuvo
por momentos indeciso, mirando ya al árbol, ya a los soldados;
después, de pronto, preguntó al muchacho: “¿Tienes buena vista,
chico?”. “¿Yo?—respondió el muchacho—. Yo veo a un gorrioncillo
aunque esté a dos leguas”. “¿Sabrás tú subir a la cima de aquel
árbol?”. “¿A la cima de aquel árbol, yo? En medio minuto me subo”.
“¿Y sabrás decirme lo que veas desde allí arriba, si son soldados
austríacos, nubes de polvo, fusiles que relucen, caballos...?”. “De
seguro que sabré”. “¿Qué quieres por prestarme este servicio?”.
“¿Qué quiero?—dijo el muchacho sonriendo—. Nada. ¡Vaya una
cosa! Y después, si fuera por los alemanes; entonces por ningún
precio; ¡pero por los nuestros! ¡Si yo soy lombardo!”. “Bien; súbete,
pues”. “Espere que me quite los zapatos”.

Se quitó el calzado, se apretó el cinturón, echó al suelo la gorra y se


abrazó al tronco del fresno. “Pero, mira...”, exclamó el oficial,
intentando detenerlo como sobrecogido por repentino temor.

El muchacho se volvió a mirarlo con sus hermosos ojos azules, en


actitud interrogante—. “Nada—dijo el oficial—; sube”.

El muchacho se encaramó como un gato. “¡Mirad delante de


vosotros!”, gritó el oficial a los soldados.

En pocos momentos el muchacho estuvo en la copa del árbol,


abrazado al tronco, con las piernas entre las hojas, pero con el
pecho descubierto, y su rubia cabeza resplandecía con el sol
pareciendo oro. El oficial apenas lo veía: tan pequeño resultaba allí
arriba. “Mira hacia el frente, y muy lejos”, gritó el oficial.

El chico, para ver mejor, sacó la mano derecha, que apoyaba en el


árbol, y se la puso sobre los ojos a manera de pantalla. “¿Qué ves?”
preguntó el oficial.

El muchacho inclinó la cara hacia él, y, haciendo portavoz de su


mano, respondió: “Dos hombres a caballo en lo blanco del camino”.
“¿A qué distancia de aquí?”. “Media legua”. “¿Se mueven?”. “Están
parados”. “¿Qué otra cosa ves?”—preguntó el oficial, después de un
instante de silencio—. “Mira a la derecha”. El chico dijo: “Cerca del
cementerio, entre los árboles, hay algo que brilla; parecen
bayonetas”. “¿Ves gente?”. “No; estarán escondidos entre los
sembrados”.

En aquel momento un silbido de bala agudísimo se sintió por el aire


y fué a perderse lejos, detrás de la casa. “¡Bájate, muchacho! gritó
el oficial—. Te han visto. No quiero saber más. Vente abajo”. “Yo no
tengo miedo”, respondió el chico. “¡Baja...!”, repitió el oficial. “¿Qué
más ves a la izquierda?”. “¿A la izquierda?”.

El muchacho volvió la cabeza a la izquierda. En aquel momento otro


silbido más agudo y más bajo hendió los aires. El muchacho se
ocultó todo lo que pudo. “¡Vamos!—exclamó—; la han tomado
conmigo!”. La bala le había pasado muy cerca. “¡Abajo!”, gritó el
oficial con energía y furioso. “En seguida bajo—respondió el chico—;
pero el árbol me resguarda; no tenga usted cuidado. ¿A la izquierda
quiere usted saber?”. “A la izquierda—respondió el oficial—; pero
baja”. “A la izquierda—gritó el niño, dirigiendo el cuerpo hacia
aquella parte—, donde hay una capilla, me parece ver...”. Un tercer
silbido pasó por lo alto, y en seguida se vió al muchacho venir abajo,
deteniéndose un punto en el tronco y en las ramas, y precipitándose
después de cabeza con los brazos abiertos. “¡Maldición!”, gritó el
oficial acudiendo.

El chico cayó a tierra de espaldas, y quedó tendido con los brazos


abiertos, boca arriba; un arroyo de sangre le salió del pecho, a la
izquierda. El sargento y dos soldados se apearon de sus caballos: el
oficial se agachó y le separó la camisa; la bala le había entrado en el
pulmón izquierdo. “¡Está muerto!”, exclamó el oficial. “¡No, vive!”,
replicó el sargento. “¡Ah, pobre niño, valiente muchacho!—gritó el
oficial—. ¡Ánimo, ánimo!”. Pero mientras decía “ánimo” y le oprimía
el pañuelo sobre la herida, el muchacho movió los ojos e inclinó la
cabeza; había muerto. El oficial palideció y lo miró fijo un minuto,
después le arregló la cabeza sobre la hierba, se levantó y estuvo
otro instante mirándolo. También el sargento y los dos soldados,
inmóviles, lo miraban; los demás estaban vueltos hacia el enemigo.
“¡Pobre muchacho!—repitió tristemente el oficial—. ¡Pobre y valiente
niño!”.

Luego se acercó a la casa, quitó de la ventana la bandera tricolor y


la extendió como paño fúnebre sobre el pobre muerto, dejándole la
cara descubierta. El sargento acercó al lado del muerto los zapatos,
la gorra, el bastón y el cuchillo.

Permanecieron aún un rato silenciosos; después el oficial se volvió al


sargento, y le dijo: “Mandaremos que lo recoja la ambulancia: ha
muerto como soldado, y como soldado debemos enterrarlo”. Dicho
esto, dió al muerto un beso en la frente y gritó: “¡A caballo!”. Todos
se aseguraron en las sillas, reunióse la sección y volvió a emprender
la marcha.

Pocas horas después, el pobre muerto tuvo los honores de guerra.

Al ponerse el sol, toda la línea de las avanzadas italianas se dirigía


hacia el enemigo, y por el mismo camino que recorrió por la mañana
la sección de caballería, caminaba en dos filas un bravo batallón de
cazadores, el cual pocos días antes había regado valerosamente con
su sangre el collado de San Martino. La noticia de la muerte del
muchacho había corrido ya entre los soldados antes que dejaran sus
campamentos. El camino, flanqueado por un arroyuelo, pasaba a
pocos pasos de distancia de la casa. Cuando los primeros oficiales
del batallón vieron al pequeño cadáver tendido al pie del fresno y
cubierto con la bandera tricolor, lo saludaron con sus sables y uno de
ellos se inclinó sobre la orilla del arroyo, que estaba muy florida,
arrancó las flores y se las echó. Entonces todos los cazadores,
conforme iban pasando, cortaban flores y las arrojaban al muerto.
En pocos momentos el muchacho se vió cubierto de flores, y los
soldados le dirigían todos sus saludos al pasar. “¡Bravo, pequeño
lombardo! ¡Adiós, niño! ¡Adiós, rubio! ¡Viva! ¡Bendito sea! ¡Adiós!”.
Un oficial le puso su cruz roja, otro le besó en la frente y las flores
continuaban lloviendo sobre sus desnudos pies, sobre el pecho
ensangrentado, sobre la rubia cabeza. Y él parecía dormido en la
hierba, envuelto en la bandera, con el rostro pálido y casi sonriente,
como si oyese aquellos saludos y estuviese contento de haber dado
la vida por su patria.
LOS POBRES
Martes 29.—“Dar la vida por la patria, como el muchacho lombardo,
es una gran virtud; pero no olvides tampoco, hijo mío, otras virtudes
menos brillantes. Esta mañana, yendo delante de mí cuando
volvíamos de la escuela, pasaste junto a una pobre que tenía sobre
sus rodillas a un niño extenuado y pálido, y que te pidió limosna. Tú
la miraste y no le diste nada, y quizás llevaras dinero en el bolsillo.
Oye, hijo mío. No te acostumbres a pasar con indiferencia delante de
la miseria que tiende la mano, y mucho menos delante de una
madre que pide limosna para su hijo. Piensa en que quizá aquel niño
tuviera hambre; piensa en la desesperación de aquella mujer.
Imagínate el desesperado sollozo de tu madre, cuando un día te
tuviese que decir: ‘Enrique, hoy no puedo darte ni un pedazo de
pan’. Cuando yo doy diez céntimos a un pobre y éste me dice: ‘¡Dios
le dé salud a usted y a sus hijos!’, tú no puedes comprender la
dulzura que siento en mi corazón con aquellas palabras, y la gratitud
que aquel hombre me inspira. Me parece que, con aquel buen
presagio, voy a conservar mi salud y tú la tuya por mucho tiempo, y
vuelvo a casa pensando: ‘¡Oh, aquel pobre me ha dado más de lo
que yo le he dado a él!’. Pues bien: haz tú por oír alguna vez buenos
augurios análogos, provocados, merecidos por ti; saca de vez en
cuando cuartos de tu bolsillo para dejarlos caer en la mano del viejo
necesitado, de la madre sin pan, del niño sin madre. A los pobres les
gusta la limosna de los niños, porque no les humilla, y porque los
niños, que necesitan de todo el mundo, se les parecen. He aquí por
qué siempre hay pobres en la puerta de las escuelas. La limosna del
hombre es acto de caridad; pero la del niño, al mismo tiempo que
un acto de caridad, es caricia. ¿Comprendes? Es como si de su mano
cayeran a la vez un socorro y una flor. Piensa en que a ti no te falta
nada, mientras que les falta todo a ellos; que mientras tú ambicionas
ser feliz, ellos con vivir se contentan. Piensa que es un horror que en
medio de tantos palacios, en las calles por donde pasan carruajes y
niños vestidos de terciopelo, hay mujeres y niños que no tienen qué
comer. ¡No tener qué comer, Dios mío! ¡Niños como tú, como tú,
buenos; inteligentes como tú, que en medio de una gran ciudad no
tienen qué comer, como fieras perdidas en un desierto! ¡Oh,
Enrique!: no pases nunca más delante de una madre que pide
limosna, sin dejarle un socorro en la mano.—Tu madre”.
DICIEMBRE

EL COMERCIANTE
Jueves 1.º
I padre quiere que cada día de fiesta haga venir a casa
a uno de mis compañeros, o que vaya a buscarlo para
hacerme poco a poco amigo de todos. El domingo fuí a
pasear con Votino: aquél tan bien vestido, que se está
siempre alisando y que tiene tanta envidia de Deroso.
Hoy ha venido a casa Garofi: aquél alto y delgado, con la nariz de
pico de loro y los ojos pequeños y vivos, que parecen sondearlo
todo. Es hijo de un droguero, y tipo muy original. Está siempre
contando los cuartos que tiene en el bolsillo; cuenta muy de prisa
con los dedos, y verifica cualquier multiplicación sin necesidad de
tabla pitagórica. Hace sus economías, y tiene ya una libreta de la
Caja de Ahorros escolar. Es desconfiado, no gasta nunca un cuarto, y
si se le cae un céntimo debajo del banco, es capaz de pasarse la
semana buscándolo. “Es como la urraca”, dice Deroso. Todo lo que
encuentra, plumas gastadas, sellos usados, alfileres, cerillas, todo lo
recoge. Hace ya más de dos años que colecciona sellos, y tiene ya
centenares de todos los países, en su grande álbum, que venderá
después al librero cuando esté completo. Entretanto, el librero le da
muchos cuadernos gratis, porque le lleva los niños a la tienda. En la
escuela está siempre traficando; todos los días vende, hace loterías
y subastas; después se arrepiente y quiere sus mercancías; compra
por dos y vende por cuatro; juega a las aleluyas y jamás pierde;
vende los periódicos atrasados al estanquero, y tiene un cuaderno
donde anota todos sus negocios, lleno todo él de sumas y de restas.
En la escuela sólo estudia Aritmética; y si ambiciona premios, no es
más que por tener entrada gratis en el teatro Guiñol. A mí me gusta
y me entretiene. Hemos jugado a hacer una tienda con los pesos y
las balanzas: él sabe el precio exacto de todas las cosas, conoce las
pesas y hace muy pronto y bien cartuchos y paquetes como los
tenderos. Dice que apenas salga de la escuela, emprenderá un
negocio, un comercio nuevo, inventado por él. Ha estado muy
contento porque le he dado sellos extranjeros, y me ha dicho al
punto en cuánto se vende cada uno para las colecciones. Mi padre,
haciendo como que leía el periódico, le estaba oyendo y se divertía.
Siempre lleva los bolsillos llenos de sus pequeñas mercancías, que
cubre con un largo delantal negro, y parece que está continuamente
pensativo y muy ocupado, como los comerciantes. Pero lo que le
gusta más que todo es su colección de sellos: éste es su tesoro, y
habla siempre de él como si debiese sacar de aquí una fortuna. Los
compañeros lo creen avaro y usurero. Yo no pienso así. Le quiero
bien; me enseña muchas cosas, y me parece un hombre. Coreta, el
hijo del vendedor de leña, dice que no daría Garofi sus sellos ni para
salvar la vida de su madre. Mi padre no lo cree. “Espera aún para
juzgarle, me ha dicho; tiene, en efecto, esa pasión; pero su corazón
es bueno”.

VANIDAD
Lunes 5.—Ayer fuí a pasear por la alameda de Rívoli con Votino y su
padre. Al pasar por la calle Dora Grosa vimos a Estardo, el que se
incomoda con los revoltosos, parado muy tieso delante del
escaparate de un librero, con los ojos fijos en un mapa: y sabe Dios
desde cuándo estaría allí, porque él estudia hasta en la calle; ni
siquiera nos saludó el muy grosero. Votino iba muy bien vestido,
quizá demasiado; llevaba botas de tafilete con pespuntes
encarnados, un traje con adornos y vivos de seda, sombrero blanco
de castor y reloj. Pero su vanidad debía parar en mal esta vez.
Después de haber andado buen trecho por la calle, dejándonos muy
atrás a su padre, que marchaba despacio, nos paramos en un
asiento de piedra junto a un muchacho modestamente vestido que
parecía cansado y estaba pensativo, con la cabeza baja. Un hombre,
que debía ser su padre, paseaba bajo los árboles leyendo un
periódico. Nos sentamos. Votino se puso entre el otro niño y yo. De
pronto se acordó de que estaba bien vestido, y quiso hacerse
admirar y envidiar de nuestro vecino. Levantó un pie y me dijo:
“¿Has visto mis botas nuevas?”. Lo decía para que el otro las mirara,
pero éste no se fijó. Entonces bajó el pie y me enseñó las borlas de
seda, mirando de reojo al muchacho, añadiendo que aquellas borlas
de seda no le gustaban y que las quería cambiar por botones de
plata. Pero el chico no miró tampoco.
Votino, entonces, se puso a jugar, dándole vueltas sobre el índice,
con su precioso sombrero de castor blanco: pero el niño parecía que
lo hacía de propósito; no se dignó dirigir siquiera una mirada al
sombrero.

Votino, que empezaba a exasperarse, sacó el reloj, lo abrió y me


enseñó la máquina. Pero el vecino, sin volver la cabeza. “¿Es plata
sobredorada?”, le pregunté. “Es de oro”. “Pero no será todo de oro—
le dije—; habrá también algo de plata”. “No hombre, no”, replicó. Y
para obligar al muchacho a mirar, le puso el reloj delante de sus
ojos, diciéndole: “Di tú, mira: ¿no es verdad que es todo de oro?”. El
chico respondió secamente: “No lo sé”. “¡Oh, oh!—exclamó Votino,
lleno de rabia—. ¡Qué soberbia!”.

Mientras decía esto, llegó su padre, que le oyó; miró un rato


fijamente a aquel niño, y después dijo bruscamente a su hijo:
“Calla”; e inclinándose a su oído, añadió: “¡Es ciego!”.

Votino se puso en pie de pronto de un salto y miró la cara del


muchacho. Tenía las pupilas apagadas, sin expresión, sin mirada.

Votino se quedó anonadado, sin palabra, con los ojos en tierra.


Después balbuceó: “¡Lo siento; no lo sabía!”.

Pero el ciego, que lo había comprendido todo, dijo con una sonrisa
breve y melancólica: “¡Oh, no importa nada!”.

Cierto que es vano; pero no tiene, en manera alguna, mal corazón


Votino. En todo el paseo no se volvió a reír.

LA PRIMERA NEVADA
Sábado 10.—¡Adiós, paseos a Rívoli! Llegó la hermosa amiga de los
niños. ¡Ya están aquí las primeras nieves! Ayer tarde, a última hora,
cayeron copos finos y abiertos, como flores de jazmín. Era un gusto
esta mañana, en la escuela, verla caer contra los cristales y
amontonarse sobre los balcones; también el maestro miraba y se
frotaba las manos; y todos estaban contentos pensando hacer bolas,
en el hielo que vendría después, y en el hogar de la casa.
Únicamente Estardo no se distraía, completamente absorto en la
lección y con los puños apoyados en las sienes. ¡Qué hermosura,
cuánta alegría hubo a la salida! Todos salíamos a la desbandada por
las calles, gritando y charlando, cogiendo pelotones de nieve y
zambulléndonos dentro como perrillos en el agua. Los padres que
esperaban fuera ya tenían los paraguas blancos; los guardias
municipales también blancos sus quepís; nuestras carteras se
pusieron blancas en seguida. Todos parecían en su delirio fuera de
sí: hasta Precusa, el hijo del forjador, aquel pálido que nunca se ríe,
y hasta Roberto, el que salvó al niño del ómnibus, el pobrecillo
saltaba con sus muletas. El calabrés, que no había tocado nunca la
nieve, hizo una pelota y se puso a comérsela como un melocotón.
Crosi, el hijo de la verdulera, se llenó de nieve la cartera, y el
albañilito nos hizo desternillar de risa cuando mi padre le invitó a
venir mañana a casa; tenía la boca llena de nieve, y no atreviéndose
a escupirla ni a tragársela, se quedó atónito mirándonos, sin
responder. También las maestras salían de la escuela corriendo y
riendo: hasta mi maestra de primera enseñanza superior, ¡pobrecilla!
corría atravesando la nieve, preservándose la cara con un velo verde
y tosiendo. Mientras tanto, centenares de muchachas de la escuela
inmediata pasaban chillando y pisoteando sobre aquella blanca
alfombra, y los maestros, los bedeles y los guardias gritaban: “¡A
casa, a casa!”, tragando copos de nieve y quitándosela de los bigotes
y de la barba. Pero también ellos se reían de aquella turba de
muchachos que festejaban el invierno...

“...Festejáis el invierno...; pero hay niños sin pan, sin zapatos, sin
lumbre. Hay millares que bajan a las ciudades después de largo
camino, llevando en sus manos ensangrentadas por los sabañones,
un pedazo de leña para calentar la escuela. Hay centenares de
escuelas casi sepultadas entre la nieve, desnudas y obscuras como
cavernas, donde los chicos se ahogan por el humo, dan diente con
diente por el frío, mirando con horror los blancos copos que caen sin
cesar, que se amontonan sin descanso sobre sus lejanas cabañas,
amenazadas por el peso de los témpanos de hielo. Vosotros, niños,
festejáis el invierno. ¡Pensad en los miles de criaturas a quienes el
invierno trae la miseria y la muerte!—Tu padre”.

EL ALBAÑILITO
Domingo 11.—El “albañilito” ha venido hoy de cazadora, vestido con
la ropa de su padre, blanca todavía por la cal y el yeso. Mi padre
deseaba que viniese, aún más que yo. ¡Cómo le gusta! Apenas
entró, se quitó su viejísimo sombrero, que estaba todo cubierto de
nieve, y se lo metió en el bolsillo; después vino hacia mí con aquel
andar descuidado de cansado trabajador, volviendo aquí y allá su
cabeza, redonda como una manzana, y con su nariz roma; y cuando
fué al comedor, dirigiendo una ojeada a los muebles, fijó sus ojos en
un cuadrito que representaba a Rigoleto, un bufón jorobado, y puso
la cara de “hocico de conejo”. Es imposible dejar de reír al vérselo
hacer. Nos pusimos a jugar con palitos; tiene una habilidad
extraordinaria para hacer torres y puentes, que parece se están de
pie por milagro, y trabaja en ello muy serio, con la paciencia de un
hombre. Entre una y otra torre me habla de su familia; viven en una
boardilla; su padre va a la escuela de adultos, de noche, a aprender
a leer; su madre no es de aquí. Parece que le quieren mucho,
porque aunque él viste pobremente, va bien resguardado del frío,
con la ropa muy remendada y el lazo de la corbata bien hecho y
anudado por su misma madre. Su padre, me dice, es un hombretón,
un gigante, que apenas cabe por la puerta; es bueno, y llama
siempre a su hijo “hocico de liebre”; el hijo, en cambio, es pequeñín.
A las cuatro merendamos juntos, pan y pasas, sentados en el sofá, y
cuando nos levantamos, no sé por qué mi padre no quiso que
limpiara el espaldar que el albañilito había manchado de blanco con
su chaqueta; me detuvo la mano y lo limpió después él sin que lo
viéramos. Jugando, al albañilito se le cayó un botón de la cazadora,
y mi madre se lo cosió; él se puso encarnado, y la veía coser muy
admirado y confuso, no atreviéndose ni a respirar. Después le
enseñé el álbum de caricaturas, y él, sin darse cuenta, imitaba los
gestos de aquellas caras, tan bien, que hasta mi padre se reía.
Estaba tan contento cuando se fué que se olvidó de ponerse el
andrajoso sombrero, y al llegar a la puerta de la escalera, para
manifestarme su gratitud, me hacía otra vez la gracia de poner el
“hocico de liebre”. Se llama Antonio Rabusco, y tiene ocho años y
ocho meses.

“¿Sabes, hijo mío, por qué no quise que limpiaras el sofá? Porque
limpiarle mientras tu compañero lo veía, era casi hacerle una
reconvención por haberlo ensuciado. Y esto no estaba bien: en
primer lugar, porque no lo había hecho de intento, y en segundo,
porque le había manchado con ropa de su padre, que se la había
enyesado trabajando; y lo que se mancha trabajando no ensucia: es
polvo, cal, barniz, todo lo que quieras, pero no es suciedad. El
trabajo no ensucia. No digas nunca de un obrero que sale de su
trabajo: ‘Va sucio’. Debes decir: ‘Tiene en sus ropas las señales, las
huellas del trabajo’. Recuérdalo. Quiere mucho al albañilito: primero,
porque es compañero tuyo, y además, porque es hijo de un obrero.
—Tu padre”.

UNA BOLA DE NIEVE


Viernes 16.—Sigue nevando, nevando. Ha sucedido un accidente
desagradable esta mañana, al salir de la escuela. Un tropel de
muchachos, apenas llegaron a la plaza, se pusieron a hacer bolas
con aquella nieve acuosa que hace bolas sólidas y pesadas como
piedras. Mucha gente pasaba por la acera. Un señor gritó: “¡Alto,
chicos!”. Y precisamente en aquel momento se oyó un grito agudo
en la otra parte de la calle, se vió a un viejo que había perdido su
sombrero y andaba vacilante, cubriéndose la cara con las manos, y a
su lado un niño que gritaba: “¡Socorro, socorro!”. En seguida acudió
gente de todas partes. Le había dado una bola en un ojo. Todos los
muchachos corrieron a la desbandada, huyendo como saetas. Yo
estaba ante la tienda del librero, donde había entrado mi padre, y vi
llegar a la carrera a varios compañeros míos que se mezclaron entre
los que estaban junto a mí y hacían como que miraban los
escaparates: eran Garrón, con su acostumbrado panecillo en el
bolsillo; Coreta, el albañilito y Garofi, el de los sellos. Mientras tanto,
se había reunido gente alrededor del viejo, y los guardias corrían de
una parte a otra, amenazando y gritando: “¿Quién ha sido? ¿Quién?
¿Eres tú? Decid quién ha sido”. Y miraban las manos de los
muchachos para ver si las tenían humedecidas de la nieve. Garofi
estaba a mi lado; reparé que temblaba mucho y estaba pálido como
un muerto. “¿Quién es? ¿Quién ha sido?”, continuaban gritando la
gente. Entonces vi a Garrón que dijo por lo bajo a Garofi: “Anda, ve
a presentarte; sería una villanía dejar que sospechen de otro”. “¡Pero
si yo no lo he hecho de intento!”, respondió Garofi temblando como
la hoja de un árbol. “No importa; cumple con tu deber”, contestó
Garrón. “¡Pero si no tengo valor para confesarlo!”. “Anímate, yo te
acompaño”. Y los guardianes y la gente gritaban cada vez más
fuerte: “¿Quién es? ¿Quién ha sido? Le han metido un cristal de sus
lentes en un ojo. Le han dejado ciego. ¡Perdidos!”. Yo creí que Garofi
caía en tierra. “Ven—le dijo resueltamente Garrón—; yo te defiendo”.
Y cogiéndole por un brazo, lo empujó hacia adelante, sosteniéndolo
como a un enfermo. La gente lo vió y lo comprendió todo en
seguida, y muchos corrieron con los puños levantados. Pero Garrón
se puso en medio gritando: “¿Qué vais a hacer, diez hombres contra
un niño?”. Entonces ellos se detuvieron, y un guardia municipal
cogió a Garofi y lo llevó, abriéndose paso entre la multitud, a una
pastelería, donde habían refugiado al herido. Viéndolo, reconocí en
seguida al viejo empleado que vive con su sobrinillo en un cuarto
piso de nuestra casa. Lo habían recostado en una silla con un
pañuelo en los ojos. “¡Ha sido sin querer!”, balbuceaba Garofi. Dos
personas le arrojaron violentamente en la tienda, gritando: “¡Abajo
esa cabeza! ¡Pide perdón!”. Y lo echaron al suelo. Pero de pronto,
dos brazos vigorosos lo pusieron en pie, y una voz resuelta dijo:
“¡No, señores!”. Era nuestro director, que lo había visto todo. “Puesto
que ha tenido el valor de presentarse, nadie tiene derecho de
vejarlo”. Todos permanecieron callados. “Pide perdón”, dijo el
director a Garofi. Garofi, ahogado en llanto, abrazó las rodillas del
viejo, y éste, buscando con la mano su cabeza, lo acarició
cariñosamente. Entonces todos dijeron: “Vamos, muchacho, vete a
casa”. Y mi padre me sacó de entre la multitud, y me preguntó en la
calle: “Enrique: en un caso análogo, ¿hubieras tenido el valor de
cumplir con tu deber, de ir a confesar tu culpa?”. Yo le respondí que
sí, y repuso: “Dame tu palabra de honor de que así lo harás”. “Te
doy mi palabra, padre mío”.

LAS MAESTRAS
Sábado 17.—Garofi estaba hoy muy atemorizado, esperando un gran
regaño del maestro; pero el profesor no ha ido, y como faltaba
también el suplente, ha venido a dar la clase la señora Cromi, la más
vieja de las maestras, que tiene dos hijas mayores y ha enseñado a
leer y escribir a muchas señoras que ahora van a llevar sus niños a
la escuela Bareti. Hoy estaba triste, porque tenía un hijo enfermo.
Apenas la vieron, empezaron a hacer gran ruido. Pero ella, con voz
pausada y serena, dijo: “Respetad mis canas; yo casi no soy ya una
maestra, sino una madre”; y entonces ninguno se atrevió a hablar
más, ni aun aquel cara de bronce de Franti, que se contentó con
hacerle burla sin que lo viera. A la clase de la señora Cromi
mandaron a la señora Delcato, maestra de mi hermano, y al puesto
de ésta a la que llaman “la monjita”, porque va siempre vestida de
obscuro, con un delantal negro; su cara es pequeña y blanca, sus
cabellos siempre peinados, los ojos muy claros y la voz tan gangosa,
que parece está murmurando oraciones. “Y es cosa que no se
comprende—dice mi madre—: tan suave y tan tímida, con aquel
hilito de voz siempre igual, que apenas suena, sin gritar y sin
incomodarse nunca, y, sin embargo, los niños están tan quietos, que
no se les oye, y hasta los más atrevidos inclinan la cabeza en cuanto
les amenaza con el dedo; parece una iglesia su escuela, y por eso
también la llaman la monjita”. Pero hay otra que me gusta mucho: la
maestra de primera enseñanza elemental, número 3; una joven con
la cara sonrosada, que tiene dos lunares muy graciosos en las
mejillas, y que lleva una pluma encarnada en el sombrero y una
crucecita amarilla colgada del cuello. Siempre está alegre, y alegre
también tiene su clase; sonríe, y cuando grita con aquella voz
argentina, parece que canta; pega con la regla en la mesa y da
palmadas para imponer silencio; después, cuando salen, corre como
una niña detrás de unos y de otros, para ponerlos en fila; y a éste le
tira del babero, al otro le abrocha el abrigo para que no se resfríe;
los sigue hasta la calle para que no alboroten; suplica a los padres
que no les castiguen en casa; lleva pastillas a los que tienen tos;
presta su manguito a los que tienen frío, y está continuamente
atormentada por los más pequeños, que le hacen caricias y le piden
besos, tirándole del velo y del vestido; pero ella se deja acariciar y
los besa a todos riendo, y todos los días vuelve a casa despeinada y
ronca, jadeante y tan contenta, con sus graciosos lunares y su
pluma colorada. Es también maestra de dibujo de las niñas, y
sostiene con su trabajo a su madre y a su hermano.

EN CASA DEL HERIDO


Domingo 18.—Con la maestra de la pluma encarnada está el
nietecillo del viejo empleado, que fué herido en un ojo por la bola de
nieve de Garofi; lo hemos visto hoy en casa de su tío, que lo
considera como un hijo. Había concluido de escribir el cuento
mensual para la semana próxima, “El pequeño escribiente
florentino”, que el maestro me dió a copiar, y me dijo mi padre:
“Vamos a subir al cuarto piso a ver cómo está de su ojo aquel
señor”. Hemos encontrado en una habitación casi obscura, donde
estaba el viejo en la cama, recostado, con muchos almohadones
detrás de la espalda; a la cabecera estaba sentada su mujer, y a un
lado el nietecillo, sin hacer nada. El viejo tenía el ojo vendado. Se
alegró mucho de ver a mi padre; le hizo sentar y le dijo que estaba
mejor, y que no sólo no perdería el ojo, sino que dentro de pocos
días estaría curado. “Fué una desgracia—añadió—; siento el mal rato
que debió pasar aquel pobre muchacho”. Después nos ha hablado
del médico, que debía venir entonces a curarle. Precisamente en
aquel momento sonó la campanilla. “Será el médico”, dijo la señora.
Se abre la puerta... ¡y qué veo! Garofi, con su capote largo, de pie
en el umbral, con la cabeza baja y sin atreverse a entrar. “¿Quién
es?”, pregunta el enfermo. “Es el muchacho que tiró la bola...”, dice
mi padre. El viejo entonces exclamó: “¡Oh, pobre niño! Ven acá; has
venido a preguntar cómo está el herido, ¿no es verdad? Estoy mejor,
tranquilízate; estoy mejor, casi curado. Acércate”. Garofi, cada vez
más cortado, se acercó a la cama, esforzándose por no llorar, y el
viejo lo acarició, pero sin poder hablar tampoco. “Gracias—le dijo al
fin el viejo—; ve, pues, a decir a tus padres que todo va bien, que
no se preocupen ya de esto”. Pero Garofi no se movía; parecía que
tenía que decir algo y no se atrevía. “¿Qué tienes que decirme: qué
quieres?”. “Yo... nada”. “Bien, hombre, adiós; hasta la vista; vete,
pues, con el corazón tranquilo”. Garofi fué hasta la puerta; pero allí
se volvió hacia el nietecillo, que lo seguía y lo miraba con curiosidad.
De pronto sacó de debajo del capote un objeto; se lo dió al
muchacho, diciéndole de prisa: “Es para ti”. Y se fué como un
relámpago. El niño enseñó el objeto a su abuelo; vimos que encima
había un letrero que decía: “Te regalo esto”. Lo miramos, lanzamos
una exclamación de sorpresa. Lo que el pobre Garofi había llevado
era el famoso álbum de la colección de sellos; la colección de la que
hablaba siempre, sobre la cual venía fundando tantas esperanzas, y
que tanto trabajo le había costado reunir: era su tesoro. ¡Pobre niño!
¡La mitad de su sangre regalaba a cambio del perdón!
EL PEQUEÑO ESCRIBIENTE FLORENTINO
(CUENTO MENSUAL)

Estaba en la cuarta clase elemental. Era un gracioso florentino de


doce años, de cabellos rubios y tez blanca, hijo mayor de cierto
empleado de ferrocarriles que, teniendo mucha familia y poco
sueldo, vivía con suma estrechez. Su padre lo quería mucho, y era
bueno e indulgente con él; indulgente en todo, menos en lo que se
refería a la escuela: en esto era muy exigente y se revestía de
bastante severidad, porque el hijo debía ponerse pronto en
disposición de obtener otro empleo para ayudar a sostener a la
familia; y para valer algo pronto, necesitaba trabajar mucho en poco
tiempo; y aunque el muchacho era aplicado, el padre le exhortaba
siempre a estudiar. Era ya de avanzada edad el padre, y el excesivo
trabajo le había también envejecido prematuramente. Con efecto,
para proveer a las necesidades de la familia, además del mucho
trabajo que tenía en su destino, se buscaba a la vez aquí y allá
trabajos extraordinarios de copista, y se pasaba sin descansar en su
mesa buena parte de la noche. Últimamente, de cierta casa editorial
que publicaba libros y periódicos, había recibido el encargo de
escribir en las fajas el nombre y la dirección de los subscriptores, y
ganaba tres liras por cada quinientas de aquellas tirillas de papel,
escritas en caracteres grandes y regulares. Pero esta tarea le
cansaba, y se lamentaba de ello a menudo, con la familia, a la hora
de comer. “Estoy perdiendo la vista—decía—; esta ocupación de
noche acaba conmigo”. El hijo le dijo un día: “Papá, déjame trabajar
en tu lugar; tú sabes que escribo regular, tanto como tú”. Pero el
padre respondió: “No, hijo, no; tú debes estudiar; tu escuela es cosa
mucho más importante que mis fajas; tendría remordimiento si te
privara del estudio una hora; lo agradezco, pero no quiero; y no me
hables más de ello”.

El hijo sabía que con su padre era inútil insistir en aquellas cosas, y
no insistió. Pero he aquí lo que hizo. Sabía que a las doce en punto
dejaba su padre de escribir y salía del despacho para la alcoba.
Alguna vez lo había oído: en cuanto el reloj daba las doce, sentía
inmediatamente el rumor de la silla que se movía y el lento paso de
su padre. Una noche esperó a que estuviese ya en la cama, se vistió
sin hacer ruido, anduvo a tientas por el cuarto, encendió el quinqué
de petróleo, se sentó a la mesa del despacho, donde había un
montón de fajas blancas y la indicación de las señas de los
subscriptores, y empezó a escribir, imitando todo lo que pudo la letra
de su padre. Y escribía contento, con gusto, aunque con miedo; las
fajas escritas aumentaban, y de vez en cuando dejaba la pluma para
frotarse las manos; después continuaba con más alegría, atento el
oído y sonriente. Escribió ciento sesenta: ¡cerca de una peseta!
Entonces paró; dejó la pluma donde estaba, apagó la luz y se volvió
a la cama de puntillas.
Aquel día, a las doce, el padre se sentó a la mesa de buen humor.
No había advertido nada. Hacía aquel trabajo mecánicamente,
contando las horas, pensando en otra cosa y no contando las fajas
escritas hasta el día siguiente. Sentados a la mesa con buen humor,
y poniendo la mano en el hombro de su hijo: “¡Eh, Julio—le dijo—
mira qué buen trabajador es tu padre! En dos horas ha trabajado
anoche un tercio más de lo que acostumbra. La mano aún está ágil,
y los ojos cumplen todavía con su deber”. Julio, contento, mudo,
decía entre sí: “¡Pobre padre! Además de la ganancia, le he
proporcionado también esta satisfacción: la de creerse rejuvenecido:
¡Ánimo, pues!”.

Alentado con el éxito, la noche siguiente, en cuanto dieron las doce,


se levantó otra vez y se puso a trabajar. Y lo mismo siguió haciendo
varias noches. Su padre seguía también sin advertir nada. Sólo una
vez, cenando, se le ocurrió esta observación: “¡Es raro; cuánto
petróleo se gasta en esta casa de algún tiempo a esta parte!”. Julio
se estremeció; pero la conversación no pasó de allí, y el trabajo
nocturno siguió adelante.

Lo que ocurrió fué que, interrumpiéndose así el sueño todas las


noches, Julio no descansaba bastante; por la mañana se levantaba
rendido aún, y por la noche, al estudiar, le costaba trabajo tener los
ojos abiertos. Una noche, por la primera vez en su vida, se quedó
dormido sobre los apuntes. “¡Vamos, vamos!—le gritó su padre,
dando una palmada—. ¡Al trabajo!”. Se asustó y volvió a ponerse a
estudiar. Pero la noche y los días siguientes continuaba la cosa lo
mismo, y aun peor: daba cabezadas sobre los libros, se despertaba
más tarde de lo acostumbrado, estudiaba las lecciones con violencia
y parecía que le disgustaba el estudio. Su padre empezó a
observarlo; después se preocupó de ello, y al fin tuvo que
reprenderle. Nunca lo había tenido que hacer por esta causa. “Julio
—le dijo una mañana—, tú te descuidas mucho, no eres ya el de
otras veces. No quiero esto. Todas las esperanzas de la familia se
cifraban en ti. Estoy muy descontento. ¿Comprendes?”. A este único
regaño, el verdaderamente severo que había recibido, el muchacho
se turbó. “Sí, cierto—murmuró entre dientes—; así no puedo
continuar; es menester que el engaño concluya”. Pero la noche de
aquel mismo día, en la comida, exclamó con alegría su padre:
“¡Sabed que en este mes he ganado en las fajas treinta y dos liras
más que el mes pasado!”. Y diciendo esto sacó a la mesa un
cartucho de dulces que había comprado para celebrar con sus hijos
la ganancia extraordinaria, que todos acogieron con júbilo. Entonces
Julio cobró ánimo y pensó para sí: “¡No, pobre padre, no cesaré de
engañarte; haré mayores esfuerzos para estudiar mucho de día,
pero continuaré trabajando de noche para ti y para todos los
demás!”. Y añadió el padre: “Treinta y dos liras...! Estoy contento...
Pero hay otra cosa—y señaló a Julio—que me disgusta”. Y Julio
recibió la reconvención en silencio, conteniendo dos lágrimas que
querían salir, pero sintiendo al mismo tiempo en el corazón cierta
dulzura. Y siguió trabajando con ahinco; pero acumulándose un
trabajo a otro, le era cada vez más difícil resistir. La cosa duró así
dos meses. El padre continuaba reprendiendo al muchacho y
mirándole cada vez más enojado. Un día fué a preguntar por él al
maestro, y éste le dijo: “Sí, cumple, porque tiene buena inteligencia;
pero no está tan aplicado como antes. Se duerme, bosteza, está
distraído, sus apuntes los hace cortos, de prisa, con mala letra: él
podría hacer más, pero mucho más”. Aquella noche el padre llamó al
hijo aparte y le hizo reconvenciones más severas que las que hasta
entonces le había hecho. “Julio, tú ves que yo trabajo, que yo gasto
mi vida por la familia. Tú no me secundas, tú no tienes lástima de
mí, ni de tus hermanos, ni aun de tu madre”. “¡Ah, no, no diga usted
eso, padre mío”, gritó el niño ahogado en llanto, y abrió la boca para
confesarlo todo. Pero su padre le interrumpió diciendo: “Tú conoces
las condiciones de la familia; sabes que hay necesidad de hacer
mucho, de sacrificarnos todos. Yo mismo debía doblar mi trabajo. Yo
contaba estos meses últimos con una gratificación de cien liras en el
ferrocarril, y he sabido esta mañana que ya no la tendré”. Ante esta
noticia, Julio retuvo en seguida la confesión que estaba para
escaparse de sus labios, y se dijo resueltamente a sí mismo: “No,
padre mío, no te diré nada; guardaré el secreto para poder trabajar
por ti; del dolor que te causo te compenso de este modo; en la
escuela estudiaré siempre lo bastante para salir del paso; lo que
importa es ayudar para ganar la vida y aligerarte de la ocupación
que te mata”. Siguió adelante, transcurrieron otros dos meses de
tarea nocturna y de pereza de día, de esfuerzos desesperados del
hijo y de amargas reflexiones del padre. Pero lo peor era que éste se
iba enfriando poco a poco con el niño, y no le hablaba sino raras
veces, como si fuera un hijo desnaturalizado del que nada hubiese
que esperar, y casi huía de encontrar su mirada. Julio lo advertía,
sufría en silencio, y cuando su padre volvía la espalda, le mandaba
un beso furtivamente, volviendo la cara con sentimiento de ternura
compasiva y triste; mientras tanto el dolor y la fatiga lo demacraban
y le hacían perder el color, obligándole a descuidarse cada vez más
en sus estudios. Comprendía perfectamente que todo concluiría en
un momento la noche que dijera: “Hoy no me levanto”; pero al dar
las doce, en el instante en que debía confirmar enérgicamente su
propósito, sentía remordimiento, le parecía que quedándose en la
cama faltaba a su deber, que robaba una peseta a su padre y a su
familia; y se levantaba pensando que cualquier noche que su padre
se despertara y lo sorprendiera, o que por casualidad se enterara
contando las fajas dos veces, entonces terminaría naturalmente
todo, sin un acto de su voluntad, para el cual no se sentía con
ánimos. Y así continuó la cosa.

Pero una tarde, en la comida, el padre pronuncia una palabra que


fué decisiva para él. Su madre lo miró, y pareciéndole que estaba
más echado a perder y más pálido que de costumbre, le dijo: “Julio,
tú estás malo”. Y después, volviéndose con ansiedad al padre: “Julio
está malo; ¡mira qué pálido está! Julio mío, ¿qué tienes?”. El padre le
miró de reojo y le dijo: “La mala conciencia hace que tenga mala
salud. No estaba así cuando era estudiante aplicado e hijo cariñoso”.
“Pero está malo”, exclamó la mamá. “¡Ya no me importa!”, respondió
el padre.

Aquella palabra le hizo el efecto de una puñalada en el corazón al


pobre muchacho. ¡Ah!, ya no le importaba su salud a su padre, que
en otro tiempo temblaba de oírlo toser solamente. Ya no lo quería,
pues; había muerto en el corazón de su padre. “¡Ah, no, padre mío!
—dijo entre sí con el corazón angustiado—; ahora acaba esto de
veras; no puedo vivir sin tu cariño, lo quiero todo; todo te lo diré, no
te engañaré más y estudiaré, como antes, suceda lo que suceda,
para que tú vuelvas a quererme, padre mío. ¡Oh, estoy decidido en
mi resolución!”.

Sin embargo, aquella noche se levantó todavía más bien por fuerza
de la costumbre que por otra causa, y cuando se levantó, quiso ir a
saludar, a volver a ver por algunos minutos, en el silencio de la
noche, por última vez, aquel cuarto donde había trabajado tanto
secretamente, con el corazón lleno de satisfacción y de ternura. Y
cuando se volvió a encontrar en la mesa, con la luz encendida, y vió
aquellas fajas blancas sobre las cuales no iba ya a escribir más
aquellos nombres de ciudades y de personas que se sabía de
memoria, le entró una gran tristeza e involuntariamente cogió la
pluma para reanudar el trabajo acostumbrado. Pero al extender la
mano tocó un libro y éste se cayó. Se quedó helado. ¡Si su padre se
despertaba...!. Cierto que no le habría sorprendido cometiendo
ninguna mala acción, y que él mismo había decidido contárselo todo;
sin embargo..., el oír acercarse aquellos pasos en la obscuridad, el
ser sorprendido a aquella hora con aquel silencio, el que su madre
se hubiese despertado y asustado, al pensar que por lo pronto su
padre hubiera experimentado una humillación en su presencia,
descubriéndolo todo... Todo esto casi lo aterraba. Aguzó el oído,
suspendiendo la respiración... No oyó nada. Escuchó por la cerradura
de la puerta que tenía detrás: nada. Toda la casa dormía. Su padre
no había oído. Se tranquilizó y volvió a escribir. Las fajas se
amontonaban unas sobre otras. Oyó el paso cadencioso de la
guardia municipal en la desierta calle; luego, ruido de carruajes, que
cesó al cabo de un rato; después, pasado algún tiempo, el rumor de
una fila de carros que pasaron lentamente; más tarde, silencio
profundo, interrumpido de vez en cuando por el ladrido de algún
perro. Y siguió escribiendo. Entretanto su padre estaba detrás de él;
se había levantado cuando se cayó el libro y esperó un rato; el ruido
de los carros había cubierto el rumor de sus pasos y el ligero chirrido
de las hojas de la puerta, y estaba allí, con su blanca cabeza sobre
la negra cabecita de Julio. Había visto correr la pluma sobre las
fajas, y en un momento todo lo había olvidado; lo había recordado y
comprendido todo, y un arrepentimiento desesperado, una ternura
inmensa había invadido su alma, y lo tenía clavado allí, detrás de su
hijo. De repente dió Julio un grito agudísimo: dos brazos convulsos
le habían cogido la cabeza. “¡Oh, padre mío, perdóname!”, gritó,
reconociendo a su padre llorando. “¡Perdóname tú a mí—respondió
el padre sollozando y cubriendo su frente de besos—. Lo he
comprendido todo, todo lo sé; yo soy quien te pide perdón, santa
criatura mía. ¡Ven, ven conmigo!”. Y le empujó, más bien que lo
llevó, a la cama de su madre, despierta, y arrojándolo entre sus
brazos, le dijo: “¡Besa a nuestro hijo, a este ángel, que desde hace
tres meses no duerme y trabaja por mí, y yo he contristado su
corazón mientras él nos ganaba el pan!”. La madre lo recogió y
apretó contra su pecho, sin poder articular una palabra, y después
dijo: “A dormir en seguida, hijo mío; ve a dormir y a descansar.
¡Llévalo a la cama...!”. El padre lo cogió en brazos, lo llevó a su
cuarto, lo metió en la cama, siempre jadeante y acariciándolo, y le
arregló las almohadas y la colcha. “Gracias, padre—repetía el hijo—,
gracias; pero ahora vete tú a la cama; ya estoy contento; vete a la
cama, papá”. Pero su padre quería verlo dormido, y sentado a la
cabecera de su cama, le tomó la mano y dijo: “¡Duerme, duerme,
hijo mío!”. Y Julio, rendido, se durmió por fin, y durmió muchas
horas, gozando por primera vez, después de muchos meses, de un
sueño tranquilo, alegrado por rientes ensueños; y cuando abrió los
ojos, después de un rato de alumbrar ya el sol, sintió primero y vió
después cerca de su pecho, apoyada sobre la orilla de la cama, la
blanca cabeza de su padre, que había pasado así la noche y dormía
aún, con la frente inclinada al lado de su corazón.
LA VOLUNTAD
Miércoles 28.—Hay en mi clase un tal Estardo, que sería capaz de
hacer lo que hizo el pequeño florentino. Esta mañana ocurrieron dos
acontecimientos en la escuela: Garofi, loco de alegría porque le
habían devuelto su álbum con el aumento de tres sellos de la
República de Guatemala, que él buscaba hacía tres meses, y
Estardo, que había obtenido la segunda medalla. ¡Estardo, el
primero en la clase después de Deroso! Todos nos admiramos.
¡Quién lo hubiera dicho en octubre, cuando su padre lo llevó a la
escuela metido en aquel gabán verde, y dijo al maestro delante de
todos: “Tenga con él mucha paciencia, porque es muy tardo para
comprender”. Todos al principio le creían un adoquín. Pero él dijo: “O
reviento, o salgo adelante”; y se puso a estudiar con fe, de día y de
noche, en casa, en la escuela y en el paseo, con los dientes
apretados y cerrados los puños, paciente como un buey, terco cual
un mulo, y así, a fuerza de machacar, no haciendo caso de las
bromas y pegando patadas a los revoltosos, ha pasado por delante
de los demás aquel testarudo. No comprendía una palabra de la
Aritmética; llenaba de disparates los apuntes; no acertaba a retener
en su memoria un período, y ahora resuelve problemas, escribe
correctamente y dice las lecciones como un papagayo. Se adivina su
voluntad de hierro cuando se ve su facha; tan grueso, con la cabeza
cuadrada y sin cuello, con las manos cortas y gordas y con aquella
voz áspera. Estudia hasta en las columnas de los periódicos y en los
anuncios de los teatros, y cada vez que junta dos reales se compra
un libro; ha reunido ya así una pequeña biblioteca, y en un
momento de buen humor se le escapó decirme que me llevaría a su
casa para verla. No habla con nadie, con nadie juega y siempre está
allí en su banco, con las manos en las sienes, firme como una roca,
oyendo al maestro. ¡Cuánto debe haber trabajado el pobre Estardo!
El maestro le dijo esta mañana, aunque estaba impaciente y de mal
humor cuando le dió la medalla: “¡Bravo, Estardo; quien trabaja,
vence!”. Pero él no parecía estar enorgullecido; no se sonrió, y
apenas volvió al banco con su medalla, tornó a apoyar las sienes en
los puños y se quedó más inmóvil que antes. Mas lo mejor fué a la
salida, que estaba esperándolo su padre, un sangrador grueso y
tosco como él, una facha con voz de trueno. Él no se esperaba
aquella medalla y no lo quería creer; fué menester que el maestro lo
asegurase, y entonces se echó a reír de gusto, y dió una palmada al
hijo en la cabeza, diciéndole en alta voz: “¡Bravo, bien, testarudo
mío!”. Y lo miraba atónito, sonriendo. Y todos los muchachos que
estaban alrededor se sonreían también, excepto Estardo. Éste
rumiaba ya en su cabeza la lección del día siguiente.

GRATITUD
Sábado 31.—“Tu compañero Estardo no se quejará nunca de su
maestro, estoy seguro; el profesor tiene mal genio y se impacienta,
tú lo dices como si fuese una cosa rara. Piensa cuántas veces te
impacientas tú; ¿y con quién? Con tu padre y con tu madre, con los
cuales tu impaciencia es un delito. ¡Bastante razón tiene tu maestro
para impacientarse alguna vez! Piensa en los años que hace que
lidia con muchachos, y que si hay muchos cariñosos y agradables,
encuentra también muchos ingratos que abusan de su bondad y
desconocen sus cuidados, y que, después de todo, entre tantos, son
más las amarguras que las satisfacciones. Piensa que el hombre más
santo de la tierra, puesto en su lugar, se dejaría llevar de la ira
alguna vez. Y después, si supieses cuántas veces el maestro va
enfermo a dar su clase, sólo porque no tiene una enfermedad
bastante grave para dispensarle de la asistencia a la escuela, y que
se impacienta porque sufre y le produce sentimiento ver que los
demás no lo advierten o abusan de él. Respeta y quiere a tu
maestro, hijo mío. Quiérelo porque tu padre lo respeta, porque
consagra su vida al bien de tantos niños que luego lo olvidan;
quiérelo porque te abre e ilumina la inteligencia y te educa el
corazón; porque un día, cuando seas hombre y no estemos ya en el
mundo ni él ni yo, su imagen se presentará a veces en tu mente al
lado de la mía, y entonces te acordarás de ciertas expresiones de
dolor y de cansancio de su cara apacible de hombre honrado, en la
cual ahora no te fijas; lo recordarás y te dará pena, aun después de
treinta años, y te avergonzarás; sentirás tristeza de no haberlo
querido bastante, de haberte portado tan mal con él. Quiere a tu
maestro, porque pertenece a esa gran familia de cincuenta mil
profesores elementales esparcidos por toda Italia, y que son como
los padres intelectuales de millones de muchachos que contigo
crecen; trabajadores mal comprendidos y mal recompensados, que
preparan para nuestra patria una generación mejor que la presente.
No estaré satisfecho de tu cariño hacia mí si no lo tienes igualmente
para todos los que te hacen bien, entre los cuales tu maestro es el
primero después de tu padre. Quiérelo como querrías a un hermano
mío; quiérelo cuando te acaricie y cuando te regañe; cuando es
justo contigo y cuando te parezca injusto; quiérelo cuando esté
alegre y afable, y quiérelo más aún cuando lo veas triste. Quiérelo
siempre. Pronuncia perpetuamente con respeto el nombre de
maestro, que, después del de padre, es el nombre más dulce que
puede dar un hombre a un semejante suyo.—Tu padre”.

You might also like