Naming and Logic
programming essentials with Wisp (WIP)
This article is a start of a text teaching programming basics with Wisp. It is a work in process. The tour starts from scratch and teaches in examples with minimal explanation. It’s core is a map of the minimal functionality you need from Scheme to write meaningful programs.
Currently it only contains entries for parts of the map. Each entry in the map will be fleshed out as I get to it. That may take weeks, months, or years, depending on whether and when it grips me to finally type down what I already have in my analog notebook.
I’d have loved to publish it only once all is written, but I considered it more important to get this into the open.
I hope that one day it will be interactive, using Guile on wasm (which is currently being built by the folks at Spritely).
To follow along, install Wisp and try the examples as you read.
The Map of Scheme
(How to make such a map? See Org Mode Tipp: imagemap)
Naming a value: define
Use define to name a value. Use .
to return a value.
define small-tree-height-meters 3 define large-tree-height-meters 5 . small-tree-height-meters
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = 3
You should see
$1 = 3
This means: the first returned value ($1
) is 3. The next time you
return a value, it will be called $2
.
Names can contain any letter except for space, quote, comma or parentheses. They must not be numbers.
define illegal name 1 define 'illegal-name 2 define ,illegal-name 3 define illegal)name 4 define 1113841 5
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. While compiling expression: Syntax error: unknown location: source expression failed to match any pattern in form (define illegal name 1) While reading expression: #<unknown port>:4:16: unexpected ")"
Use logic with numbers
= 3 5
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #f
= 3 3
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
#t
means true, #f
means false.
Returns the result of logic without needing a period (.
).
The logic comes first. This is clear for =
, but easy to misread for >
.
Use logic with infix
. {3 = 5}
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #f
Infix logic gives a value, so you need .
to return it.
Because infix-logic gives a value, you can use it in place of a value.
For example to nest it:
. {{5 < 3} equal? #f}
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
Or to name it as value:
define is-math-sane? {3 < 5} . is-math-sane?
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
By convention, names that have the value true
or false
have the suffix ?
.
Use logic with names
define small-tree-h/m 3 define large-tree-h/m 5 . {small-tree-h/m < large-tree-h/m}
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
Logic with true and false
and #t #t
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
and #f #t #t
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #f
If any logical value passed to and
is #false
, further values are not checked.
or #f #f #t
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
Or checks whether any value is #t.
and #t #t #t ;; => #true and #t #f #t ;; => #false and {3 < 5} {5 < 3} ;; => #false or #t #f #t ;; => true or {3 < 5} {5 < 3} ;; => #true or #f #f #f ;; => #false
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t $2 = #f $3 = #f $4 = #t $5 = #t $6 = #f
Calling or
only looks at values until it sees a single #t
. It it finds no #t
, it returns #f
.
For and
and or
, everything is #true
(#t
) except for #false
(#f
).
Looking at the number of hard to trace errors in other languages that
turn up in production, this is the only sane policy.
Name the result of logic with indentation
define birch-h/m 3 define chestnut-h/m 5 define same-héight? = birch-h/m chestnut-h/m define smaller? . {birch-h/m < chestnut-h/m} . smaller?
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
The infix directly gives a value, so it needs the .
as prefix to
return the value instead of trying to call the value as logic.
Name logic with define :
define : same-heigth? tree-height-a tree-height-b = tree-height-a tree-height-b same-height? 3 3
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. ice-9/boot-9.scm:1676:22: In procedure raise-exception: Unbound variable: same-height? Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.
By convention, logic that returns true or false has the suffix ?
.
You can now use your named logic like all other logic. Even with infix.
define : same-height? tree-height-a tree-height-b = tree-height-a tree-height-b . {3 same-height? 3}
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
What this map of Scheme calls named logic is commonly called
function
or procedure
. We’ll stick with logic for the sake of
a leaner conceptual mapping.
The indented lines that define the named logic are called the body.
Name a name in define with .
define small-tree-height-meters 3 define height . small-tree-height-meters . height
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = 3
.
returns the value of its line.
Return the value of logic with .
define : larger-than-4? size . {size > 4} . larger-than-4?
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #<procedure larger-than-4? (size)>
The value of logic defined with define :
is a procedure
. You can
see the arguments in the output: If you call it with too few or too
many arguments, you get warnings.
There are other kinds of logic: syntax rules and reader-macros. We
will cover syntax rules later. New reader macros are rarely needed;
using {...}
for infix math is a reader macro.
Name in define with define
define birch-h/m 3 define : birch-is-small define reference-h/m 4 . { birch-h/m < reference-h/m } birch-is-small
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
Only the last part is returned.
Note the .
in front of the { birch-h/m < reference-h/m }
: a
calculation inside braces is executed in-place, so its value needs to
be returned.
Name the result of logic in one line with :
or ()
define birch-h/m 3 define chestnut-h/m 5 define same-height : = birch-h/m chestnut-h/m . same-height define same-height-again (= birch-h/m chestnut-h/m) . same-height-again
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #f $2 = #f
This is consistent with infix-math:
define birch-h/m 3 define chestnut-h/m 5 define same-height {birch-h/m = chestnut-h/m} . same-height
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #f
Add comments with ;
define birch-h/m 3 ;; this is a comment define height ;; comment at the end ;; comment between lines . birch-h/m . height
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = 3
It is common to use ;;
instead of ;
, but not required.
Editors support this style.
Name text with "
define tree-description "large tree" define footer "In Love, Arne" define greeting . "Hello" display footer
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. In Love, Arne
Like { }
, text (called string
as in “string of characters”) is its
value.
Text can span multiple lines. Line breaks in text do not affect code logic.
You can use \n
to add a line break within text without having a
visual line break. The backslash (\
) is the escape character and
\n
represents a line break. To type a real \
within quotes ( "
), you must escape it as \\
.
Return the value with .
to name text
with indentation.
With display
you can show text as it will look in an editor.
Text is stronger than comments:
define with-comment ;; belongs to coment ;; comment . "Hello ;; part of the text" . with-comment
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = "Hello ;; part of the text"
Take decisions with cond
define chestnut-h/m 5 define tree-description cond {chestnut-h/m > 4} . "large tree" else . "small tree" . tree-description
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = "large tree"
When it comes to cond
, everything is #true
(#t
) except for #false
(#f
).
The cond
checks its clauses one by one in their order and uses only
the first that has the value #true
.
cond 5 . #t else . #f
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
cond #f . #f else . #t
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
Use fine-grained numbers with number-literals
define more-precise-height 5.32517 define 100-meters 1e2 . more-precise-height . 100-meters
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = 5.32517 $2 = 100.0
These are floating point numbers. They store approximate values in 64 bit binary, depending on the platform. Read all the details in the Guile Reference manual Real and Rational Numbers, the r5rs numbers, and IEEE 754.
Use exact numbers with #e
and quotients
define exactly-1/5 #e0.2 define exactly-1/5-too 1/5 . exactly-1/5 . exactly-1/5-too
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = 1/5 $2 = 1/5
Guile computations with exact numbers stay reasonably fast even for unreasonably large or small numbers.
See inexact value of exact number with exact->inexact
exact->inexact #e0.2 exact->inexact 1/5 exact->inexact 2e7
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = 0.2 $2 = 0.2 $3 = 2.0e7
The inverse is inexact->exact
:
inexact->exact 0.5
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = 1/2
Note that a regular 0.2
need not be exactly 1/5
, because floating
point numbers do not have exact representation for that. You’ll need
#e
to have precise 0.2
.
inexact->exact 0.2 . #e0.2
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = 3602879701896397/18014398509481984 $2 = 1/5
Use math with the usual operators as logic
define one-hundred * 10 10 define half-hundred : / one-hundred 2 . half-hundred
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = 50
Remember that names cannot be valid numbers!
define 100 ;; error! * 10 10
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. While compiling expression: Syntax error: unknown location: source expression failed to match any pattern in form (define 100 (* 10 10))
Change the value or logic of a defined name with set!
define birch-h/m 3 set! birch-h/m 3.74 . birch-h/m
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = 3.74
It is customary to suffix named logic that changes values of existing names with !
.
Since logic can cause changes to names and not just return a result,
it is not called function
, but procedure
in documentation; proc
for brevity.
Create nameless logic with lambda
define : is-same-height? a b > a b ;; <- this is a mistake . is-same-height? is-same-height? 3 3 define : fixed a b = a b set! is-same-height? fixed . is-same-height? is-same-height? 3 3 ;; shorter and avoiding name pollution and confusion. set! is-same-height? lambda : a b = a b ;; must be on a new line ;; to not be part of the arguments. . is-same-height? is-same-height? 3 3
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #<procedure is-same-height? (a b)> $2 = #f $3 = #<procedure fixed (a b)> $4 = #t $5 = #<procedure is-same-height? (a b)> $6 = #t
The return value of lambda
is logic (a procedure
).
Logic knows the name it has been defined as, except if it is defined
via lambda
.
lambda
is a special form. Think of it as define : name arguments
,
but without the name.
Return list of values with list
list 3 5 define known-heights list 3 3.75 5 100 . known-heights
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = (3 5) $2 = (3 3.75 5 100)
You can put values on their own lines by returning their value: .
returns all the values in its line. Different from define :
, list keeps
all values, not just the last.
define known-heights-2 list 3 . 3.75 5 . 100 define known-heights-3 list . 3 . 3.75 . 5 . 100 define : last-height . 3 3.75 5 100 = 100 : last-height
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
Compare structural values with equal?
{{{known-heights}}} {{{known-heights2}}} = 3 3 3 equal? known-heights known-heights-2 known-heights-3
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = (3 5) $2 = (3 3.75 5 100) $3 = #t $4 = #t $5 = #t
Like =
and +
, equal?
can be used on arbitrary numbers of values.
Apply logic to a list of values with apply
apply = : list 3 3 equal? = 3 3 apply = list 3 3
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t $2 = #t
Only the last argument of apply is treated as list, so you can give initial arguments:
define a 1 define b 1 apply = a b list 1 1
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
Get the arguments of named logic as list with . args
define : same? heights apply = heights same? : list 1 1 1 same? list 1 1 1 define : same2? . heights apply = heights same2? 1 1 1 same2? . 1 1 1
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t $2 = #t $3 = #t $4 = #t
These are called rest
. Getting them is not an efficiency feature: the list creation is implicit.
You can mix regular arguments and rest
arguments:
define : same? alice bob . rest display : list alice bob rest newline apply = alice bob rest same? 1 1 1 1
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. (1 1 (1 1)) $1 = #t
Remember that apply uses only the last of its arguments as list, in symmetry with . rest
.
Get the result of applying logic to each value in lists with map
define birch-h/m 3 define : same-height-as-birch? height/m = birch-h/m height/m define heights : list 3 3.75 5 100 . heights map same-height-as-birch? . heights map + list 1 2 3 list 3 2 1 map list list 1 2 3 list 3 2 1
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = (3 3.75 5 100) $2 = (#t #f #f #f) $3 = (4 4 4) $4 = ((1 3) (2 2) (3 1))
When operating on multiple lists, it takes one argument from each list. All lists must be the same length.
To remember: apply
extracts the values from its last argument, map
extracts one value from each argument after the first.
Apply logic to each value in lists without keeping the result with for-each
define birch-h/m 3 define has-birch-height #f define : set-true-if-birch-height! height/m cond {birch-h/m = height/m} set! has-birch-height #t define heights : list 3 3.75 5 100 for-each set-true-if-birch-height! heights . has-birch-height
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
Import pre-defined named logic and values with import
import : ice-9 pretty-print srfi :1 lists ;; no space after :. it is part of the name pretty-print list 12 list 34 . 5 6 first : list 1 2 3 ;; 1 second : list 1 2 3 ;; 2 third : list 1 2 3 ;; 3 member 2 : list 1 2 3 ;; list 2 3 => #true
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. (12 (34) 5 6) $1 = 1 $2 = 2 $3 = 3 $4 = (2 3)
Import uses modules which can have multiple components. In the first
import, ice-9
is one component and the second is pretty-print
. In
the second, srfi
is the first component, :1
is the second, and
lists
is the third.
ice-9 is the name for the core extensions of Guile. It’s a play on ice-nine, a fictional perfect seed crystal.
SRFI’s are Scheme Requests For Implementation, portable libraries
built in collaboration between different Scheme implementations. The
ones available in Guile can be found in the Guile reference manual.
More can be found on srfi.schemers.org. They are imported by number
(:1
) and can have a third component with a name, but that’s not
required.
You can use only
to import only specific names.
import : only (srfi :1) first second only (srfi :1) iota first : list 1 2 3 ;; 1 second : list 1 2 3 ;; 2 third : list 1 2 3 ;; error iota 5 ;; list 0 1 2 3 4
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = 1 $2 = 2 ice-9/boot-9.scm:1676:22: In procedure raise-exception: Unbound variable: third Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. $3 = (0 1 2 3 4)
Apply partial procedures with srfi :26 cut
define : plus-3 number + 3 number map plus-3 list 1 2 3 ;; list 4 5 6 import : srfi :26 cut map : cut + 3 <> list 1 2 3 ;; list 4 5 6 map : cut - <> 1 list 1 2 3 ;; list 0 1 2 map : cut - 1 <> list 1 2 3 ;; list 0 -1 -2
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = (4 5 6) $2 = (4 5 6) $3 = (0 1 2) $4 = (0 -1 -2)
Name structured values with define-record-type
import : srfi :9 records define-record-type <tree> make-tree type height-m weight-kg carbon-kg . tree? type tree-type height-m tree-height weight-kg tree-weight carbon-kg tree-carbon define birch-young make-tree "birch" 13 90 45 ;; 10 year, 10cm diameter, define birch-old make-tree "birch" 30 5301 2650 ;; 50 year, 50cm diameter. define birch-weights map tree-weight : list birch-young birch-old . birch-young . birch-old . birch-weights
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #<<tree> type: "birch" height-m: 13 weight-kg: 90 carbon-kg: 45> $2 = #<<tree> type: "birch" height-m: 30 weight-kg: 5301 carbon-kg: 2650> $3 = (90 5301)
Carbon content in birch trees is about 46% to 50.6% of the mass. See forestry commission technical paper 1993.
Height from Waldwissen.
Weight from BaumUndErde.
Get the result of logic inline with parentheses ()
, braces {}
, or colon :
import : srfi :26 cut list 1 2 : + 1 2 . 4 list 1 2 {1 + 2} 4 list 1 2 (+ 1 2) 4 map (cut + 3 <>) : list 1 2 3
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = (1 2 3 4) $2 = (1 2 3 4) $3 = (1 2 3 4) $4 = (4 5 6)
Line breaks and indentation are ignored inside parentheses, except for
the value of strings
.
The operators that need linebreaks are disabled: colon :
and period
.
do not get the value or return it, but the last value is returned
implicitly. This is the default in regular Scheme.
:
needs linebreaks, because it only goes to the end of the line.
.
needs linebreaks, because it only applies at the beginning of the
line (after indentation).
Define derived logical control structures with define-syntax-rule
In usual logic application as done in procedures
, arguments are
evaluated to their return value first.
They evaluate from inside out:
import : ice-9 pretty-print define pp pretty-print ;; for brevity define : hello-printer . args pp "Hello" for-each pp args hello-printer 1 : pp "second" pp "third" . 4 5 ;; prints "second" "third" "Hello" 1 4 5
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. "second" "third" "Hello" 1 #<unspecified> #<unspecified> 4 5
But cond
only evaluates the required branches. It is not a
procedure
, but a syntax rule. Syntax rules evaluate from outside to
inside.
import : ice-9 pretty-print define pp pretty-print ;; for brevity define-syntax-rule : early-printer args ... begin pp "Hello" for-each pp : list args ... early-printer 1 : pp "second" pp "third" . 4 5 ;; prints "Hello" "second" "third" 1 4 5, because the early printer ;; comes first, but list and map are regular procedures.
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. "Hello" "second" "third" 1 #<unspecified> #<unspecified> 4 5
The logic define-syntax-rule
can reorder arguments and pass them to
procedures
and other syntax rules
. It cannot ask for their values
directly, because the names are not evaluated to (return) yalues yet.
It operates on the names and the structure.
Instead of define : name . args
it uses a pattern
define-syntax-rule : name args ...
The ellipsis ...
marks args
as standing for zero or more names. It
must be used with the ellipsis.
The body of define-syntax-rule
must only have one element. The logic
begin
wraps its own body to count as only one element. It returns
the value of the last element in its body.
Get and resolve names used in code with quote
, eval
, and module-ref
list : quote alice quote bob quote carol quote dave ;; => (alice bob carol dave) define alice "the first" eval 'alice : current-module ;; => "the first" module-ref (current-module) 'alice ;; => "the first" ;; module-ref is less powerful than eval. It is usually safer define code quote list 1 2 3 . code ;; => (list 1 2 3) ;; uses parentheses form eval code : current-module ;; => (1 2 3) ' 1 2 3 ;; (1 2 3) list 1 2 3 ;; (1 2 3) equal? : ' 1 2 3 list 1 2 3
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = (alice bob carol dave) $2 = "the first" $3 = "the first" $4 = (list 1 2 3) $5 = (1 2 3) $6 = (1 2 3) $7 = (1 2 3) $8 = #t
The form = is a shorthand to create an *immutable*
list that is =equal?
to ==
But some operations like = from =srfi :1
do not work on immutable lists.
Reuse your logic with let-recursion
Remember the for-each
example:
define has-birch-height #f define : set-true-if-birch-height! height/m define birch-h/m 3 cond {birch-h/m = height/m} set! has-birch-height #t define heights : list 3 3.75 5 100 for-each set-true-if-birch-height! heights . has-birch-height
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
Instead of for-each
, we can build our own iteration:
define : has-birch-height? heights define birch-h/m 3 let loop : : heights heights cond (null? heights) #f : = birch-h/m : car heights ;; car is first . #t else loop : cdr heights define heights : list 3 3.75 5 100 has-birch-height? heights
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #t
null?
asks whether the list is empty. car
gets the first element
of a list, cdr
gets the list without its first element.
Recursion is usually easier to debug (all variable elements are available at the top of the let recursion) and often creates cleaner APIs than iteration.
As rule of thumb: start with the recursion end condition (here:
(null? heights)
and ensure that each branch of the cond
either
ends recursion or moves a step towards finishing (usually with cdr
).
Also see recursion wins.
Extending a list with cons
To build your own map
function which returns a list of results, you
need to add to a list.
cons 1 : list 2 3 ;; => list 1 2 3
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = (1 2 3)
Used for a simplified map
implementation that accepts only a single list:
import : only (srfi :1) first define : single-map proc elements let loop : (changed (list)) (elements elements) cond : null? elements reverse changed else loop ;; add processed first element to changed cons : proc : first elements . changed ;; drop first element from elements cdr elements single-map even? : list 1 2 3 ;; => #f #t #f
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = (#f #t #f)
Document procedures with docstrings
define : documented-proc arg . "Proc is documented" . #f ;; doc must not be last element procedure-documentation documented-proc ;; variables have no docstrings but ;; properties can be set manually. define variable #f set-object-property! variable 'documentation . "Variable is documented" object-property variable 'documentation
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = "Proc is documented" $2 = "Variable is documented" $3 = "Variable is documented"
You can get the documentation with ,d
on the REPL:
,d documented-proc => Proc is documented ,d variable => Variable is documented
For generating documentation from comments, there’s guild doc-snarf
.
;; Proc docs can be snarfed define : snarfed-proc arg . #f ;; Variable docs can be snarfed define snarfed-variable #f
GNU Guile 3.0.10.1-522f3 Copyright (C) 1995-2024 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. $1 = #f
If this is saved as hello.w, get the docs via
wisp2lisp hello.w > hello.scm && guild doc-snarf --texinfo hello.scm
Create a manual as package documentation with texinfo
Create a docs/
folder and add a hello.texi
file.
An example file can look like the following:
@documentencoding UTF-8 @settitle Hello World @c This is a comment @c The Top node is the first page for info @node Top @c Show the title @top @menu * First Steps:: * API Reference:: @end menu @contents @node First Steps @chapter First Steps Quick start: install, minimal example @itemize @item Download from ... @item Install: @code{make}. @end itemize Example: @lisp (+ 1 2) @result{} 3 @end lisp @node API Reference @chapter API Reference @section Procedures @subsection hello Print Hello @example hello @end example
Add a Makefile
in the docs/ folder:
all: hello.info hello.epub hello_html/index.html hello.info: hello.texi makeinfo hello.texi hello.epub: hello.texi makeinfo --epub hello.texi hello_html/index.html: hello.texi makeinfo --html hello.texi
Run make:
make
Read the docs with calibre
or the browser
or plain info
:
calibre hello.epub & \ firefox hello_html/index.html & \ info -f ./hello.info
Nicer still would be a Makefile.am
with TEXINFOS rules which also
provide correct installation out-of-the-box.
The HTML output is plain, you can adapt it with CSS as usual.
Alternately you can write an org-mode document and evaluate
(require 'ox-texinfo)
to activate exporting to texinfo.
To Be Continued …
Also see the Map of R7RS: https://misc.lassi.io/2022/map-of-r7rs-small.html
And see the Scheme primer: https://spritely.institute/static/papers/scheme-primer.html