27 Pyret for Racketeers and Schemers
If you’ve programmed before in a language like Scheme or the student levels of Racket (or the WeScheme programming environment), or for that matter even in certain parts of OCaml, Haskell, Scala, Erlang, Clojure, or other languages, you will find many parts of Pyret very familiar. This chapter is specifically written to help you make the transition from (student) Racket/Scheme/WeScheme (abbreviated “RSW”) to Pyret by showing you how to convert the syntax. Most of what we say applies to all these languages, though in some cases we will refer specifically to Racket (and WeScheme) features not found in Scheme.
In every example below, the two programs will produce the same results.
27.1 Numbers, Strings, and Booleans
Numbers are very similar between the two. Like Scheme, Pyret implements arbitrary-precision numbers and rationals. Some of the more exotic numeric systems of Scheme (such as complex numbers) aren’t in Pyret; Pyret also treats imprecise numbers slightly differently.
RSW | Pyret |
1 |
|
RSW | Pyret |
1/2 |
|
RSW | Pyret |
#i3.14 |
|
Strings are also very similar, though Pyret allows you to use single-quotes as well.
RSW | Pyret |
"Hello, world!" |
|
RSW | Pyret |
"\"Hello\", he said" |
|
RSW | Pyret |
"\"Hello\", he said" |
|
Booleans have the same names:
RSW | Pyret |
true |
|
RSW | Pyret |
false |
|
27.2 Infix Expressions
Pyret uses an infix syntax, reminiscent of many other textual programming languages:
RSW | Pyret |
(+ 1 2) |
|
RSW | Pyret |
(* (- 4 2) 5) |
|
RSW | Pyret |
(/ 1 2 3 4) |
|
27.3 Function Definition and Application
RSW | Pyret |
(dist 3 4) |
|
RSW | Pyret | |||
|
|
27.4 Tests
RSW | Pyret |
(check-expect 1 1) |
|
RSW | Pyret | ||
|
|
The second way is this: as an alias for check
we can also write
examples
. The two are functionally identical, but they capture
the human difference between examples (which explore the
problem, and are written before attempting a solution) and
tests (which try to find bugs in the solution, and are written
to probe its design).
where
block to accompany a function
definition. For instance:
fun double(n):
n + n
where:
double(0) is 0
double(10) is 20
double(-1) is -2
end
check "squaring always produces non-negatives":
(0 * 0) is 0
(-2 * -2) is 4
(3 * 3) is 9
end
Just as in Racket, there are many testing operators in Pyret (in
addition to is
). See
the
documentation.
27.5 Variable Names
RSW | Pyret |
this-is-a-name |
|
this-name
(a variable) from
this - name
(a subtraction expression) because the -
in
the latter must be surrounded by spaces.
(define e^i*pi -1)
27.6 Data Definitions
RSW | Pyret |
(define-struct pt (x y)) |
|
|
in the middle:
data Point: | pt(x, y) end
|
, resulting
in the more readable
data Point: pt(x, y) end
;; A Point is either ;; - (pt number number), or ;; - (pt3d number number number)
data Point:
| pt(x, y)
| pt3d(x, y, z)
end
RSW | Pyret |
(pt 1 2) |
|
RSW | Pyret |
(pt? x) | is-pt(x) |
cases
):
RSW | Pyret |
(pt-x v) |
|
.x
extracts an x
field of any value
that has such a field, without attention to how it was
constructed. Thus, we can use .x
on a value whether it was
constructed by pt
or pt3d
(or indeed anything else with
that field). In contrast, cases
does pay attention to this
distinction.27.7 Conditionals
There are several kinds of conditionals in Pyret, one more than in the Racket student languages.
General conditionals can be written using if
, corresponding to
Racket’s if
but with more syntax.
RSW | Pyret | |||
|
|
RSW | Pyret | |||||
|
|
if
includes else if
, which makes it possible
to list a collection of questions at the same level of indentation,
which if in Racket does not have. The corresponding code in
Racket would be written
(cond [full-moon "howl"] [new-moon "bark"] [else "meow"])
ask
, designed to parallel cond
:
ask:
| full-moon then: "howl"
| new-moon then: "bark"
| otherwise: "meow"
end
cond
to dispatch on a datatype:
(cond [(pt? v) (+ (pt-x v) (pt-y v))] [(pt3d? v) (+ (pt-x v) (pt-z v))])
ask:
| is-pt(v) then: v.x + v.y
| is-pt3d(v) then: v.x + v.z
end
if is-pt(v):
v.x + v.y
else if is-pt3d(v):
v.x + v.z
end
cases (Point) v:
| pt(x, y) => x + y
| pt3d(x, y, z) => x + z
end
v
is a Point
, provides a clean
syntactic way of identifying the different branches, and makes
it possible to give a concise local name to each field position
instead of having to use selectors like .x
. In general, in
Pyret we prefer to use cases
to process data
definitions. However, there are times when, for instance, there many
variants of data but a function processes only very few of them. In
such situations, it makes more sense to explicitly use predicates and
selectors.27.8 Lists
In Racket, depending on the language level, lists are created using
either cons or list, with empty for the empty
list. The corresponding notions in Pyret are called link
,
list
, and empty
, respectively. link
is a
two-argument function, just as in Racket:
RSW | Pyret |
(cons 1 empty) |
|
RSW | Pyret |
(list 1 2 3) |
|
Note that the syntax [1, 2, 3]
, which represents lists in many
languages, is not legal in Pyret: lists are not privileged with
their own syntax. Rather, we must use an explicit constructor:
just as [list: 1, 2, 3]
constructs a list, [set: 1, 2,
3]
constructs a set instead of a list.In fact, we can
create our own constructors
and use them with this syntax.
Exercise
Try typing
[1, 2, 3]
and see the error message.
cases
. There are two variants, empty
and link
(which we used to construct the lists):
RSW | Pyret | |||||
|
|
f
and r
(for
“first” and “rest”). Of course, this convention does not work if
there are other things by the same name; in particular, when writing a
nested destructuring of a list, we conventionally write fr
and
rr
(for “first of the rest” and “rest of the rest”).27.9 First-Class Functions
lam
:
RSW | Pyret |
(lambda (x y) (+ x y)) |
|
27.10 Annotations
; square: Number -> Number ; sort-nums: List<Number> -> List<Number> ; sort: List<T> * (T * T -> Boolean) -> List<T>
fun square(n :: Number) -> Number: ...
fun sort-nums(l :: List<Number>) -> List<Number>: ...
fun sort<T>(l :: List<T>, cmp :: (T, T -> Boolean)) -> List<T>: ...
27.11 What Else?
If there are other parts of Scheme or Racket syntax that you would like to see translated, please let us know.