34 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.
34.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 | 1 |
RSW | Pyret |
1/2 | 1/2 |
RSW | Pyret |
#i3.14 | ~3.14 |
Strings are also very similar, though Pyret allows you to use single-quotes as well.
RSW | Pyret |
"Hello, world!" | "Hello, world!" |
RSW | Pyret |
"\"Hello\", he said" | "\"Hello\", he said" |
RSW | Pyret |
"\"Hello\", he said" | '"Hello", he said' |
Booleans have the same names:
RSW | Pyret |
true | true |
RSW | Pyret |
false | false |
34.2 Infix Expressions
Pyret uses an infix syntax, reminiscent of many other textual programming languages:
RSW | Pyret |
(+ 1 2) | 1 + 2 |
RSW | Pyret |
(* (- 4 2) 5) | (4 - 2) * 5 |
Note that Pyret does not have rules about orders of precedence between operators, so when you mix operators, you have to parenthesize the expression to make your intent clear. When you chain the same operator you don’t need to parenthesize; chaining associates to the left in both languages:
RSW | Pyret |
(/ 1 2 3 4) | 1 / 2 / 3 / 4 |
These both evaluate to 1/24.
34.3 Function Definition and Application
Function definition and application in Pyret have an infix syntax, more reminiscent of many other textual programming languages. Application uses a syntax familiar from conventional algebra books:
RSW | Pyret |
(dist 3 4) | dist(3, 4) |
Application correspondingly uses a similar syntax in function headers, and infix in the body:
RSW | Pyret | |||
|
|
34.4 Variable Names
Both languages have a fairly permissive system for naming variables. While you can use CamelCase and under_scores in both, it is conventional to instead use what is known as kebab-case.This name is inaccurate. The word “kebab” just means “meat”. The skewer is the “shish”. Therefore, it ought to at least be called “shish kebab case”. Thus:
RSW | Pyret |
this-is-a-name | this-is-a-name |
Even though Pyret has infix subtraction, the language can unambiguously tell apart 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)
34.5 Data Definitions
Pyret diverges from Racket (and even more so from Scheme) in its handling of data definitions. First, we will see how to define a structure:
RSW | Pyret |
(define-struct pt (x y)) |
|
data Point: | pt(x, y) end
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) | pt(1, 2) |
RSW | Pyret |
(pt? x) | is-pt(x) |
RSW | Pyret |
(pt-x v) | v.x |
34.6 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 | |||||
|
|
(cond [full-moon "howl"] [new-moon "bark"] [else "meow"])
ask: | full-moon then: "howl" | new-moon then: "bark" | otherwise: "meow" end
(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 | pt(x, y, z) => x + z end
34.7 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>: ...
34.8 What Else?
If there are other parts of Scheme or Racket syntax that you would like to see translated, please let us know.