0% found this document useful (0 votes)
2 views

Programming With Unicon 2nd Ed Clinton Jeffery Shamim Mohamed download

The document is a draft manuscript for the second edition of 'Programming With Unicon' by Clinton Jeffery and others, dated December 16, 2018. It covers various topics related to the Unicon programming language, including core concepts, structures, string processing, advanced features, and system interface. Additionally, it provides links to other programming-related ebooks available for download.

Uploaded by

cristabapen
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
0% found this document useful (0 votes)
2 views

Programming With Unicon 2nd Ed Clinton Jeffery Shamim Mohamed download

The document is a draft manuscript for the second edition of 'Programming With Unicon' by Clinton Jeffery and others, dated December 16, 2018. It covers various topics related to the Unicon programming language, including core concepts, structures, string processing, advanced features, and system interface. Additionally, it provides links to other programming-related ebooks available for download.

Uploaded by

cristabapen
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/ 91

Programming With Unicon 2nd Ed Clinton Jeffery

Shamim Mohamed download

https://ebookbell.com/product/programming-with-unicon-2nd-ed-
clinton-jeffery-shamim-mohamed-10009244

Explore and download more ebooks at ebookbell.com


Here are some recommended products that we believe you will be
interested in. You can click the link to download.

Programming With Openscad A Beginners Guide To Coding 3dprintable


Objects 1st Edition Justin Gohde

https://ebookbell.com/product/programming-with-openscad-a-beginners-
guide-to-coding-3dprintable-objects-1st-edition-justin-gohde-46410140

Programming With Python And Its Applications To Physical Systems M


Shubhakanta Singh

https://ebookbell.com/product/programming-with-python-and-its-
applications-to-physical-systems-m-shubhakanta-singh-50637024

Programming With Microsoft Visual Basic 2012 6th Edition Zak

https://ebookbell.com/product/programming-with-microsoft-visual-
basic-2012-6th-edition-zak-55132386

Programming With Microsoft Visual Basic 2010 Vbnet Programming 5th


Edition Zak

https://ebookbell.com/product/programming-with-microsoft-visual-
basic-2010-vbnet-programming-5th-edition-zak-55139980
Programming With Java Edet Theophilus

https://ebookbell.com/product/programming-with-java-edet-
theophilus-55229942

Programming With Rust Donis Marshall

https://ebookbell.com/product/programming-with-rust-donis-
marshall-55709862

Programming With C20 Concepts Coroutines Ranges And More Updated 2024
2nd Edition Andreas Fertig

https://ebookbell.com/product/programming-with-c20-concepts-
coroutines-ranges-and-more-updated-2024-2nd-edition-andreas-
fertig-56812174

Programming With Tensorflow Kolla Bhanu Prakash G R


Kanagachidambaresan

https://ebookbell.com/product/programming-with-tensorflow-kolla-bhanu-
prakash-g-r-kanagachidambaresan-22736720

Programming With Quartz 2d And Pdf Graphics In Mac Os X 1st Edition


David Gelphman

https://ebookbell.com/product/programming-with-quartz-2d-and-pdf-
graphics-in-mac-os-x-1st-edition-david-gelphman-2382698
Programming with Unicon

2nd edition

Clinton Jeery
Shamim Mohamed
Jafar Al Gharaibeh
Ray Pereda
Robert Parlett
Copyright c 1999-2018 Clinton Jeery, Shamim Mohamed, Jafar Al Gharaibeh, Ray
Pereda, and Robert Parlett

This is a draft manuscript dated December 16, 2018. Send comments and errata to
jemail protected].

This document was prepared using LATEX.


Contents

Preface to the Second Edition vii

I Core Unicon 5
1 Programs and Expressions 7
1.1 Your First Unicon Program . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2 Command Line Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3 Expressions and Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.4 Numeric Computation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.5 Strings and Csets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.6 Goal-directed Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.7 Fallible Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.8 Generators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.9 Iteration and Control Structures . . . . . . . . . . . . . . . . . . . . . . . . 20
1.10 Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

2 Structures 29
2.1 Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.2 Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.3 Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.4 Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.5 Using Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

3 String Processing 41
3.1 The String and Cset Types . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.1.1 String Indexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.1.2 Character Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.1.3 Character Escapes . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.2 String Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.2.1 String Scanning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

i
ii CONTENTS

3.3 Pattern Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49


3.3.1 Regular Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.3.2 Pattern Composition . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.3.3 Pattern Match Operators . . . . . . . . . . . . . . . . . . . . . . . . 51
3.3.4 Scopes of Unevaluated Variables . . . . . . . . . . . . . . . . . . . . 51
3.4 String Scanning and Pattern Matching Miscellany . . . . . . . . . . . . . . 51
3.4.1 Grep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.5 Grammars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

4 Advanced Language Features 57


4.1 Limiting or Negating an Expression . . . . . . . . . . . . . . . . . . . . . . 57
4.2 List Structures and Parameter Lists . . . . . . . . . . . . . . . . . . . . . . 58
4.3 Co-expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
4.4 User-Dened Control Structures . . . . . . . . . . . . . . . . . . . . . . . . 60
4.5 Parallel Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
4.6 Coroutines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
4.7 Permutations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.8 Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

5 The System Interface 69


5.1 The Role of the System Interface . . . . . . . . . . . . . . . . . . . . . . . 69
5.2 Files and Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
5.3 Programs and Process Control . . . . . . . . . . . . . . . . . . . . . . . . . 73
5.4 Networking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
5.5 Messaging Facilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
5.6 Tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
5.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90

6 Databases 91
6.1 Language Support for Databases . . . . . . . . . . . . . . . . . . . . . . . 91
6.2 Memory-based Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
6.3 DBM Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
6.4 SQL Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
6.5 Tips and Tricks for SQL Database Applications . . . . . . . . . . . . . . . 100
6.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102

7 Graphics 103
7.1 2D Graphics Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
7.2 Graphics Contexts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
7.3 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
7.4 Colors and Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
CONTENTS iii

7.5 Images, Palettes, and Patterns . . . . . . . . . . . . . . . . . . . . . . . . . 111


7.6 3D Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
7.7 Textures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
7.8 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

8 Threads 135
8.1 Threads and Co-Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . 136
8.2 First Look at Unicon Threads . . . . . . . . . . . . . . . . . . . . . . . . . 136
8.3 Thread Safety . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
8.4 Thread Synchronization . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
8.5 Thread Communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
8.6 Practical examples using threads and messages . . . . . . . . . . . . . . . . 161
8.6.1 Disk space usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
8.6.2 More suggestions for parallel processing . . . . . . . . . . . . . . . . 168
8.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168

9 Execution Monitoring 171


9.1 Monitor Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
9.2 Obtaining Events Using evinit . . . . . . . . . . . . . . . . . . . . . . . . . 179
9.3 Instrumentation in the Icon Interpreter . . . . . . . . . . . . . . . . . . . . 181
9.4 Articial Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
9.5 Monitoring Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
9.6 Some Useful Library Procedures . . . . . . . . . . . . . . . . . . . . . . . . 186
9.7 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186

II Object-oriented Software Development 187


10 Objects and Classes 189
10.1 Objects in Programming Languages . . . . . . . . . . . . . . . . . . . . . . 189
10.2 Objects in Program Design . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
10.3 Classes and Class Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . 193
10.4 Declaring Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
10.5 Object Instances and Initially Sections . . . . . . . . . . . . . . . . . . . . 196
10.6 Object Invocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
10.7 Comparing Records and Classes . . . . . . . . . . . . . . . . . . . . . . . . 199
10.8 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201

11 Inheritance and Associations 203


11.1 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
11.2 Associations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
iv CONTENTS

11.3 Aggregation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215


11.4 User-dened associations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
11.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219

12 Writing Large Programs 221


12.1 Abstract Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
12.2 Design Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
12.3 Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
12.4 HTML documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
12.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232

13 Use Cases and Supplemental UML Diagrams 235


13.1 Use Cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
13.2 Statechart Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
13.3 Collaboration Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
13.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242

III Example Applications 243


14 CGI Scripts 245
14.1 Introduction to CGI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
14.2 The CGI Execution Environment . . . . . . . . . . . . . . . . . . . . . . . 248
14.3 An Example HTML Form . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
14.4 An Example CGI Script: Echoing the User's Input . . . . . . . . . . . . . 250
14.5 Debugging CGI Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
14.6 Appform: An Online Scholarship Application . . . . . . . . . . . . . . . . 252

15 System and Administration Tools 255


15.1 Searching for Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
15.2 Finding Duplicate Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
15.3 User File Quotas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
15.4 Capturing a Shell Command Session . . . . . . . . . . . . . . . . . . . . . 268
15.5 Filesystem Backups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
15.6 Filtering Email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
15.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279

16 Internet Programs 281


16.1 The Client-Server Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
16.2 An Internet Scorecard Server . . . . . . . . . . . . . . . . . . . . . . . . . . 282
16.3 A Simple Talk Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
16.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
CONTENTS v

17 Genetic Algorithms 293


17.1 What are Genetic Algorithms? . . . . . . . . . . . . . . . . . . . . . . . . . 293
17.2 Operations: Fitness, Crossover, and Mutation . . . . . . . . . . . . . . . . 294
17.3 The GA Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
17.4 ga_eng: a Genetic Algorithm Engine . . . . . . . . . . . . . . . . . . . . . 298
17.5 Color Breeder: a GA Application . . . . . . . . . . . . . . . . . . . . . . . 303
17.6 Picking Colors for Text Displays . . . . . . . . . . . . . . . . . . . . . . . . 305

18 Object-oriented User Interfaces 307


18.1 A Simple Dialog Example . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
18.2 A More Complex Dialog Example . . . . . . . . . . . . . . . . . . . . . . . 310
18.3 Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
18.4 Menu Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
18.5 Other Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
18.5.1 Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
18.5.2 Borders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
18.5.3 Images and icons . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
18.5.4 Scroll bars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
18.5.5 Custom Components . . . . . . . . . . . . . . . . . . . . . . . . . . 328
18.5.6 Tickers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
18.6 Advanced List Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
18.6.1 Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
18.6.2 Popups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
18.6.3 Drag and drop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
18.7 Programming Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
18.8 ivib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
18.9 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360

IV Appendices 361
A Language Reference 363
A.1 Immutable Types: Numbers, Strings, Csets, Patterns . . . . . . . . . . . . 363
A.2 Mutable Types: Containers and Files . . . . . . . . . . . . . . . . . . . . . 365
A.3 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
A.4 Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
A.5 Control Structures and Reserved Words . . . . . . . . . . . . . . . . . . . . 373
A.6 Operators and Built-in Functions . . . . . . . . . . . . . . . . . . . . . . . 377
A.7 Preprocessor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
A.8 Execution Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
vi CONTENTS

B The Icon Program Library 419


B.1 Procedure Library Modules . . . . . . . . . . . . . . . . . . . . . . . . . . 420
B.2 Application Programs, Examples, and Tools . . . . . . . . . . . . . . . . . 461
B.3 Selected IPL Authors and Contributors . . . . . . . . . . . . . . . . . . . . 481

C The Unicon Component Library 483


C.1 GUI Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483

D Dierences between Icon and Unicon 497


D.1 Extensions to Functions and Operators . . . . . . . . . . . . . . . . . . . . 497
D.2 Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497
D.3 System Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497
D.4 Database Facilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498
D.5 Multiple Programs and Execution Monitoring Support . . . . . . . . . . . 498

E Portability Considerations 499


E.1 POSIX extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499
E.2 Microsoft Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504

F Installation 507
F.1 Building on Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507
F.2 Building on OS X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507
F.3 Building on Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507

Bibliography 509
Preface to the Second Edition
This book will raise your level of skill at computer programming, regardless of whether
you are presently a novice or expert. The eld of programming languages is still in its
infancy, and dramatic advances will be made every decade or two until mankind has had
enough time to think about the problems and principles that go into this exciting area of
computing. The Unicon language described in this book is such an advance, incorporating
many elegant ideas not yet found in most contemporary languages.
Unicon is an object-oriented, goal-directed programming language based on the Icon
programming language. Unicon can be pronounced however you wish; we pronounce it
variably depending on mood, whim, or situation; the most frequent pronunciation rhymes
with lexicon.
For Icon programmers this work serves as a companion book that documents material
such as the Icon Program Library, a valuable resource that is underutilized. Don't be
surprised by language changes: the book presents many new facilities that were added to
Icon to make Unicon and gives examples from new application areas to which Unicon is
well suited. For people new to Icon and Unicon, this book is an exciting guide to a powerful
language.
It is with sweet irony that we call this book the 2nd Edition, since the rst edition
was never formally published but instead existed solely as an online document, although
laser-printed hard copies could be requested. A lot has happened to Unicon since the rst
edition of this book, which culminated in 2004. This 2nd Edition catches readers up
with things like concurrent threads and vastly improved 3D graphics facilities. Along the
way, the games chapter and parts of the internet programming chapter got spun o into a
separate work, the so-called Manual of Puissant Skill at Game Programming.

Organization of This Book

This book consists of four parts. The rst part, Chapters 1-8, presents the core of the
Unicon language, much of which comes from Icon. These early chapters start with simple
expressions, progress through data structures and string processing, and include advanced
programming topics and the input/output capabilities of Unicon's portable system inter-
face. Part two, in Chapters 9-12, describes object-oriented development as a whole and

vii
viii PREFACE TO THE SECOND EDITION

presents Unicon's object-oriented facilities in the context of object-oriented design. Object-


oriented programming in Unicon corresponds closely to object-oriented design diagrams in
the Unied Modeling Language, UML. Some of the most interesting parts of the book are
in part three; Chapters 13-18 provide example programs that use Unicon in a wide range
of application areas. Part four consists of essential reference material presented in several
Appendixes.

Acknowledgments

Thanks to the Icon Project for creating a most excellent language. Thanks especially to
those unsung heroes, the university students and Internet volunteers who implemented the
language and its program library over a period of many years. Icon contributors can be
divided into epochs. In the epoch leading up to the rst edition of this book, we were
inspired by contributions from Gregg Townsend, Darren Merrill, Mary Cameron, Jon Lipp,
Anthony Jones, Richard Hatch, Federico Balbi, Todd Proebsting, Steve Lumos and Naomi
Martinez. In the epoch since the rst edition of this book, the Unicon Project owes a debt
of gratitude to Ziad al Sharif, Hani bani Salameh, Jafar Al Gharaibeh, Mike Wilder, and
Sudarshan Gaikaiwari.
The most impressive contributors are those whose inuence on Icon has spanned across
epochs, such as Ralph Griswold, Steve Wampler, Bob Alexander, Ken Walker, Phillip
Thomas, and Kostas Oikonomou. We revere you folks! Steve Wampler deserves extra
thanks for serving as the technical reviewer for the rst edition of this book. Phillip
Thomas and Kostas Oikonomou have provided extensive support and assistance that goes
way beyond the call of duty; in many ways this is their book.
This manuscript received critical improvements and corrections from many additional
technical reviewers, including, David A. Gamey, Craig S. Kaplan, David Feustel, David
Slate, Frank Lhota, Art Eschenlauer, Wendell Turner, Dennis Darland, and Nolan Clayton.
The authors wish to acknowledge generous support from the National Library of
Medicine and AT&T Bell Labs Research. This work was also supported in part by the
National Science Foundation under grants CDA-9633299, EIA-0220590 and EIA-9810732,
and the Alliance for Minority Participation.
Clinton Jeery
Shamim Mohamed
Jafar al Gharaibeh
Ray Pereda
Robert Parlett
Introduction
Software development requires thinking about several dimensions simultaneously. For large
programs, writing the actual computer instructions is not as dicult as guring out the
details of what the computer is supposed to do. After analyzing what is needed, program
design brings together the data structures, algorithms, objects, and interactions that ac-
complish the required tasks. Despite the importance of analysis and design, programming
is still the central act of software development for several reasons. The weak form of the
Sapir-Whorf hypothesis suggests that the programming language we use steers and guides
the way we think about software, so it aects our designs. Software designs are mathemat-
ical theorems, while programs are proofs that test those designs. As in other branches of
mathematics, the proofs reign supreme. In addition, a correct design can be foiled by an
inferior implementation.
This book is a guide and reference for an exciting programming language called Unicon
that has something to oer both computer scientists as well as casual programmers. You
will nd explanations of fundamental principles, unique language idioms, and advanced
concepts and examples. Unicon exists within the broader context of software development,
so the book also covers software engineering fundamentals. Writing a correct, working
program is the central task of software engineering. This does not happen automatically
as a result of the software design process. Make no mistake: if you program very much,
the programming language you use is of vital importance. If it weren't, we would still be
programming in machine language.

Prototyping and the Spiral Model of Development

A software prototype is a working subset of a software system. Prototypes help check


software designs and user interfaces, demonstrate key features to customers, or prove the
feasibility of a proposed solution. A prototype may generate customer feedback on missing
functionality, provide insight on how to improve the design, lead to a decision about whether
to go ahead with a project or not, or form a starting point for the algorithms and data
structures that will go into the nal product. Prototyping is done early in the software
development process. It ts naturally into the spiral model of development proposed by
Barry Boehm (1988). Figure I-1 shows the spiral model; time is measured by the distance

1
2 PREFACE TO THE SECOND EDITION

from the center. Analysis, design, coding, and evaluation are repeated to produce a better
product with each iteration. "Prototyping" is the act of coding during those iterations when
the software is not yet fully specied or the program does not yet remotely implement the
required functionality.

Figure I-1 The Spiral Model of Software Development

Tight spirals are better than loose spirals. The more powerful the prototyping tools, the
less time and money spent in early iterations of development. This translates into either
faster time to market, or a higher quality product. Some prototypes are thrown away once
they have served the purpose of clarifying requirements or demonstrating some technique.
This is OK, but in the spiral model some prototypes are gradually enhanced until they
become the nal production system.

Icon: a Very High Level Language for Applications

Icon is a programming language developed at the University of Arizona. Icon generalizes


its developers' experience creating an earlier language, SNOBOL4. Icon embodies seminal
research ideas, but it is also more fun and easier to program than other languages. Most
very high-level languages revel in cryptic syntax, while Icon is not just more powerful, but
often more readable than its competitors. This gain in expressive power without losing
readability is an addicting result of Icon's elegant design.
The current Arizona Icon, version 9.5, is described in The Icon Programming Language,
3rd edition by Ralph and Madge Griswold (1996). Its reference implementation is a virtual
machine interpreter. Icon evolved through many releases over two decades and is far more
capable than it was originally. It is apparently a nished work.

Enter Unicon: More Icon than Icon

The name Unicon refers to the descendant of Icon described in this book and distributed
from www.unicon.org. Unicon is Icon with portable, platform-independent access to hard-
3

ware and software features that have become ubiquitous in modern applications develop-
ment, such as objects, networks, and databases. Unicon is created from the same public
domain source code that Arizona Icon uses, so it has a high degree of compatibility. We
were not free to call it version 10 of the Icon language, since it was not produced or endorsed
by the Icon Project at the University of Arizona.
Just as the name Unicon frees the Icon Project of all responsibility for our eorts, it
frees us from the requirement of backward compatibility. While Unicon is almost entirely
backward compatible with Icon, dropping full compatibility allows us to clear out some
dead wood and more importantly, to make some improvements in the operators that will
benet everyone at the expense of...no one but the compatibility police. This book covers
the features of Icon and Unicon together. A compatibility check list and description of the
dierences between Icon and Unicon are given in Appendix D.

The Programming Languages Food Chain

It is interesting to compare Icon and Unicon with the competition. Mainstream program-
ming languages such as C, C++, and Java, like the assembler languages that were main-
stream before them, are ideal tools for writing all sorts of programs, so long as vast amounts
of programmer time are available. Throwing more programmers at a big project does not
work well, and programmers are getting more expensive while computing resources continue
to become cheaper. These pressures inexorably lead to the use of higher-level languages
and the development of better design and development methods. Such human changes are
incredibly slow compared to technological changes, but they are visibly occurring never-
theless. Today, the most productive programmers are using extra CPU cycles and memory
to reduce the time it takes to develop useful programs.
There is a subcategory of mainstream languages, marketed as rapid application de-
velopment languages, whose stated goals seem to address this phenomenon. Languages
such as Visual Basic or PowerBuilder provide graphical interface builders and integrated
database connectivity, giving productivity increases in the domain of data entry and pre-
sentation. The value added in these products are in their programming environments, not
their languages. The integrated development environments and tools provided with these
languages are to be acclaimed and emulated, but they do not provide productivity gains
that are equally relevant to all application domains. They are only a partial solution to
the needs of complex applications.
Icon is designed to be easier and faster to program than mainstream languages. The
value it adds is in the expressive power of the language itself, in the category of very high
level languages that includes Lisp, APL, Smalltalk, REXX, Perl, Tcl, Python, and Ruby;
there are many others. Very high-level languages can be subdivided into scripting lan-
guages and applications languages. Scripting languages often glue programs together from
disparate sources. They are typically strong in areas such as multilingual interfacing and le
4 PREFACE TO THE SECOND EDITION

system interactions, while suering from weaker expression semantics, typing, scope rules,
and control structures than their applications-oriented cousins. Applications languages
typically originate within a particular application domain and support that domain with
special syntax, control structures, and data types. Since scripting is an application domain,
scripting languages are just one prominent subcategory of very high-level languages.
Icon is an applications language with roots in text processing and linguistics. Icon
programs tend to be more readable than similar programs written in other very high-level
languages, making Icon well-suited to the aims of literate programming. For example,
Icon was used to implement Norman Ramsey's literate programming tool noweb (Ramsey,
1994). Literate programming is the practice of writing programs and their supporting
textual description together in a single document.
Unicon makes the core contributions of Icon useful for a broader range of applications.
This book's many examples illustrate the range of tasks for which Unicon is well suited, and
these examples are the evidence in support of Unicon's existence. Consider using Unicon
when one or more of the following conditions are true. The more conditions that are true,
the more you will benet from Unicon.
• Programmer time must be minimized.
• Maintainable, concise source code is desired.
• The program includes complex data structures or experimental algorithms.
• The program involves a mixture of text processing and analysis, custom graphics,
data manipulation, network or le system operations.
• The program must run on several operating systems and have a nearly identical
graphical user interface with little or no source code dierences.
Unicon is not the last word in programming. You probably should not use Unicon if your
program has one or more of the following requirements:
• The fastest possible performance is needed.
• The program has hard real-time constraints.
• The program must perform low-level or platform-specic interactions with the hard-
ware or operating system.
Programming languages play a key role in software development. The Unicon language is a
very high level object-oriented language with a unique combination of expressive power and
scalable rapid development. In this book, many examples from a wide range of application
areas demonstrate how to apply and combine Unicon's language constructs to solve real-
world problems. It is time to move past the introductions. Prepare to be spoiled by this
language. You may have the same feelings that Europeans felt when they gave up using
Roman numerals and switched to the Hindu-Arabic number system. This multiplication
stu isn't that hard anymore!
Part I
Core Unicon

5
Chapter 1
Programs and Expressions
This chapter presents many of the key features of Unicon, starting with those it has in
common with other popular languages. Detailed instructions show how to compile and run
programs. Soon the examples introduce important ways in which Unicon is dierent from
other languages. These dierences are more than skin deep. If you dig deeply, you can nd
dozens of details where Unicon provides just the right blend of simplicity, exibility, and
power. After this chapter, you will know how to

• edit, compile, and execute Unicon programs


• use the basic types to perform calculations
• identify expressions that can fail, or produce multiple results
• control the ow of execution using conditionals, looping, and procedures

1.1 Your First Unicon Program

This section presents the nuts and bolts of writing and running an Unicon program, after
which you will be able to try the code examples or write your own programs. Before you
can run the examples here or in any subsequent chapter, you must install Unicon on your
system. (See Appendix F for details on downloading and installing Unicon from the Unicon
web site, http://unicon.org.) We are going to be very explicit here, and assume nothing
about your background. If you are an experienced programmer, you will want to skim this
section, and move on to the next section. If you are completely new to programming, have
no fear. Unicon is pretty easy to learn.
All programs consist of commands that use hardware to obtain or present information
to users, and perform calculations that transform information into a more useful form.
To program a computer you write a document containing instructions for the computer to
carry out. In Unicon a list of instructions is called a procedure, and a program is a collection
of one or more procedures. In larger programs, groups of related procedures are organized

7
8 CHAPTER 1. PROGRAMS AND EXPRESSIONS

into classes or packages; these features are presented in Part II of this book. Unicon
programs are text les that may be composed using any text editor. For the purposes
of demonstration this section describes how to use Ui, the program editor and integrated
development tool that comes with Unicon.
It is time to begin. Fire up Ui by typing "ui" from the command line, or launching the
menu item or icon labeled "Unicon," and type:

procedure main()
write("Hello, amigo!")
end

Your screen should look something like Figure 1-1. The large upper area of the window
is the editing region where you type your program code. The lower area of the window is
a status region in which the Ui program displays a message when a command completes
successfully, or when your program has an error. Until you explicitly name your le some-
thing else, a new le has the name noname.icn. The font Ui uses to display source code is
selectable from the Options menu.

Figure 1-1: Writing an Unicon program using the Ui program.


1.1. YOUR FIRST UNICON PROGRAM 9

The list of instructions that form a procedure begins with the word procedure and
ends with the word end. Procedures have names. After writing a list of instructions in
a procedure you may refer to it by name without writing out the list again. The write()
instruction is just such a procedure, only it is already written for you; it is built in to the
language. When you issue a write() instruction, you tell the computer what to write. The
details a procedure uses in carrying out its instructions are given inside the parentheses
following that procedure's name; in this case, "Hello, amigo!" is to be written. When you
see parentheses after a name in the middle of a list of instructions, it is an instruction to
go execute that procedure's instructions. Inside the parentheses there may be zero, one, or
many values supplied to that procedure.
Besides writing your program, there are a lot of menu commands that you can use to
control the details of compiling and executing your program within Ui. For instance, if you
select Run→Run, Ui will do the following things for you.

1. Save the program in a le on disk. All Unicon programs end in .icn; you could name
it anything you wished, using the File→SaveAs command.

2. Compile the Unicon program from human-readable text to (virtual) machine lan-
guage. To do this step manually, you can select the Compile→Make executable
command.

3. Execute the program. This is the main purpose of the Run command. Ui performed
the other steps in order to make this operation possible.

If you type the hello.icn le correctly, the computer should chug and grind its teeth for
awhile, and

Hello, amigo!

should appear in a window on your screen. This ought to be pretty intuitive, since the
instructions included the line

write("Hello, amigo!")

in it. That's how to write to the screen. It's that simple.


The rst procedure to be executed when a program runs is called main(). Every in-
struction listed in the procedure named main() is executed in order, from top to bottom,
after which the program terminates. Use the editor to add the following lines right after
the line write("Hello, amigo") in the previous program:

write("How are you?")


write(7 + 12)

The end result after making your changes should look like this:
10 CHAPTER 1. PROGRAMS AND EXPRESSIONS

procedure main()
write("Hello, amigo!")
write("How are you?")
write(7 + 12)
end

Run the program again. This example shows you what a list of instructions looks like,
as well as how easy it is to tell the computer to do some arithmetic.
Note
It would be ne (but not very useful) to tell the computer to add 7 and 12 without
telling it to write the resulting value. On seeing the instruction

7 + 12

the computer would do the addition, throw the 19 away, and go on.
Add the following line, and run it:

write("7 + 12")

This illustrates what quotes are for. Quoted text is taken literally; without quotes, the
computer tries to simplify (do some arithmetic, or compute the value of what is written),
which might be dicult if the material in question is not an expression!

write(hey you)

makes no sense and is an error. Add this line, and run it:

write(7 + "12")

The 12 in quotes is taken literally as some text, but that text happens to be digits that
comprise a number, so adding it to another number makes perfect sense. The computer
will not have as much success if you ask it to add 7 to amigo. The computer views all
of this in terms of values. A value is a unit of information, such as a number. Anything
enclosed in quotes is a single value. The procedure named write() prints values on your
screen. Operators such as + take values and combine them to produce other values, if it
is possible to do so. The values you give to + had better be numbers! If you try to add
something that doesn't make sense, the program will stop running at that point, and print
an error message.
By now you must have the impression that writing things on your screen is pretty easy.
Reading the keyboard is just as easy, as illustrated by the following program:

procedure main()
write("Type a line ending with <ENTER>:")
write("The line you typed was" , read())
end
1.1. YOUR FIRST UNICON PROGRAM 11

Run the program to see what it does. The procedure named read() is used to get what
the user types. It is built in to the language. The read() instruction needs no directions
to do its business, so nothing is inside the parentheses. When the program is run, read()
grabs a line from the keyboard, turns it into a value, and produces that value for use in
the program, in this case for the enclosing write() instruction.
The write() instruction is happy to print out more than one value on a line, separated
by commas. When you run the program, the "the line you typed was" part does not get
printed until after you type the line for read() and that instruction completes. The write()
instruction must have all of its directions (the values inside the parentheses) before it can
go about its business.
Now let's try some variations. Can you guess what the following line will print?

write("this line says " , "read()")

The read() procedure is never executed because it is quoted! Quotes say "take these
letters literally, not as an equation or instruction to evaluate." How about:

write("this line says , read()")

Here the quotes enclose one big value, which is printed, comma and all. The directions one
gives to a procedure are parameters ; when you give a procedure more than one parameter,
separated by commas, you are giving it a parameter list. For example,

write("this value ", "and this one")

Compile and run the following strange-looking program. What do you think it does?

procedure main()
while write( "" ˜== read() )
end

This program copies the lines you type until you type an empty line by pressing Enter
without typing any characters rst. The "" are used just as usual. They direct the program
to take whatever is quoted literally, and this time it means literally nothing - an empty line.
The operator ˜== stands for "not equals". It compares the value on its left to the value on
its right, and if they are not equal, it produces the value on the right side; if they are equal,
it fails - that is, the not equals operator produces no value. If you have programmed in
other languages, this may seem like a strange way to describe what is usually performed
with nice simple Boolean values True and False. For now, try to take this description
at face value; Unicon has no Boolean type or integer equivalent, it uses a more powerful
concept that we will examine more fully in the chapters that follow.
Thus, the whole expression "" ˜== read() takes a line from the keyboard, and if it is not
empty, it produces that value for the enclosing write() instruction. When you type an empty
12 CHAPTER 1. PROGRAMS AND EXPRESSIONS

line, the value read() produces is equal to "", and ˜== produces no value for the enclosing
write() instruction, which similarly fails when given no value. The while instruction is a
"loop" that repeats the instruction that follows it until that instruction fails (in this case,
until there is no more input). There are other kinds of loops, as well as another way to use
while; they are all described later in this chapter.
So far we've painted you a picture of the Unicon language in very broad strokes, and
informally introduced several relevant programming concepts along the way. These con-
cepts are presented more thoroughly and in their proper contexts in the next sections and
subsequent chapters. Hopefully you are already on your way to becoming an Icon pro-
grammer extraordinaire. Now it is time to dive into many of the nuts and bolts that make
programming in Unicon a unique experience.

1.2 Command Line Options

Unicon comes with an IDE, but you can edit programs with any editor, and compile and
run them from your operating system's command line. This section describes the Unicon
command line tools along with several useful options. The Unicon compiler executable is
named unicon, and to compile the program foo.icn you would type

unicon foo

To execute the resulting program, just type

foo

To compile and link a program consisting of several modules, you can type them all on
the command line, as in

unicon foo bar baz

but often you will want to compile them separately (using the -c command line option)
and link the resulting object les, called ucode les; their extension is .u

unicon -c foo
unicon -c bar
unicon -c baz
unicon foo.u bar.u baz.u

Some of the other useful command line options include:

• -o arg name the resulting output le arg

• -x args execute the program immediately after linking; this option goes after the
program lenames
1.3. EXPRESSIONS AND TYPES 13

• -t turn on tracing

• -u produce a warning for undeclared variables

• -E output preprocessed source code

• -C compile to C code and link

These options can be specied in the Ui program under the Compile menu's Compile
Options command. Other options exist; consult your Unicon and Icon manual pages and
platform-specic help les and release information for more details.

1.3 Expressions and Types

Each procedure in a Unicon program is a sequence of expressions. Expressions are instruc-


tions for obtaining values of some type, such as a number or a word; some expressions also
cause side eects, such as sending data to a hardware device. Simple expressions just read
or write a value stored in memory. More interesting expressions specify a computation that
manipulates zero or more argument values to obtain result values by some combination of
operators, procedures, or control structures.
The simplest expressions are literals, such as 2 or "hello, world!". These expressions
directly specify a value stored in memory. When the program runs, they do not do any
computation, but rather evaluate to themselves. Literals are combined with other values to
produce interesting results. Each literal has a corresponding type. This chapter focuses on
the atomic types. Atomic types represent individual, immutable values. The atomic types
in Unicon are integer and real (oating-point) numbers, string (a sequence of characters),
and cset (a character set). Atomic types are distinguished by the fact that they have literal
values, specied directly in the program code and represented as data in the compiled code.
Values of other types such as lists are constructed during execution. Later chapters describe
structure types that organize collections of values, and system types for interacting with
the operating system via les, databases, windows, and network connections.
After literals, references to variables are the next simplest form of expression. Variables
are named memory locations that hold values for use in subsequent expressions. You refer
to a variable by its name, which must start with a letter or underscore and may contain
any number of letters, underscores, or numbers. Use names that make the meaning of the
program clear. The values stored in variables are manipulated by using variable names in
expressions like i+j. This expression results in a value that is the sum of the values in the
variables i and j, just like you would expect.
Some words may not be used as variable names because they have a special meaning
in the language. These reserved words include procedure, end, while, and so on. Other
special variables called keywords start with the ampersand character (&) and denote special
14 CHAPTER 1. PROGRAMS AND EXPRESSIONS

values. For example, global variables are initialized to the null value represented by the
keyword &null. Other keywords include &date, &time, and so on. Complete lists of reserved
words and keywords are given in Appendix A.
Unlike many languages where you have to state up front (declare ) all the variables you
are going to use and specify their data type, in Unicon variables do not have to be declared
at all, and any variable can hold any type of value. However, Unicon will not allow you to
mix incompatible types in an expression. Unicon is type safe, meaning that every operator
checks its argument values to make sure they are compatible, converts them if necessary,
and halts execution if they cannot be converted.

1.4 Numeric Computation

Unicon supports the usual arithmetic operators on data types integer and real. Integers
are signed whole numbers of arbitrary magnitude. The real type is a signed oating point
decimal number whose size on any platform is the largest size supported by machine instruc-
tions, typically 64-bit double precision values. In addition to addition (+), subtraction (-),
multiplication (*) and division (/), there are operators for modulo (%) and exponentiation
(ˆ). Arithmetic operators require numeric operands.
Note
Operations on integers produce integers; fractions are truncated, so 8/3 produces 2. If
either operand is a real, the other is converted to real and the result is real, so 8.0/3 is
2.66666...
As a general rule in Unicon, arguments to numeric operators and functions are auto-
matically converted to numbers if possible, and a run-time error occurs otherwise. The
built-in functions integer(x) and real(x) provide an explicit conversion mechanism that
fails if x cannot be converted to numeric value, allowing a program to check values without
resulting in a run-time error.
In addition to the operators, built-in functions support several common numeric oper-
ations. The sqrt(x) function produces the square root of x, and exp(x) raises e to the x
power. The value of pi (3.141...) is available in keyword &pi, the Golden Ratio (1.618...)
is available in &phi, and e (2.718...) is available in &e. The log(x) function produces the
natural log of x. The common trigonometric functions, such as sin() and cos() take their
angle arguments in radian units. The min(x1, x2, ...) and max(x1, x2, ...) routines re-
turn minimum and maximum values from any number of arguments. Appendix A gives a
complete list of built-in functions and operators.
Listing 1-1 shows a simple Unicon program that illustrates the use of variables in a
numeric computation. The line at the beginning is a comment for the human reader.
Comments begin with the # character and extend to the end of the line on which they
appear. The compiler ignores them.
1.5. STRINGS AND CSETS 15

Listing 1-1 Mystery program

# What do I compute?
procedure main()
local i, j, old_r, r
i := read()
j := read()
old_r := r := min(i, j)
while r > 0 do {
old_r := r
if i > j then
i := r := i % j
else
j := r := j % i
}
write(old_r)
end

This example illustrates assignment ; values are assigned to (or "stored in") variables
with the := operator. As you saw in the previous section, the function read() reads a line
from the input and returns its value. The modulo operator (%) is an important part of
this program: i % j is the remainder when i is divided by j.
While loops can use a reserved word do followed by an expression (often a compound
expression in curly braces). The expression following the do is executed once each time the
expression that controls the while succeeds. Inside the while loop, a conditional if-then-else
expression is used to select from two possible actions.
The names of the variables in this example are obscure, and there are no comments in
it other than the one at the top. Can you guess what this program does, without running
it? If you give up, try running it with a few pairs of positive numbers.
In addition to arithmetic operators, there are augmented assignment operators. To
increment the value in a variable by 2, these two statements are equivalent:

i +:= 2
i := i + 2

Augmented assignment works for most binary operators, not just arithmetic. The
expression i op:= expr means the same as i := i op expr.

1.5 Strings and Csets

The non-numeric atomic types in Unicon are character sequences (strings) and character
sets (csets). Icon came from the domain of string processing, and from it Unicon inherits
16 CHAPTER 1. PROGRAMS AND EXPRESSIONS

many sophisticated features for manipulating strings and performing pattern matching.
This section presents the simple and most common operations. More advanced operations
and examples using strings and csets are given in Chapter 4.
String literals are enclosed in double quotes, as in "this is a string", while cset literals
are enclosed in single quotes, as in ’aeiou’. Although strings and csets are composed of
characters, there is no character type; a string (or cset) consisting of a single character is
used instead.
Current implementations of Unicon use eight-bit characters, allowing strings and csets
to be composed from 256 unique characters. ASCII representation is used for the lower 128
characters, except on EBCDIC systems. The appearance of non-ASCII values is platform
dependent. Like integers, strings can be arbitrarily large, constrained only by the amount
of memory you have on your system.
Several operators take string arguments. The *s operator gives the length of string s.
The expression s1||s2 produces a string consisting of the characters in s1 followed by s2.
The subscript operator s[i] produces a one-letter substring of s at the ith position. Indices
are counted starting from position 1. If i is nonpositive, it is from the end of the string, for
example s[-2] is the second to the last character in the string.
Csets support set operators. c1++c2 produces a cset that is the union of c1 and
c2. The expression c1**c2 is the intersection, while c1--c2 is the dierence. In addition,
several keywords are commonly used csets. The keywords &letters, &lcase, and &ucase
denote the alphabetic characters, lower case characters a-z, and upper case characters A-Z,
respectively, while &digits is the set from 0-9, &ascii is the lower 128 characters, and &cset
is the set of all (256, on most implementations) characters.
Many built-in functions operate on strings and csets. Some of the simple string functions
are reverse(x), which produces the reverse of a string (or list) x, and trim(s,c), which
produces a substring of s that does not end with any character in cset c.
Functions and operators that require string arguments convert numeric values to strings
automatically, and halt execution with a run-time error if given a value that cannot be
converted to a string.

1.6 Goal-directed Evaluation

So far, the examples of how expressions are evaluated have included nothing you wouldn't
nd in ordinary programming languages. It is time to push past the ordinary. In most
conventional languages, each expression always computes exactly one result. If no valid
result is possible, a sentinel value such as -1, NULL, EOF (end-of-le) or INF (innity) is
returned instead. This means that the program must check the return value for this con-
dition. For example, while reading integers from the input and performing some operation
on them you might do something like this:
while (i := read()) ˜= -1 do
1.6. GOAL-DIRECTED EVALUATION 17

process(i)

This will work, of course, except when you really need to use -1 as a value! It is
somewhat cumbersome, however, even when a sentinel value is not a problem. Unicon
provides a much nicer way to write this type of code, developed originally in the Icon
language. In Unicon, expressions are goal-directed. This means that every expression when
evaluated has a goal of producing results for the surrounding expression. If an expression
succeeds in producing a result, the surrounding expression executes as intended, but if an
expression cannot produce a result, it is said to fail and the surrounding expression cannot
be performed and in turn fails.
Now take a look at that loop again. If it weren't for the termination condition, you
would not need the intermediate variable i. If you would like to say:

process(read())

your wishes are answered by Unicon; you can indeed write your program like this. The
expression read() tries to produce a value by reading the input. When it is successful,
process() is called with the value; but when read() cannot get any more values, that is,
at the end of the le, it fails. This failure propagates to the surrounding expression and
process() is not called either. Here is the clincher: control expressions like if and while
don't check for Boolean (true/false) values, they check for success! So our loop becomes

while process(read())

The do clause of a while loop is optional; in this case, the condition does everything we
need, and no do clause is necessary.
Consider the if statement that was used in the earlier arithmetic example:

if i > j then ...

Comparison operators such as > succeed or fail depending on the values of the operands.
This leads to another question: if an expression like i < 3 succeeds, what value should it
produce? No "true" value is needed, because any result other than failure is interpreted as
"true." This allows the operator to return a useful value instead! The comparison operators
produce the value of their right operand when they succeed. You can write conditions like

if 3 < i < 7 then ...

that appear routinely in math classes. Other programming languages only dream about
being this elegant. First, Unicon computes 3 < i. If that is true, it returns the value i, which
is now checked with 7. This expression in fact does exactly what you'd expect. It checks
to see that the value of i is between 3 and 7. (Also, notice that if the rst comparison fails,
the second one will not be evaluated.)
18 CHAPTER 1. PROGRAMS AND EXPRESSIONS

1.7 Fallible Expressions

Because some expressions in Unicon can fail to produce a result, you should learn to
recognize such expressions on sight. These fallible expressions control the ow of execution
through any piece of Unicon code you see. When failure is expected it is elegant. When
it is unexpected in your program code, it can be disastrous, causing incorrect output that
you may not notice or, if you are lucky, the program may terminate with a run-time error.
Some fallible expressions fail when they cannot perform the required computation; oth-
ers are predicates whose purpose is to fail if a condition is not satised. The subscript and
sectioning operators are examples of the rst category. The expression x[i] is a subscript
operator that selects element i out of some string or structure x. It fails if the index i is
out of range. Similarly, the sectioning operator x[i:j] fails if either i or j are out of range.
The read() function is illustrative of a large number of built-in functions that can fail.
A call to read() fails at the end of a le. You can easily write procedures that behave
similarly, failing when they cannot perform the computation that is asked. Unfortunately,
for an arbitrary procedure call p(), you can't tell if it is fallible without studying its source
code or reference documentation. The safest thing is to expect any procedure call is fallible
and check whether it failed, unless you know it is not fallible or its failure doesn't matter.
Following this advice may avoid many errors and save you lots of time. In this book we
will be careful to point out fallible expressions when we introduce them.
The less than operator < is a typical predicate operator, one that either fails or produces
exactly one result. The unary predicates /x and \x test a single operand, succeeding and
producing the operand if it is null, or non-null, respectively. The following binary predicates
compare two operands. The next section presents some additional, more complex fallible
expressions.

< <= > >= = ˜= numeric comparison operators


<< <<= >> >>= == ˜== lexical (alphabetic) comparison
=== ˜=== reference comparison

1.8 Generators

So far we have seen that an expression can produce no result (failure) or one result (success).
In general, an expression can produce any number of results: 0, 1, or many. Expressions
that can produce more than one result are called generators. Consider the task of searching
for a substring within a string:

find("lu", "Honolulu")

In most languages, this would return one of the substring matches, usually the rst
position at which the substring is found. In Unicon, this expression is a generator, and
1.8. GENERATORS 19

can produce all the positions where the substring occurs. If the surrounding expression
only needs one value, as in the case of an if test or an assignment, only the rst value of a
generator is produced. If a generator is part of a more complex expression, then the return
values are produced in sequence until the whole expression produces a value.
Let us look at this example:

3 < find("or", "horror")

The rst value produced by find() is 2, which causes the < operation to fail. Execution
then resumes the call to find(), which produces a 5 as its next value, and the expression
succeeds. The value of the expression is the rst position of the substring greater than 3.
The most obvious generator is the alternation operator |. The expression

expr1 | expr2

produces its left-hand side followed by its right-hand side, if needed by the surrounding
expression. This can perform many computations quite compactly. For example,

x = (3 | 5)

checks to see if the value of x is 3 or 5. More complex expressions follow logically:

(x | y) = (3 | 5)

checks to see if either x or y has the value 3 or 5. It is the Unicon equivalent of C's

(x == 3) || (x == 5) || (y == 3) || (y == 5)

In understanding Unicon code, it helps if you identify the generators, if there are any.
In addition to the alternation operator | and the function find(), there are a few other
generators in Icon's built in repertoire of operators and functions. We mention them briey
here, so you can be on the lookout for them when reading code examples.
The expression i to j is a generator that produces all the values between i and j. The
expression i to j by k works similarly, incrementing each result by k; i, j, and k must all be
integer or real numbers, and k must be non-zero. The expression i to j is equivalent to i
to j by 1. The unary ! operator is a generator that produces the elements of its argument.
This works on every type where it makes sense. Applied to a string, it produces all its
characters (in order). Sets, tables, lists, or records produce the members of the structure.
Generators get resumed for more results as needed in order for the surrounding expres-
sion to succeed, and this may propagate through many levels of nested enclosing expressions.
However, special expressions called bounded expressions will never resume their generator
subexpressions. For example, the conditional expressions used in if and while are never
resumed if they succeed; if they produce a result the then-branch or the loop body is exe-
cuted, and if that code fails, it does not cause generators in the conditional to be resumed.
20 CHAPTER 1. PROGRAMS AND EXPRESSIONS

Those bounded conditional expressions are re-evaluated starting from scratch if execution
comes their way again. Another popular bounded expression is the semi-colon operator.
The expression expr1 ; expr2 evaluates the two expressions in order, and bounds the rst
expression, so you don't have to worry about backtracking into it if the second expression
fails.

1.9 Iteration and Control Structures

You have already seen two control structures in Unicon: the if and the while loop, which
test for success. Unicon has several other control structures that vary in complexity and
usefulness. Unicon is expression-based, and all control structures are expressions that
can be used in surrounding expressions if desired. The big dierence between control
structures and ordinary operators or procedures is that ordinary operators and procedures
don't execute until their arguments have been evaluated and produced a result; they don't
execute at all if an argument fails. In contrast, a control structure uses one of its arguments
to decide whether (or how many times) to evaluate its other arguments.
Since control structures are expressions, they may produce a result for a surrounding
expression. For example, the result of an if expression is the result of either its then part
or its else part, whichever one was selected. On the other hand, a loop executes until its
test fails, after which there is no meaningful result for it to produce; loops usually fail as
far as surrounding expressions are concerned.
The control structure every processes the entire sequence of values produced by a gen-
erator. The expression

every expr1 do expr2

evaluates expr2 for each result generated by expr1. This loop looks similar enough to a
while loop to confuse people at rst. The dierence is that a while loop re-evaluates expr1
from scratch after each iteration of expr2 , but every resumes expr1 for an additional result
where it left o the last time through the loop. Using a generator to control a while loop
makes no sense; the generator will restart each iteration, which may give you an innite
loop. Similarly, not using a generator to control an every loop also makes no sense; if
expr1 is not a generator the loop body executes at most one time.
The classic example of every is a loop that generates the number sequence from a
to expression, assigning the number to a variable that can be used in expr2 . In many
languages these are called for loops. A for loop in Unicon is written like this:

every i := 1 to 10 do write(i)

Of course, every and to are not limited to this BASIC-style for loop. Generators are more
exible; the for loop above looks clumsy when compared with the equivalent
1.9. ITERATION AND CONTROL STRUCTURES 21

every write(1 to 10)

A generator operand to a non-generator forms a generator. The enclosing non-generator


(such as write()) is re-run each time the generator suspends and resumes.
Unicon's every keyword generalizes the concept of iterators found in other languages.
Iterators are special control structures that walk through a collection of data. Instead of
being a special feature, in Unicon iterators are just one of many ways to utilize generators.
The sequence of results from an expression does not have to be stored in a structure to
iterate over them. The sequence of results does not even have to be nite; many generator
expressions produce an innite sequence of results, as long as the surrounding expression
keeps asking them for more. Here is another example of how every expressions are more
exible than for loops. The expression

every f(1 | 4 | 9 | 16 | 25 | 36)

executes the function f several times, passing the rst few square numbers as parameters.
A shorter equivalent that uses the power operator (ˆ) is every f((1 to 6)ˆ2). An example in
the next section shows how to generalize this to work with all the squares.
The if, while, and every expressions are Unicon's primary control structures. Several
other control structures are available that may be more useful in certain situations. The
loop

until expr1 do expr2

is while's evil twin, executing expr2 as long as expr1 fails; on the other hand

repeat expr

is an innite loop, executing expr over and over.


There are also variations on the if expression introduced earlier for conditional execution.
First, the else branch is optional, so you can have an if expression that does nothing if
the condition is not satised. Second, there is a special control structure introduced for
the common situation in which several alternatives might be selected using a long sequence
of if ... else if ... else if ... expressions. The case expression replaces these chains of if
expressions with the syntax:

case expr of {
branch1: expr1
branch2: expr2
...
default: expr i
}
22 CHAPTER 1. PROGRAMS AND EXPRESSIONS

When a case expression executes, the expr is evaluated, and compared to each branch
value until one that matches exactly is found, as in the binary equality operator ===.
Branch expressions can be generators, in which case every result from the branch is com-
pared with expr . The default branch may be omitted in case expressions for which no
action is to be taken if no branch is satised.
When we introduced the repeat loop, you probably were wondering how to exit from
the loop, since most applications do not run forever. One answer would be to call one of the
built-in functions that terminate the entire program when it is time to get out of the loop.
The exit(), stop(), and runerr() functions all serve this valuable purpose; their dierences
are described in Appendix A.
A less drastic way to get out of any loop is to use the break expression:

break expr

This expression exits the nearest enclosing loop; expr is evaluated outside the loop
and treated as the value produced by executing the loop. This value is rarely used by
the surrounding expression, but the mechanism is very useful, since it allows you to chain
any number of breaks together, to exit several levels of loops simultaneously. The break
expression has a cousin called next that does not get out of a loop, but instead skips the
rest of the current iteration of a loop and begins the next iteration of the loop.

1.10 Procedures

Procedures are a basic building block in most languages. Here is an example of an ordinary
procedure. This one computes a simple polynomial, ax2 + bx + c.

procedure poly(x,a,b,c)
return a * xˆ2 + b * x + c
end

Parameters
Procedure parameters are passed by value except for structured data types, which are
passed by reference. This means that when you pass in a string, number, or cset value,
the procedure gets a copy of that value; any changes the procedure makes to its copy will
not be reected in the calling procedure. On the other hand, structures that contain other
values, such as lists, tables, records, and sets are not copied. The procedure being called
gets a handle to the original value, and any changes it makes to the value will be visible to
the calling procedure. Structure types are described in the next chapter.
When you call a procedure with too many parameters, the extras are discarded. This
feature is valuable for prototyping but can be dangerous if you aren't careful! Similarly,
1.10. PROCEDURES 23

if you call a procedure with too few parameters, the remaining variables are assigned the
null value, &null. The null value is also passed as a parameter if you omit a parameter.
Now it is time to describe the unary operators \ and /. These operators test the expres-
sion against the null value. The expression /x succeeds and returns x if the value is the null
value. This can be used to assign default values to procedure arguments: Any arguments
that have a null value can be tested for and assigned a value. Here's an example:

procedure succ(x, i)
/i := 1
return x + i
end

If this procedure is called as succ(10), the missing second parameter, i, is assigned the
null value. The forward slash operator then tests i against the null value, which succeeds;
therefore the value 1 is assigned to i.
The backward slash checks if its argument is non-null. For example, this will write the
value of x if it has a non-null value:

write("The value of x is ", \x)

If x does in fact have the null value, then \x will fail, which will mean that the write()
procedure will not be called. If it helps you to not get these two mixed up, a slash pushes
its operand "up" for non-null, and "down" for a null value.
The procedure succ() shows one way to specify a default value for a parameter. The
built-in functions use such default values systematically to reduce the number of parameters
needed; consistent defaults for entire families of functions make them easy to remember.
Another key aspect of the built-in operations is implicit type conversion. Arguments to
built-in functions and operators are converted as needed.
Defaulting and type conversion are so common and so valuable in Unicon that they
have their own syntax. Parameter names may optionally be followed by a coercion function
(usually the name of a built in type) and/or a default value, separated by colons. These
constructs are especially useful in enforcing the public interfaces of library routines that
will be used by many people.

procedure succ(x:integer, i:integer:1)


end

This parameter declaration is a more concise equivalent of

procedure succ(x, i)
x := integer(x) | runerr(101, x)
/i := 1 | i := integer(i) | runerr(101, i)
end
24 CHAPTER 1. PROGRAMS AND EXPRESSIONS

Variables and scopes


Variable names used as parameters are fundamentally dierent from procedure names. The
scope of parameters is limited to the body of a single procedure, while procedure names
are visible to the entire program. Parameters and procedures are special forms of two basic
kinds of variables in Unicon: local variables and global variables.
The scope of global variables, including procedure names, consists of the entire program.
Their value is stored in memory for the entire execution of the program. There are two
kinds of local variables; both introduce names that are dened only within a particular
procedure. Regular local variables are created when a procedure is called, and destroyed
when a procedure fails or returns a result; a separate copy of regular local variables is
created for each call. Static local variables are global variables whose names are visible
only within a particular procedure; a single location in memory is shared by all calls to the
procedure, and the last value assigned in one call is remembered in the next call.
Variables do not have to be declared, and by default they are local. To get a global
variable, you have to declare it outside any procedure with a declaration like this:

global MyGlobal

Such a declaration can be before, after, or in between procedures within a program


source le, but cannot be inside a procedure body. Of course, another way to declare a
global variable is to dene a procedure; this creates a global variable initialized with the
appropriate procedure value containing the procedure's instructions.
Regular and static local variables may be declared at the top of a procedure body, after
the parameters and before the code starts, as in the following example:

procedure foo()
local x, y
static z
...
end

Each declared local variable name may be followed by a := and an initializer expression
that species the variable's initial value. Without an initializer, variables start with the
value &null. Although you do not have to declare local variables, large programs, library
code or multi-person projects should declare all local variables. If you don't, and some
other part of the code introduces a global variable by the same name as your undeclared
local, your variable will be interpreted as a reference to the global. To help avoid this
problem, the -u command line option to the compiler causes undeclared local variables to
produce a compilation error message.
A procedure body can begin with an initial clause, which executes only the rst time
the procedure is called. The initial clause is mainly used to initialize static variables in ways
1.10. PROCEDURES 25

that aren't handled by initializers. For example, the following procedure returns the next
number in the Fibonacci sequence each time it is called, using static variables to remember
previous results in the sequence between calls.

procedure fib()
static x,y
local z
initial {
x := 0
y := 1
return 1
}
z := x + y
x := y
y := z
return z
end

Writing your own generators


When a procedure returns a value, the procedure and its regular local variables cease to ex-
ist. But there are expressions that don't disappear when they produce a value: generators!
You can create your own generators by writing procedures that use suspend instead of
return. suspend is dierent from return in that it saves the point of execution within the
procedure; if another value is required by the calling expression, the generator continues
execution from where it previously left o.
Here is a procedure to generate all the squares. Instead of using multiplication, it
uses addition to demonstrate generators! The code uses the fact that if we keep adding
successive odd numbers, we get the squares.

procedure squares()
odds := 1
sum := 0
repeat {
suspend sum
sum +:= odds
odds +:= 2
}
end

To perform a computation on the squares, we can use it in an every statement:

every munge(squares())
26 CHAPTER 1. PROGRAMS AND EXPRESSIONS

Warning
This is an innite loop! (Do you know why? Whether munge() succeeds or fails, every
will always resume squares() for another result to try; squares() generates an innite
result sequence.)
The fail expression makes the procedure fail. Control goes to the calling procedure, re-
turning no value, and the procedure call ceases to exist; it cannot be resumed. A procedure
also fails implicitly when control ows o the end of the procedure's body.
Here is a procedure that produces all the non-blank characters of a string, but bails out
if the character # is reached:

procedure nonblank(s)
every c := !s do {
if c == "#" then fail
if c ˜== " " then suspend c
}
end

Recursion
A recursive procedure is one that calls itself, directly or indirectly. There are many cases
where it is the most natural way of solving the problem. Consider the famous "Towers of
Hanoi" problem. Legend has it that when the universe was created, a group of monks in
a temple in some remote place were presented with a problem. There are three diamond
needles, and on one of them is a stack of 64 golden disks all of dierent sizes, placed in
order with the largest one at the bottom and the smallest on top. All the disks are to be
moved to a dierent needle under the conditions that only one disk may be moved at a
time, and a larger disk can never be placed on a smaller disk. When the monks nish this
task, the universe will come to an end.
How can you move the n smallest disks? If n is 1, just move it. Since it's the smallest,
this will not violate the condition. If n is greater than 1, here's what we can do: rst,
move the n-1 upper disks to the intermediate needle, then transfer the n th disk, then move
the n-1 upper disks to the destination needle. This whole procedure does not violate the
requirements either (satisfy yourself that such is the case).
Now write the procedure hanoi(n) that computes this algorithm. The rst part is
simple: if you have one disk, just move it.

procedure hanoi(n, needle1:1, needle2:2)


if n = 1 then write("Move disk from ", needle1, " to ", needle2)

Otherwise, perform a recursive call with n-1. First, to nd the spare needle we have:
other := 6 - needle1 - needle2
1.10. PROCEDURES 27

Now move the n-1 disks from needle1 to other, move the biggest disk, and then move
the n-1 again. The needles are passed as additional parameters into the recursive calls.
They are always two distinct values out of the set {1, 2, 3}.

hanoi(n-1, needle1, other)


write("Move disk from ", needle1, " to ", needle2)
hanoi(n-1, other, needle2)

That's it! You're done. Listing 1-2 contains the complete program for you to try:

Listing 1-2 Towers of Hanoi

procedure main()
write("How many disks are on the towers of Hanoi?")
hanoi(read())
end
procedure hanoi(n:integer, needle1:1, needle2:2)
local other
if n = 1 then write("Move disk from ", needle1, " to ", needle2)
else {
other := 6 - needle1 - needle2
hanoi(n-1, needle1, other)
write("Move disk from ", needle1, " to ", needle2)
hanoi(n-1, other, needle2)
}
end

Turn on tracing see how this program works. To enable tracing, compile your program
with a -t option, or assign the keyword &trace a non-zero number giving the depth of calls
to trace. Setting &trace to -1 will turn on tracing to an innite depth.
To move n disks, 2 n - 1 individual disk movements will be required. If the monks move
one disk a second, it will take 2 64 - 1 seconds, or about 60 trillion years. Wikipedia has
listed the age of the universe at around 13.75 billion years. It seems unlikely that we need
worry about the monks nishing their task!

Summary

In this chapter you have learned:

• Unicon is an expression-based language organized as a set of procedures starting from


a procedure called main().
• Unicon has four atomic types: arbitrary precision integers, real numbers, arbitrary
length strings of characters, and character sets.
28 CHAPTER 1. PROGRAMS AND EXPRESSIONS

• There is no Boolean concept in Unicon; instead, control is driven by whether an


expression succeeds in producing a result or fails to do so. This eliminates the need
for most sentinel values, shortening many expressions.
• Generator expressions can produce multiple results as needed by the surrounding
expression in order for it to produce results.
• Procedure parameters are passed by value for atomic types, and by reference for all
other data types. Unicon features extensive argument defaults and automatic type
coercion throughout its built-in function and operator repertoire.
• Unicon has two scope levels: global and local. Undeclared variables are implicitly
dened to be local.
Chapter 2
Structures
The examples in the previous chapter employed data types whose values are immutable.
For example, all operations that manipulate numbers and strings compute new values,
rather than modify existing values. This chapter presents structured types that organize
and store collections of arbitrary (and possibly mixed) types of values. When you complete
this chapter, you will understand how to use these types.

• Tables associate their elements with key values for rapid lookup.

• Lists oer ecient access by position as well as by stack or queue operations.

• Records store values using a xed number of named elds.

• Sets support operations such as union and intersection on groups of elements.

• Using structures to represent trees, graphs, and matrices.

There are several structure types that describe dierent basic relationships between values.
The philosophy of structures in Unicon is to provide built-in operators and functions for
common organization and access patterns - the exible "super glue" that is needed by nearly
all applications. Their functionality is similar to the C++ Standard Template Library or
generic classes in other languages, but Unicon's structure types are much simpler to learn
and use, and are well supported by the expression evaluation mechanism described in the
previous chapter.
All structure types in Icon share many aspects in common, such as the fact that struc-
tures are mutable. The values inside them may change. In that respect, structures are
similar to a collection of variables that are bundled together. In many cases, Unicon's
structure types are almost interchangeable! Operators like subscripts and built-in functions
such as insert() are dened consistently for many types. Code that relies on such operators
is polymorphic : it may be used with multiple structure types in an interchangeable way.
For both the structures described in this chapter and the strings described in the next
chapter, be aware that Unicon performs automatic storage management, also known as

29
30 CHAPTER 2. STRUCTURES

garbage collection. If you have used a language like C or C++, you know that one of the
biggest headaches in writing programs in these languages is tracking down bugs caused
by memory allocation, especially dynamic heap memory allocation. Unicon transparently
takes care of those issues for you.
Another big source of bugs in languages like C and C++ are pointers, values that
contain raw memory addresses. Used properly, pointers are powerful and ecient. The
problem is that they are easy to use incorrectly by accident; this is true for students and
practicing software engineers alike. It is easy in C to point at something that is o-limits,
or to trash some data through a pointer of the wrong type.
Unicon has no pointer types, but all structure values implicitly use pointer semantics.
A reference is a pointer for which type information is maintained and safety is strictly
enforced. All structure values are references to data that is allocated elsewhere, in a
memory region known as the heap. You can think of a reference as a safe pointer: the only
operations it supports are copying the pointer, or dereferencing it using an operation that
is dened for its type.
Assigning a structure to a variable, or passing it as a parameter, gives that variable
or parameter a copy of the reference to the structure but does not make a copy of the
structure. If you want a copy of a structure, you call the function copy(x), which makes a
shallow copy of a single table, list, record, or set. If that structure contains references to
other structures as its elements, those substructures are not copied by copy(). To copy a
deep structure (lists of lists, tables of records, etc.) you can use the procedure deepcopy()
that is given as an example later in this chapter.

2.1 Tables

Tables are unordered collections of values that are accessed using associated keys. They
are Unicon's most versatile type. All of the other structure types can be viewed as special
cases of tables, optimized for performance on common operations. Most operations that
are dened for tables are dened for other structure types as well.
Subscripts are used for the primary operations of associating keys with values that are
inserted into the table, and then using keys to look up objects in the table. The table()
function creates a new empty table. For example, the lines

T := table()
T["hello"] := "goodbye"

create a new table, and associate the key "hello" with the value "goodbye". The table()
function takes one optional argument: the default value to return when lookup fails. The
default value of the default value is &null, so after the above example, write(T["goodbye"])
would write an empty line, since write() treats a null argument the same as an empty string,
and write() always writes a newline. Assigning a value to a key that is not in the table
2.2. LISTS 31

inserts a value into the table. This occurs in the second line of the example above, so
write(T["hello"]) writes out "goodbye".
Subscripts are the primary operation on tables, but there are several other useful op-
erations. The insert(T, k1 , x1 , k2 , x2 , ...) function adds new key-value pairs to T. The
delete(T, k1 , k2 , ...) function deletes values from T that correspond to the supplied keys.
Icon's unary * operator produces the size of its argument; for a table, *T is the number of
key-value pairs in the table. Unary ! generates elements from a collection; for a table, !T
generates the values stored in the table. Unary ? is the random operator; for a table, ?T
produces a random value stored in the table. Both unary ! and ? produce values stored in
a table, not the keys used to lookup values.
Function member(T, k) succeeds if k is a key in T and fails otherwise. Function key(T)
generates the keys that have associated values. The following example prints word counts
for the input (assuming getword() generates words of interest):

wordcount := table(0)
every word := getword() do wordcount[word] +:= 1
every word := key(wordcount) do write(word, " ", wordcount[word])

The default value for the table is 0. When a new word is inserted, the default value
gets incremented and the new value (that is, 1) is stored with the new word. Tables grow
automatically as new elements are inserted.
Tables are closely related to the set data type (discussed later in this chapter). The
keys of a table are a set; the associated values accessed via the subscript operator are sort
of a bonus data payload. In any case, tables behave in certain set-like ways; when their
elements are generated by the ! operator, they come out in a pseudo random order. Like
sets, and csets in the previous chapter, the operators T1++T2, T1**T2, and T1--T2 are
the union, intersection, and dierence of the keys of tables T1 and T2. These operators
construct new tables and do not modify their operands. In union and intersection, when
duplicate table keys occur in the two operands, the associated values from the left operand
are what goes in the new table that holds the result.

2.2 Lists

Lists are dynamically sized ordered collections of values. They are accessed by subscripts,
with indexes starting at 1. You can also insert or remove elements from the beginning,
middle, or end of the list. Lists take the place of arrays, stacks, queues, and deques found
in other languages and data structures textbooks.
There are three ways to explicitly construct a list. In the most generic form, a list is
created by calling the function list(), which takes optional parameters for the lists's initial
size and the initial value given to all elements of the list. The default size is 0 and the
default initial value is &null.
32 CHAPTER 2. STRUCTURES

The second form of list constructor is when you create a list by enclosing a comma-
separated sequence of 0 or more values in square nbrackets. For example

L := ["linux", 2.0, "unix"]

creates a list with three elements, a string, a real number, and another string.
A third form of list constructor, called comprehension , looks like the previous form,
except the square brackets contain adjacent colon characters and have an expression inside.

L := [: expr :]

In a comprehension the constructed list's initial values are obtained by fully evaluating
an expression and placing all of its results into the list, in order. The expression fails if
expr fails; if you wanted that to be an empty list you may need to append |[].
Lists are dynamic. Lists grow or shrink as a result of stack and queue operations.
The push() and pop() functions add and remove elements from the front of a list, while
put() and pull() add and remove elements at the end of the list. In addition, insert(L, i, x)
inserts x at position i, and delete(L, i) deletes the element at position i. The expression []
is another way to create an empty list; it is equivalent to calling list() with no arguments.
The previous list could have been constructed one element at a time with the following
code. put() accepts a variable number of arguments .

L := [ ]
put(L, "linux")
put(L, 2.0)
put(L, "unix")

Elements of the list can be obtained either through list manipulation functions or by
subscripting. Given the list L above, in the following code the rst line writes "unix" while
the second line moves the rst element to the end of the list.

write(L[3])
put(L, pop(L))

There is no restriction on the kinds of values that may be stored in a list. For example,
the elements of a list can themselves be lists. You can create lists like

L := [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

and index them with multiple subscripts. L[2][3] is equivalent to L[2,3] and yields the value
6 in this example.
Lists also support several common operators. The operator *L produces the size of list
L. The operators !L and ?L generate the elements of L in sequence, and produce a single
random element of L, respectively. The following procedure uses the unary ! operator to
sum the values in list L, which must be numbers.
2.3. RECORDS 33

procedure sum(L)
total := 0
every total +:= !L
return total
end

Comparing the two, lists are like tables with boring keys: the positive integers starting
from 1. Function member(L, k) succeeds if 0 < integer(k) <= *L, while key(L) is equivalent
to the expression 1 to *L. List indexes are contiguous, unlike table keys, and so lists can
support a slice operator to produce a sublist, given a pair of indexes to mark the bounds.
The L[i:j] expression produces a new list that contains a copy of the elements in L between
positions i and j. The L[i+:j] expression is equivalent to L[i:i+j]. List concatenation is another
valuable operator. The L1 ||| L2 expression produces a new list whose elements are a copy
of the elements in L1 followed by a copy of the elements in L2.

2.3 Records

A record is a xed-sized, ordered collection of values whose elements are accessed using
user-dened named elds. A record is declared as a global name that introduces a new
type with a corresponding constructor procedure, as in the following example. The eld
names are a comma-separated list of identiers enclosed in parentheses.

record complex(re, im)

Record instances are created using a constructor procedure with the name of the record
type. The elds of an instance are accessed by name using dot notation or string subscript,
or by integer index subscript. You can use records as records, or as special tables or lists
with a constant size and xed set of keys.
member(R,s) tests whether s is a eld in R; key(R) generates R's eld names. Functions
like insert(), or push() are not supported on records, since they change the size of the
structure that they modify. Here is a demonstration of record operations.

a := complex(0, 0)
b := complex(1, -1)
if a.re = b.re then write("not likely")
if a["re"] = a[2] then write("a.re and a.im are equal")

Unicon provides a mechanism for constructing new record types on the y, described in
Chapter 6, as well as the ability to declare classes, which are new data types that form the
building blocks for object-oriented programs, described starting in Chapter 9. Records are
closely related to classes and objects: they can be considered to be an optimized special
case of objects that have no methods.
34 CHAPTER 2. STRUCTURES

2.4 Sets

A set is an unordered collection of values with the uniqueness property: an element can
only be present in a set once. The function set(x...) creates a set containing its arguments.
For the sake of backward compatibility with Icon, list arguments to set() are not inserted;
instead, the list elements are inserted. As with other structures, the elements may be of
any type, and may be mixed. For example, the assignment
S := set("rock lobster", ’B’, 52)
creates a set with three members: a string, a cset, and an integer. The equivalent set is
produced by set(["rock lobster","B", 52]). To place a list in a set set constructor, wrap
it in another list, as in set([L]), or insert the list into the set after it is created. Because
the set constructor function initializes directly from a list argument, set comprehension
follows trivially from list comprehension. For example, set([: 2 to 20 by 2 :]) creates a set
containing the even integers from two to twenty.
The functions member(), insert(), and delete() do what their names suggest. As for
csets in the previous chapter, S1++S2, S1**S2, and S1--S2 are the union, intersection,
and dierence of sets S1 and S2. Set operators construct new sets and do not modify
their operands. Because a set can contain any value, it can contain a reference to itself.
This is one of several dierences between Unicon sets, which are mutable structures, and
mathematical sets. Another dierence is that Unicon sets have a nite number of elements,
while mathematical sets can be innite in size.
As a short example, consider the following program, called uniq, that lters duplicate
lines in its standard input as it writes to its standard output. Unlike the UNIX utility of
this name, our version does not require the duplicate lines to be adjacent.
procedure main()
S := set()
while line := read() do
if not member(S, line) then {
insert(S, line)
write(line)
}
end
Sets are closely related to the table data type. They are very similar to an optimized
special case of tables that map all keys to the value &null. Unlike tables, sets have no
default value and do not support the subscript operator.

2.5 Using Structures

Structures can hold other structures, allowing you to organize information in whatever way
best ts your application. Building complex structures such as a table of lists, or a list
2.5. USING STRUCTURES 35

of records that contain sets, requires no special trickery or new syntax. Examples of how
such structures are accessed and traversed will get you started. Recursion is often involved
in operations on complex structures, so it plays a prominent role in the examples. The
concept of recursion was discussed in Chapter 1.

A Deep Copy
The built-in function copy(x) makes a one-level copy of structure values. For a multi-level
structure, you need to call copy() for each substructure if the new structure must not point
into the old structure. This is a natural task for a recursive function.

procedure deepcopy(x)
local y
case type(x) of {
"table"|"list"|"record": {
y := copy(x)
every k := key(x) do y[k] := deepcopy(x[k])
}
"set": {
y := set()
every insert(y, deepcopy(!x))
}
default: return x
}
return y
end

This version of deepcopy() works for arbitrarily deep tree structures, but the program
execution will crash if deepcopy() is called on a structure containing cycles. It also does
not copy directed acyclic graphs correctly. In both cases the problem is one of not noticing
when you have already copied a structure, and copying it again. The Icon Program Library
has a deep copy procedure that handles this problem, and we present the general technique
that is used to solve it in the next section.

Representing Trees and Graphs


Since there is no restriction on the types of values in a list, they can be other lists too.
Here is an example of how a tree may be implemented with records and lists:

record node(name, links)


...
barney := node("Barney", list())
betty := node("Betty", list())
bambam := node("Bam-Bam", [barney, betty])
36 CHAPTER 2. STRUCTURES

The structure created by these expressions is depicted in Figure 2-1. The list of links
at each node allows trees with an arbitrary number of children at the cost of extra memory
and indirection in the tree traversals. The same representation works for arbitrary graphs.

Figure 2-1: A Record Containing a List of Two Records

To nd every node related to variable bambam, follow all the links reachable starting
from bambam. Here is a procedure that performs this task.

procedure print_relatives(n)
local i
static relatives
initial relatives := set()
every i := n | !n.links do {
if not member(relatives, i.name) then {
write(i.name)
insert(relatives, i.name)
print_relatives(i)
}
}
end

Calling print_relatives(bambam) will print

Bam-Bam
Barney
Betty

Static variables and the initial clause are explained in Chapter 1. Can you guess what
purpose static variable relatives serves? For a proper tree structure, it is not needed at
all, but for more general data structures such as directed graphs this static variable is very
important! One defect of this procedure is that there is no way to reset the static variable
and call print_relatives() starting from scratch. How would you remove this defect?
2.5. USING STRUCTURES 37

The n-Queens Example


The 8-Queens problem is a classic backtracking problem. The goal is to place eight queens
on a chessboard so that none of the queens attack any other. Here is a solution to a more
general form of the problem, that of placing n queens on an n x n board. The solution we
present is by Steve Wampler, and it is in the Icon Program Library.
An array of size n stores the solutions, with each element representing a column. The
values in the array are integers specifying the row in each column that has the queen. (Since
the queens cannot attack each other, each column must contain exactly one queen.) The
problem size n and the array are declared global so that all procedures can see them; this
allows the program to avoid passing these variables in to every procedure call. Use globals
sparingly, and only where they are appropriate, as is the case here.

link options
global solution, n
procedure main(args)
local i, opts

The program starts by handling command-line arguments. In Unicon programs, main()


is called with a single parameter that is a list of strings whose elements are the command-
line arguments of the program.
The n-queens program recognizes only one thing on the command line: the option -n
followed by an integer species the size of board to use. Thus the command line queens
-n 9 will generate solutions on a 9x9 board. The default value of n is 6. The options()
procedure is an Icon Program Library procedure described in Appendix B; it removes
options from the command line and places them in a table whose keys are option letters
such as "n". Library procedures such as options() are incorporated into a program using
the link declaration, as in the link options that begins the code fragment above. A link
declaration adds the procedures, global variables, and record types in the named module
(in this case, procedure options() came from a le options.icn) to the program.

opts := options(args,"n+")
n := \opts["n"] | 6
if n <= 0 then stop("-n needs a positive numeric parameter")

The value n gives the size for the solution array and also appears in a banner:

solution := list(n) # a list of column solutions


write(n,"-Queens:")
every q(1) # start by placing queen in first column
end
38 CHAPTER 2. STRUCTURES

Now comes the meat of the program, the procedure q(c). It tries to place a queen
in column c and then calls itself recursively to place queens in the column to the right.
The q(c) procedure uses three arrays: rows, up, and down. They are declared to be
static, meaning that their values will be preserved between executions of the procedure,
and all instances of the procedure will share the same lists. Since each row must have
exactly one queen, the rows array helps to make sure any queen that is placed is not on a
row that already has a queen. The other two arrays handle the diagonals: up is an array
(of size 2n-1 ) of the upward slanting diagonals, and down is an array for the downward
slanting diagonals. Two queens in positions (r_1, c_1) and (r_2, c_2) are on the same
"up" diagonal if n+r_1-c_1 = n+r_2-c_2 and they are on the same "down" diagonal if
r_1+c_1-1 = r_2+c_2-1. Figure 2-2 shows some of the up and down diagonals.

Figure 2-2: Up and Down Diagonals in the n-Queens Problem

#
# q(c) - place a queen in column c.
#
procedure q(c)
local r
static up, down, rows
initial {
up := list(2*n-1,0)
down := list(2*n-1,0)
rows := list(n,0)
}
2.5. USING STRUCTURES 39

The next expression in q() is an every loop that tries all possible values for the queen in
row c. The variable r steps through rows 1 to 8. For any row at which the program places
a queen, it must ensure that
1. rows[r] is zero, that is, no other column has a queen in row r,
2. up[n+r-c] is 0, that is, there is not already a queen in the "up" diagonal, and
3. down[r+c-1] is 0, that is, there is not already a queen in the down diagonal.
If these conditions are met, then it is OK to place a queen by assigning a 1 to all those
arrays in the appropriate position:

every 0 = rows[r := 1 to n] = up[n+r-c] = down[r+c-1] &


rows[r] <- up[n+r-c] <- down[r+c-1] <- 1 do {

For assignment, instead of := this expression uses the reversible assignment operator <-.
This assigns a value just like in conventional assignment, but it remembers the old value;
if it is ever resumed, it restores the old value and fails. This causes the appropriate entries
in the row, up, and down arrays will be reinitialized between iterations.
When the every loop found a good placement for this column, either the program is
done (if this was the last column) or else it is time to try to place a queen in the next row:

solution[c] := r # record placement.


if c = n then show()
else q(c + 1) # try to place next queen.
}
end

That's it! The rest of the program just prints out any solutions that were found.
Printing the chess board is similar to other reports you might write that need to create
horizontal lines for tables. The repl() function is handy for such situations. The repl(s, i)
function returns i "replicas" of string s concatenated together. The show() function uses
it to create the chessboard.

#
# show the solution on a chess board.
#
procedure show()
static count, line, border
initial {
count := 0
line := repl("| ",n) || "|"
border := repl("----",n) || "-"
}
write("solution: ", count+:=1, "\n ", border)
every line[4*(!solution - 1) + 3] <- "Q" do {
40 CHAPTER 2. STRUCTURES

write(" ", line, “\n ", border)


}
write()
end

2.6 Summary

Unicon's structures are better than sliced bread. To be fair, this is because Icon's inventors
really got things right. These structures are the foundations of complex algorithms and the
glue that builds sophisticated data models. They are every computer scientists' buzzword-
compliant best friends: polymorphic, heterogeneous, implicitly referenced, cycle-capable,
dynamically represented, and automatically reclaimed. They provide a direct implemen-
tation of the common information associations used in object-oriented design. But most
important of all, they are extremely simple to learn and use.
Exploring the Variety of Random
Documents with Different Content
Families S p h æ r o c a p s i d a , D o r a t a s p i d a et
P h r a c to p e lt i d a .

PLATE 133.

N.B.—The signification of the


characters is the same in all the
figures (compare p. 718).
a. Northern polar spines.
b. Northern tropical spines.
c. Equatorial spines.
d. Southern tropical spines.
e. Southern polar spines.

Sphærocapsida, Dorataspida et
Phractopeltida.
Diam. Page.

Fig. 1.
Phractopelta
dorataspis, n.
sp., × 300 852

Fig. 2. Dorypelta
tessaraspis, n.
sp., × 300 858

Fig. 3.
Stauropelta
cruciata, n. sp., × 400 859
Fig. 4.
Pantopelta
icosaspis, n. sp., × 400 855
Meridional
section through
the double
shell.

Fig. 5. Octopelta
scutella, n. sp., × 400 856
Proximal part of
two meeting
spines,
isolated.

Fig. 6.
Orophaspis
furcata, n. sp., × 400 818

Fig. 7. Porocapsa
murrayana, n.
sp., × 300 800
The central
capsule is filled
up by spherical
vacuoles and
enclosed by
the porous
shell; in the
centre radii of
small granules
(nuclei ?)
occur.

Fig. 8. × 300 801


Cannocapsa
stethoscopium,
n. sp.,
The shell alone.

Fig. 9.
Astrocapsa
coronata, n. sp., × 400 799
Middle part of
one spine with
the four
aspinal holes.
Fig. 9a.
Transverse
section of a
radial spine,
with the four
surrounding
aspinal holes
and the
neighbouring
part of the
shell, × 400

Fig. 10.
Astrocapsa
stellata, n. sp., × 400 799
Part of one spine,
with the
aspinal holes
and their four
triangular
teeth.

Fig. 11.
Cenocapsa
nirvana, n. sp., × 200 802
The entire shell,
with its
pavement of
small plates
and the twenty
cruciform
perspinal
holes.
Fig. 11a. A group
of small ovate
plates which
compose the
shell; in each
plate a dimple
with a porule, × 400
Fig. 11b. A
cruciform
perspinal hole,
seen from the
face, × 400
Fig. 11c. A
cruciform
perspinal hole,
with its four
teeth, seen in
profile, × 400

PLATE 134.

Legion A C A N T H A R I A .

Order SPHÆROPHRACTA.

Family D o r a t a s p i d a .
PLATE 134.

N.B.—The signification of the


characters is the same in all the
figures (compare p. 718).
a. Northern polar spines.
b. Northern tropical spines.
c. Equatorial spines.
d. Southern tropical spines.
e. Southern polar spines.

Dorataspida.
Diam. Page.

Fig. 1.
Dodecaspis
tricincta, n. sp., × 400 834
The enclosed
central capsule
contains
numerous
spherical
nuclei.

Fig. 2.
Lychnaspis
minima, n. sp., × 400 841
Six-sided basal
pyramid of an
equatorial
spine, with the
leaf-cross, seen
from the
centre.
Fig. 3. Zonaspis
cingulata, n. sp., × 400 834
Equatorial section
through the
central
capsule. n,
nuclei; g,
yellow bodies
(intracapsular
xanthellæ).

Fig. 4. Zonaspis
cingulata, n. sp., × 800 834
Central pyramidal
base of an
equatorial
spine, with the
leaf-cross.

Fig. 5. Stauraspis
cruciata, n. sp., × 400 831
Central union of
the radial
spines, three
polar spines
being taken
off.

Fig. 6.
Lychnaspis
longissima, n.
sp., × 400 841

Fig. 7.
Lychnaspis
minima, n. sp., × 400 841
Five-sided basal
pyramid of a
tropical spine,
with the leaf-
cross, seen
from the
centre.

Fig. 8.
Lychnaspis
minima, n. sp., × 400 841
Six-sided basal
pyramid of a
polar spine,
with the leaf-
cross, seen
from the
centre.

Fig. 9. Icosaspis
elegans, n. sp., × 400 844
An isolated polar
plate.

Fig. 10. Icosaspis


cruciata, n. sp., × 400 844
An isolated
equatorial
plate.

Fig. 11, 12.


Dorataspis
species, × 100
Diagram of the
composition of
the shell of
twenty plates
(and also of
the central
union of the
basal leaf-
cross).
Fig. 11. Oblique
equatorial
aspect.
Fig. 12. Accurate
polar aspect
(compare p.
804, 805).

Fig. 13.
Coscinaspis
isopora, n. sp., × 400 828
An isolated
equatorial plate
(with two
aspinal and six
coronal pores).

Fig. 14.
Coscinaspis
isopora, n. sp., × 400 828
Two isolated
tropical plates
(b, northern; d,
southern),
each with two
aspinal and
five coronal
pores.

Fig. 15.
Diporaspis
nephropora, n.
sp., × 400 816

Fig. 16. × 400 829


Acontaspis
hastata, n. sp.,

PLATE 135.

Legion ACANTHARIA.

Order SPHÆROPHRACTA.

Families S p h æ r o c a p s i d a et D o r a t a s p i d a .

PLATE 135.

N.B.—The signification of the


characters is the same in all the
figures (compare p. 718).
a. Northern polar spines.
b. Northern tropical spines.
c. Equatorial spines.
d. Southern tropical spines.
e. Southern polar spines.

Sphærocapsida et Dorataspida.
Diam. Page.

Fig. 1. Hylaspis
serrulata, n. sp., × 300 846
Fig. 2.
Lychnaspis
undulata, n. sp., × 400 841

Fig. 3.
Lychnaspis
giltschii, n. sp., × 400 839
The spherical
central capsule
is enclosed in
the shell.

Fig. 4.
Lychnaspis
rottenburgii, n.
sp., × 400 841

Fig. 5. Zonaspis
æquatorialis, n.
sp., × 300 834

Fig. 6.
Sphærocapsa
cruciata, n. sp., × 150 798
The entire shell,
with its twenty
cruciate
perspinal
holes.

Fig. 7.
Sphærocapsa
cruciata, n. sp., × 800 798
Insertion of one
spine in the
cruciate
perspinal hole
of the shell.

Fig. 8.
Sphærocapsa
quadrata, n. sp., × 800 798
A group of pores
and dimples in
the shell
surface.

Fig. 9.
Sphærocapsa
dentata, n. sp., × 800 798
Insertion of one
spine in the
cruciate
perspinal hole
of the shell.

Fig. 10.
Sphærocapsa
pavimentata, n.
sp., × 800 798
Insertion of one
spine in the
perspinal hole
of the shell,
which is
composed of
four cruciate
aspinal holes
and
surrounded by
a group of
dimples and
pores.
PLATE 136.

Legion ACANTHARIA.

Orders SPHÆROPHRACTA et PRUNOPHRACTA.

Families D o r a t a s p i d a et B e l o n a s p i d a .

PLATE 136.

N.B.—The signification of the


characters is the same in all the
figures (compare p. 718).
a. Northern polar spines.
b. Northern tropical spines.
c. Equatorial spines.
d. Southern tropical spines.
e. Southern polar spines.

Dorataspida et Belonaspida.
Diam. Page.

Fig. 1.
Tessaraspis
arachnoides, n.
sp., × 300 836

Fig. 2. Icosaspis
tabulata, n. sp., × 200 843
Fig. 3. Icosaspis
icosastaura, n.
sp., × 400 846

Fig. 4. Icosaspis
elegans, n. sp., × 300 844

Fig. 5.
Tessaraspis
concreta, n. sp., × 400 838

Fig. 6.
Phatnaspis
cristata, n. sp., × 400 869

Fig. 7.
Phatnaspis
haliommidium,
n. sp., × 200 871
Central capsule
within the
shell—outline.

Fig. 8.
Coscinaspis
polypora, n. sp., × 300 827
A single lattice-
plate of the
shell.

Fig. 9.
Phatnaspis
lacunaria, n. sp., × 400 869
PLATE 137.

Legion ACANTHARIA.

Order SPHÆROPHRACTA.

Family D o r a t a s p i d a .

PLATE 137.

N.B.—The signification of the characters


is the same in all the figures (compare
p. 718).
a. Northern polar spines.
b. Northern tropical spines.
c. Equatorial spines.
d. Southern tropical spines.
e. Southern polar spines.

Dorataspida.
Diam. Page.

Fig. 1. Phractaspis
complanata, n. sp., × 400 809

Fig. 2. Phractaspis
prototypus, n. sp., × 400 809

Fig. 3. Phractaspis
constricta, n. sp., × 400 810

Fig. 4. Pleuraspis
horrida, n. sp., × 400 811

Fig. 5. Stauruspis
stauracantha, n. sp., × 300 832

Fig. 6. Stauruspis
stauracantha, n. sp., × 600 832
A single spine.

Fig. 7. Echinaspis
echinoides, n. sp., × 300 833

Fig. 8. Echinaspis
echinoides, n. sp., × 800 833
A single spine.

Fig. 9. Coscinaspis
parmipora, n. sp., × 400 827

PLATE 138.

Legion ACANTHARIA.

Order SPHÆROPHRACTA.

Family D o r a t a s p i d a .

PLATE 138.

N.B.—The signification of the characters


is the same in all the figures (compare
p. 718).
a. Northern polar spines.
b. Northern tropical spines.
c. Equatorial spines.
d. Southern tropical spines.
e. Southern polar spines.

Dorataspida.
Diam. Page.

Fig. 1. Coscinaspis × 300 826


peripora (vel Dorataspis
peripora), n. sp.,

Fig. 2. Dorataspis
fusigera, n. sp., × 400 813

Fig. 3. Dorataspis
micropora, n. sp., × 300 815

Fig. 4. Dorataspis typica,


n. sp., × 300 815

Fig. 4a. Polar view of the


central union of the
twenty spines, × 300 815

Fig. 5. Ceriaspis inermis,


n. sp., × 400 821

Fig. 6. Ceriaspis favosa,


n. sp., × 400 821

Fig. 7. Hystrichaspis
fruticata, n. sp., × 300 825

Fig. 8. Hystrichaspis
pectinata, n. sp., × 300 822

Fig. 9. Hystrichaspis
furcata, n. sp., × 400 822

Fig. 10. Hystrichaspis


dorsata, n. sp., × 300 823

Fig. 11. Hystrichaspis


cristata (vel Siphonaspis
cristata, n. sp.), × 400 823

PLATE 139.

Legion ACANTHARIA.

Order PRUNOPHRACTA.
Families B e l o n a s p i d a et H e x a l s p i d a .

PLATE 139.

N.B.—The signification of the characters


is the same in all the figures (compare
p. 718).
a. Northern polar spines.
b. Northern tropical spines.
c. Equatorial spines.
d. Southern tropical spines.
e. Southern polar spines.

Belonaspida et Hexalspida.
Diam. Page.

Fig. 1. Hexacolpus nivalis,


n. sp., × 300 880

Fig. 2. Hexalaspis
heliodiscus, n. sp., × 300 875

Fig. 3. Hexaconus
ciliatus, n. sp., × 300 876

Fig. 4. Hexaconus
serratus, n. sp., × 300 877
c, Central base of an
equatorial spine; d,
central base of a tropical
spine.

Fig. 5. Hexaconus
coronatus, n. sp., × 300 877

Fig. 6. Hexaconus
velatus, n. sp., × 300 877
Marginal view of the shell.

Fig. 7. Hexaconus
vaginatus, n. sp., × 300 877
Fig. 8. Thoracaspis
bipennis, n. sp., × 300 862

Fig. 9. Belonaspis datura,


n. sp., × 400 863

PLATE 140.

Legion ACANTHARIA.

Order PRUNOPHRACTA.

Families B e l o n a s p i d a , H e x a l a s p i d a et D i p l o c o n i d a .

PLATE 140.

N.B.—The signification of the characters


is the same in all the figures (compare
p. 718).
a. Northern polar spines.
b. Northern tropical spines.
c. Equatorial spines.
d. Southern tropical spines.
e. Southern polar spines.

Belonaspida, Hexalaspida et Diploconida.


Diam. Page.

Fig. 1. Diploconus
amalla, n. sp., × 300 885

Fig. 2. Diploconus
hexaphyllus, n. sp., × 300 886

Fig. 3. Diploconus
cyathiscus, n. sp., × 300 885
Fig. 4. Diploconus
cotyliscus, n. sp., × 400 886
Polar view.

Fig. 5. Diplocolpus
serratus, n. sp., × 300 888

Fig. 6. Diplocolpus
cristatus, n. sp., × 400 887

Fig. 7. Diplocolpus
costatus, n. sp., × 400 887

Fig. 8. Diplocolpus
sulcatus, n. sp., × 300 888

Fig. 9. Diplocolpus
dentatus, n. sp., × 300 888
Meridional section through
the centre of the shell.

Fig. 10. Hexacolpus


infundibulum, n. sp., × 300 881

Fig. 11. Hexacolpus


trypanon, n. sp., × 300 881

Fig. 12. Hexaconus


echinatus, n. sp., × 300 878

Fig. 13. Coleaspis


vaginata, n. sp., × 300 866
Meridional section through
the shell.

Fig. 14. Coleaspis


hydrotomica, n. sp., × 400 867

Fig. 15. Hexonaspis


hexapleura, n. sp., × 400 879
A single spine with its
thick apophyses.

Fig. 16. Hexonaspis


hastata, n. sp., × 400 879
*** END OF THE PROJECT GUTENBERG EBOOK REPORT ON THE
RADIOLARIA COLLECTED BY H.M.S. CHALLENGER DURING THE
YEARS 1873-1876, PLATES ***

Updated editions will replace the previous one—the old editions will
be renamed.

Creating the works from print editions not protected by U.S.


copyright law means that no one owns a United States copyright in
these works, so the Foundation (and you!) can copy and distribute it
in the United States without permission and without paying
copyright royalties. Special rules, set forth in the General Terms of
Use part of this license, apply to copying and distributing Project
Gutenberg™ electronic works to protect the PROJECT GUTENBERG™
concept and trademark. Project Gutenberg is a registered trademark,
and may not be used if you charge for an eBook, except by following
the terms of the trademark license, including paying royalties for use
of the Project Gutenberg trademark. If you do not charge anything
for copies of this eBook, complying with the trademark license is
very easy. You may use this eBook for nearly any purpose such as
creation of derivative works, reports, performances and research.
Project Gutenberg eBooks may be modified and printed and given
away—you may do practically ANYTHING in the United States with
eBooks not protected by U.S. copyright law. Redistribution is subject
to the trademark license, especially commercial redistribution.

START: FULL LICENSE


THE FULL PROJECT GUTENBERG LICENSE
PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS
WORK

To protect the Project Gutenberg™ mission of promoting the free


distribution of electronic works, by using or distributing this work (or
any other work associated in any way with the phrase “Project
Gutenberg”), you agree to comply with all the terms of the Full
Project Gutenberg™ License available with this file or online at
www.gutenberg.org/license.

Section 1. General Terms of Use and


Redistributing Project Gutenberg™
electronic works
1.A. By reading or using any part of this Project Gutenberg™
electronic work, you indicate that you have read, understand, agree
to and accept all the terms of this license and intellectual property
(trademark/copyright) agreement. If you do not agree to abide by all
the terms of this agreement, you must cease using and return or
destroy all copies of Project Gutenberg™ electronic works in your
possession. If you paid a fee for obtaining a copy of or access to a
Project Gutenberg™ electronic work and you do not agree to be
bound by the terms of this agreement, you may obtain a refund
from the person or entity to whom you paid the fee as set forth in
paragraph 1.E.8.

1.B. “Project Gutenberg” is a registered trademark. It may only be


used on or associated in any way with an electronic work by people
who agree to be bound by the terms of this agreement. There are a
few things that you can do with most Project Gutenberg™ electronic
works even without complying with the full terms of this agreement.
See paragraph 1.C below. There are a lot of things you can do with
Project Gutenberg™ electronic works if you follow the terms of this
agreement and help preserve free future access to Project
Gutenberg™ electronic works. See paragraph 1.E below.
1.C. The Project Gutenberg Literary Archive Foundation (“the
Foundation” or PGLAF), owns a compilation copyright in the
collection of Project Gutenberg™ electronic works. Nearly all the
individual works in the collection are in the public domain in the
United States. If an individual work is unprotected by copyright law
in the United States and you are located in the United States, we do
not claim a right to prevent you from copying, distributing,
performing, displaying or creating derivative works based on the
work as long as all references to Project Gutenberg are removed. Of
course, we hope that you will support the Project Gutenberg™
mission of promoting free access to electronic works by freely
sharing Project Gutenberg™ works in compliance with the terms of
this agreement for keeping the Project Gutenberg™ name associated
with the work. You can easily comply with the terms of this
agreement by keeping this work in the same format with its attached
full Project Gutenberg™ License when you share it without charge
with others.

1.D. The copyright laws of the place where you are located also
govern what you can do with this work. Copyright laws in most
countries are in a constant state of change. If you are outside the
United States, check the laws of your country in addition to the
terms of this agreement before downloading, copying, displaying,
performing, distributing or creating derivative works based on this
work or any other Project Gutenberg™ work. The Foundation makes
no representations concerning the copyright status of any work in
any country other than the United States.

1.E. Unless you have removed all references to Project Gutenberg:

1.E.1. The following sentence, with active links to, or other


immediate access to, the full Project Gutenberg™ License must
appear prominently whenever any copy of a Project Gutenberg™
work (any work on which the phrase “Project Gutenberg” appears,
or with which the phrase “Project Gutenberg” is associated) is
accessed, displayed, performed, viewed, copied or distributed:
This eBook is for the use of anyone anywhere in the United
States and most other parts of the world at no cost and with
almost no restrictions whatsoever. You may copy it, give it
away or re-use it under the terms of the Project Gutenberg
License included with this eBook or online at
www.gutenberg.org. If you are not located in the United
States, you will have to check the laws of the country where
you are located before using this eBook.

1.E.2. If an individual Project Gutenberg™ electronic work is derived


from texts not protected by U.S. copyright law (does not contain a
notice indicating that it is posted with permission of the copyright
holder), the work can be copied and distributed to anyone in the
United States without paying any fees or charges. If you are
redistributing or providing access to a work with the phrase “Project
Gutenberg” associated with or appearing on the work, you must
comply either with the requirements of paragraphs 1.E.1 through
1.E.7 or obtain permission for the use of the work and the Project
Gutenberg™ trademark as set forth in paragraphs 1.E.8 or 1.E.9.

1.E.3. If an individual Project Gutenberg™ electronic work is posted


with the permission of the copyright holder, your use and distribution
must comply with both paragraphs 1.E.1 through 1.E.7 and any
additional terms imposed by the copyright holder. Additional terms
will be linked to the Project Gutenberg™ License for all works posted
with the permission of the copyright holder found at the beginning
of this work.

1.E.4. Do not unlink or detach or remove the full Project


Gutenberg™ License terms from this work, or any files containing a
part of this work or any other work associated with Project
Gutenberg™.

1.E.5. Do not copy, display, perform, distribute or redistribute this


electronic work, or any part of this electronic work, without
prominently displaying the sentence set forth in paragraph 1.E.1
with active links or immediate access to the full terms of the Project
Gutenberg™ License.

1.E.6. You may convert to and distribute this work in any binary,
compressed, marked up, nonproprietary or proprietary form,
including any word processing or hypertext form. However, if you
provide access to or distribute copies of a Project Gutenberg™ work
in a format other than “Plain Vanilla ASCII” or other format used in
the official version posted on the official Project Gutenberg™ website
(www.gutenberg.org), you must, at no additional cost, fee or
expense to the user, provide a copy, a means of exporting a copy, or
a means of obtaining a copy upon request, of the work in its original
“Plain Vanilla ASCII” or other form. Any alternate format must
include the full Project Gutenberg™ License as specified in
paragraph 1.E.1.

1.E.7. Do not charge a fee for access to, viewing, displaying,


performing, copying or distributing any Project Gutenberg™ works
unless you comply with paragraph 1.E.8 or 1.E.9.

1.E.8. You may charge a reasonable fee for copies of or providing


access to or distributing Project Gutenberg™ electronic works
provided that:

• You pay a royalty fee of 20% of the gross profits you derive
from the use of Project Gutenberg™ works calculated using the
method you already use to calculate your applicable taxes. The
fee is owed to the owner of the Project Gutenberg™ trademark,
but he has agreed to donate royalties under this paragraph to
the Project Gutenberg Literary Archive Foundation. Royalty
payments must be paid within 60 days following each date on
which you prepare (or are legally required to prepare) your
periodic tax returns. Royalty payments should be clearly marked
as such and sent to the Project Gutenberg Literary Archive
Foundation at the address specified in Section 4, “Information
about donations to the Project Gutenberg Literary Archive
Foundation.”

• You provide a full refund of any money paid by a user who


notifies you in writing (or by e-mail) within 30 days of receipt
that s/he does not agree to the terms of the full Project
Gutenberg™ License. You must require such a user to return or
destroy all copies of the works possessed in a physical medium
and discontinue all use of and all access to other copies of
Project Gutenberg™ works.

• You provide, in accordance with paragraph 1.F.3, a full refund of


any money paid for a work or a replacement copy, if a defect in
the electronic work is discovered and reported to you within 90
days of receipt of the work.

• You comply with all other terms of this agreement for free
distribution of Project Gutenberg™ works.

1.E.9. If you wish to charge a fee or distribute a Project Gutenberg™


electronic work or group of works on different terms than are set
forth in this agreement, you must obtain permission in writing from
the Project Gutenberg Literary Archive Foundation, the manager of
the Project Gutenberg™ trademark. Contact the Foundation as set
forth in Section 3 below.

1.F.

1.F.1. Project Gutenberg volunteers and employees expend


considerable effort to identify, do copyright research on, transcribe
and proofread works not protected by U.S. copyright law in creating
the Project Gutenberg™ collection. Despite these efforts, Project
Gutenberg™ electronic works, and the medium on which they may
be stored, may contain “Defects,” such as, but not limited to,
incomplete, inaccurate or corrupt data, transcription errors, a
copyright or other intellectual property infringement, a defective or
damaged disk or other medium, a computer virus, or computer
codes that damage or cannot be read by your equipment.

1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for


the “Right of Replacement or Refund” described in paragraph 1.F.3,
the Project Gutenberg Literary Archive Foundation, the owner of the
Project Gutenberg™ trademark, and any other party distributing a
Project Gutenberg™ electronic work under this agreement, disclaim
all liability to you for damages, costs and expenses, including legal
fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR
NEGLIGENCE, STRICT LIABILITY, BREACH OF WARRANTY OR
BREACH OF CONTRACT EXCEPT THOSE PROVIDED IN PARAGRAPH
1.F.3. YOU AGREE THAT THE FOUNDATION, THE TRADEMARK
OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL
NOT BE LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT,
CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES EVEN IF
YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGE.

1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you


discover a defect in this electronic work within 90 days of receiving
it, you can receive a refund of the money (if any) you paid for it by
sending a written explanation to the person you received the work
from. If you received the work on a physical medium, you must
return the medium with your written explanation. The person or
entity that provided you with the defective work may elect to provide
a replacement copy in lieu of a refund. If you received the work
electronically, the person or entity providing it to you may choose to
give you a second opportunity to receive the work electronically in
lieu of a refund. If the second copy is also defective, you may
demand a refund in writing without further opportunities to fix the
problem.

1.F.4. Except for the limited right of replacement or refund set forth
in paragraph 1.F.3, this work is provided to you ‘AS-IS’, WITH NO
OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR ANY PURPOSE.

1.F.5. Some states do not allow disclaimers of certain implied


warranties or the exclusion or limitation of certain types of damages.
If any disclaimer or limitation set forth in this agreement violates the
law of the state applicable to this agreement, the agreement shall be
interpreted to make the maximum disclaimer or limitation permitted
by the applicable state law. The invalidity or unenforceability of any
provision of this agreement shall not void the remaining provisions.

1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation,


the trademark owner, any agent or employee of the Foundation,
anyone providing copies of Project Gutenberg™ electronic works in
accordance with this agreement, and any volunteers associated with
the production, promotion and distribution of Project Gutenberg™
electronic works, harmless from all liability, costs and expenses,
including legal fees, that arise directly or indirectly from any of the
following which you do or cause to occur: (a) distribution of this or
any Project Gutenberg™ work, (b) alteration, modification, or
additions or deletions to any Project Gutenberg™ work, and (c) any
Defect you cause.

Section 2. Information about the Mission


of Project Gutenberg™
Project Gutenberg™ is synonymous with the free distribution of
electronic works in formats readable by the widest variety of
computers including obsolete, old, middle-aged and new computers.
It exists because of the efforts of hundreds of volunteers and
donations from people in all walks of life.

Volunteers and financial support to provide volunteers with the


assistance they need are critical to reaching Project Gutenberg™’s
goals and ensuring that the Project Gutenberg™ collection will
remain freely available for generations to come. In 2001, the Project
Gutenberg Literary Archive Foundation was created to provide a
secure and permanent future for Project Gutenberg™ and future
generations. To learn more about the Project Gutenberg Literary
Archive Foundation and how your efforts and donations can help,
see Sections 3 and 4 and the Foundation information page at
www.gutenberg.org.

Section 3. Information about the Project


Gutenberg Literary Archive Foundation
The Project Gutenberg Literary Archive Foundation is a non-profit
501(c)(3) educational corporation organized under the laws of the
state of Mississippi and granted tax exempt status by the Internal
Revenue Service. The Foundation’s EIN or federal tax identification
number is 64-6221541. Contributions to the Project Gutenberg
Literary Archive Foundation are tax deductible to the full extent
permitted by U.S. federal laws and your state’s laws.

The Foundation’s business office is located at 809 North 1500 West,


Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up
to date contact information can be found at the Foundation’s website
and official page at www.gutenberg.org/contact

Section 4. Information about Donations to


the Project Gutenberg Literary Archive
Foundation
Project Gutenberg™ depends upon and cannot survive without
widespread public support and donations to carry out its mission of
increasing the number of public domain and licensed works that can
be freely distributed in machine-readable form accessible by the
widest array of equipment including outdated equipment. Many
small donations ($1 to $5,000) are particularly important to
maintaining tax exempt status with the IRS.

The Foundation is committed to complying with the laws regulating


charities and charitable donations in all 50 states of the United
States. Compliance requirements are not uniform and it takes a
considerable effort, much paperwork and many fees to meet and
keep up with these requirements. We do not solicit donations in
locations where we have not received written confirmation of
compliance. To SEND DONATIONS or determine the status of
compliance for any particular state visit www.gutenberg.org/donate.

While we cannot and do not solicit contributions from states where


we have not met the solicitation requirements, we know of no
prohibition against accepting unsolicited donations from donors in
such states who approach us with offers to donate.

International donations are gratefully accepted, but we cannot make


any statements concerning tax treatment of donations received from
outside the United States. U.S. laws alone swamp our small staff.

Please check the Project Gutenberg web pages for current donation
methods and addresses. Donations are accepted in a number of
other ways including checks, online payments and credit card
donations. To donate, please visit: www.gutenberg.org/donate.

Section 5. General Information About


Project Gutenberg™ electronic works
Professor Michael S. Hart was the originator of the Project
Gutenberg™ concept of a library of electronic works that could be
freely shared with anyone. For forty years, he produced and
distributed Project Gutenberg™ eBooks with only a loose network of
volunteer support.
Project Gutenberg™ eBooks are often created from several printed
editions, all of which are confirmed as not protected by copyright in
the U.S. unless a copyright notice is included. Thus, we do not
necessarily keep eBooks in compliance with any particular paper
edition.

Most people start at our website which has the main PG search
facility: www.gutenberg.org.

This website includes information about Project Gutenberg™,


including how to make donations to the Project Gutenberg Literary
Archive Foundation, how to help produce our new eBooks, and how
to subscribe to our email newsletter to hear about new eBooks.
back
back
back
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.

More than just a book-buying platform, we strive to be a bridge


connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.

Join us on a journey of knowledge exploration, passion nurturing, and


personal growth every day!

ebookbell.com

You might also like