A Dylan Primer for Scheme Programmers

This document was originally authored by Jonathan Sobel.

Almost everything you already do in Scheme can be translated easily into Dylan. In fact, with one exception, Dylan is a proper superset of Scheme. The one exception is that continuations have indefinite extent in Scheme and dynamic extent in Dylan. Some individual implementations of Dylan might provide a mechanism for producing continuations with indefinite extent, making all Scheme programs be Dylan programs, too. (Of course, you won’t be taking full advantage of the power of Dylan if you only write Scheme programs in it.)

This document is really just a large table in two columns. On the left, you will see a Scheme expression, and on the right, its Dylan counterpart. If one column contains N/A, then that language has no corresponding direct way to express what is in the other column.

Please remember, there is much more to Dylan than what you’ll find here! For example, this document doesn’t show you how to define new classes or create generic functions (functions which support ad hoc polymorphic behavior). This document is only intended to help ease your transition from Scheme to Dylan.

Literals

Scheme Dylan
#t
#t
#f
#f
23
23
#b1011
#b1011
#o644
#o644
#x2A5F
#x2A5F
-4/5
N/A
6.02E23
6.02E23
#\a
'a'
#\newline
'\n'
"Hello"
"Hello"
N/A
"Hello\n"
'apple
#"apple"
apple:
N/A
#"two words"
'(1 #\a dog)
#(1, 'a', #"dog")
'#(5 10 15)
#[5, 10, 15]
`(1 2 ,x ,@y)
N/A

Syntax

Note that, in Dylan, any words after an end (e.g. end method) are optional.

Scheme Dylan
(define var exp)
define variable var = exp
define constant var = exp
(f x y z)
f(x, y, z)
(begin 1 2 3)
begin 1; 2; 3; end
begin 1; 2; 3 end
(quote datum)
N/A
(lambda (x y . z)
  (say "hello")
  (f x y z)
)
method (x, y, #rest z)
  say("hello");
  f(x, y, z);
end method
(let ((x 5))
  body)
let x = 5;
body
// (Scope ends at next
// "body-ender.")
N/A
let (x, y) = exp;
// (Binds multiple values
// returned by exp.)
(let ((x 5) (y 6))
  (f x y))
let (x, y) = values(5, 6);
f(x, y)
(letrec ((f (lambda (x)
        f-body)
   )
   (g (lambda (y z)
        g-body)
   ))
  body)
local method f (x)
  f-body
end method f,
method g (y, z)
  g-body
end method g;
body
(if test
    (begin then1
     then2)
    (begin else1
     else2)
)
if (test)
  then1;
  then2;
else
  else1;
  else2;
end if
(set! var value)
var := value
(and a b c)
a & b & c
(or a b c)
a | b | c
(cond
 (test1 result1)
 (test2 result2)
 (else result)
)
case
  test1 => result1;
  test2 => result2;
  otherwise => result;
end case
(case exp
 ((a 2) result1)
 (('a' 'b') result2)
 (else result)
)
select (exp)
  #"a", 2 => result1;
  'a', 'b' => result2;
  otherwise => result;
end select
N/A
select (exp by comparison-func)
  f(x) => result1;
  g(y), h(z) => result2;
  otherwise => result;
end select
(do ((var1 init1 step1)
     (var2 init2 step2))
    (test result)
  body
)
for (var1 = init1 then step1,
     var2 = init2 then step2,
     until: test)
  body
finally result
end for

Predefined functions

These are organized based on the “Standard Procedures” section of R4RS.

Boolean functions
(not obj)
~ obj
~obj
(boolean? obj)
instance?(obj, <boolean>)
Equivalence predicates
(eqv? x y)
x == y
(eq? x y)
N/A
(equal? x y)
x = y
Pairs and Lists
(pair? obj)
instance?(obj, <pair>)
(cons x y)
pair(x, y)
(car ls)
head(ls)
(cdr ls)
tail(ls)
(set-car! ls val)
head-setter(val, ls)
head(ls) := val
(set-cdr! ls val)
tail-setter(val, ls)
tail(ls) := val
(cadadr ls)
N/A
(null? obj)
instance?(obj, <empty-list>)
obj = #()
empty?(ls) // most common
(list? obj)
instance?(obj, <list>)
(list x y z)
list(x, y, z)
(length ls)
size(ls)
(append ls1 ls2 ls3)
concatenate(ls1, ls2, ls3)
(reverse ls)
reverse(ls)
(list-ref ls n)
element(ls, n)
(member obj ls)
member?(obj, ls)
(memv obj ls)
member?(obj, ls, test: \==)
Symbols
(symbol? obj)
instance?(obj, <symbol>)
(symbol->string sym)
as(<string>, sym)
(string->symbol str)
as(<symbol>, str)
Numerical operations
(number? obj)
instance?(obj, <number>)
(complex? obj)
instance?(obj, <complex>)
(real? obj)
instance?(obj, <real>)
(rational? obj)
instance?(obj, <rational>)
(integer? obj)
instance?(obj, <integer>)
integral?(num)
(= n1 n2)
n1 = n2
n1 == n2
(< n1 n2)
n1 < n2
(> n1 n2)
n1 > n2
(<= n1 n2)
n1 <= n2
(>= n1 n2)
n1 >= n2
(zero? n)
zero?(n)
(positive? n)
positive?(n)
(negative? n)
negative?(n)
(odd? i)
odd?(i)
(even? i)
even?(i)
(+ 1 2 3)
1 + 2 + 3
(* 1 2 3)
1 * 2 * 3
(- 5 3)
5 - 3
(/ 2.3 1.7)
2.3 / 1.7
(- x)
- x
-x
(expt 2 16)
2 ^ 16
[Most of the standard Scheme numeric functions (e.g. max, remainder) are defined similarly in Dylan. No need to list them all here.]
** Characters**
(char? obj)
instance?(obj, <character>)
(char=? char1 char2)
char1 = char2
char1 == char2
(char<? char1 char2)
char1 < char2
(char>? char1 char2)
char1 > char2
(char<=? char1 char2)
char1 <= char2
(char>=? char1 char2)
char1 >= char2
(char->integer char)
as(<integer>, char)
(integer->char n)
as(<character>, n)
(char-upcase char)
as-uppercase(char)
(char-downcase char)
as-lowercase(char)
Strings
(string? obj)
instance?(obj, <string>)
(make-string k char)
make(<string>, size: k, fill: char)
(string char ...)
N/A
(string-length str)
size(str)
(string-ref str k)
element(str, k)
str[k]
(string-set! str k char)
element-setter(char, str, k)
str[k] := char
(string=? str1 str2)
str1 = str2
(string<? str1 str2)
str1 < str2
(substring str start end)
copy-sequence(str, start: start, end: end)
(string-append str1 str2)
concatenate(str1, str2)
(string->list str)
as(<list>, str)
(list->string chars)
as(<string>, chars)
(string-copy str)
shallow-copy(str)
copy-sequence(str)
(string-fill! str char)
fill!(str, char)
Vectors
(vector? obj)
instance?(obj, <vector>)
(make-vector k fill)
make(<vector>, size: k, fill: fill)
(vector obj ...)
vector(obj, ...);
(vector-length vec)
size(vec)
(vector-ref vec k)
element(vec, k)
vec[k]
(vector-set! vec k obj)
element-setter(obj, vec, k)
vec[k] := obj
(vector->list vec)
as(<list>, vec)
(list>vector list)
as(<vector>, list)
(vector-fill! vec obj)
fill!(vec, obj)
Control Features
(procedure? obj)
instance?(obj, <function>)
(apply proc arg1 arg2 args)
apply(proc, arg1, arg2, args)
(map proc list1 list2)
map(proc, list1, list2)
N/A
map(proc, vec1, vec2)
N/A
map(proc, string1, string2)
(for-each proc list1 list2)
do(proc, list1, list2)

Continuations

As mentioned before, continuations have dynamic extent in Dylan. Also, whereas call/cc is a function, Dylan uses a syntax form to grab a continuation.

(call/cc
  (lambda (k)
    body))
block (k)
  body
end block
(call/cc
  (lambda (k)
    (dynamic-wind
      (lambda () #f)
      (lambda () body)
      (lambda ()
         cleanup-stuff))))
block (k)
  body
cleanup
  cleanup-stuff
end block