A Dylan Primer for Scheme Programmers

Almost everything you already do in Scheme can be translated easily into Dylan(tm). 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.

Scheme				Dylan

Literals

#t				#t
#f				#f
23				23
#b1011				#b1011
#o644				#o644
#x2A5F				#x2A5F
-4/5				-4/5
6.02E23				6.02E23
#\a				'a'
#\newline			'\n'
		(Dylan supports \a, \b, \e, \f, \n, \r, \t, and \0)
"Hello"				"Hello"
N/A				"Hello\n"
'apple				#"apple" or apple:
N/A				#"two words" (Think "hashed string"...)
'(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.

(define var exp)		define variable var = exp
			    or	define constant var = exp

(f x y z)			f(x, y, z)

(begin 1 2 3)			begin 1; 2; 3; end
			    or	begin 1; 2; 3 end

(quote datum)			N/A

(lambda (x y . z)		method (x, y, #rest z)
  (say "hello")			  say("hello");
  (f x y z)			  f(x, y, z);
)				end method

(let ((x 5))			let x = 5;
  body)				body
			(Scope ends at next "body-ender.")

N/A				let (x, y) = exp;
			(Binds multiple values returned by exp.)

(let ((x 5) (y 6))		let (x, y) = values(5, 6);
  (f x y))			f(x, y)

(letrec ((f (lambda (x)		local method f (x)
	      f-body)			f-body
	 )			      end method f,
	 (g (lambda (y z)	      method g (y, z)
	      g-body)			g-body
	 ))			      end method g;
  body)				body

(if test			if (test)
    (begin then1		  then1;
	   then2)		  then2;
    (begin else1		else
	   else2)		  else1;
)				  else2;
				end if

(set! var value)		var := value

(and a b c)			a & b & c

(or a b c)			a | b | c

(cond				case
 (test1 result1)		  test1 => result1;
 (test2 result2)		  test2 => result2;
 (else result)			  otherwise => result;
)				end case

(case exp			select (exp)
 ((a 2) result1)		  #"a", 2 => result1;
 (('a' 'b') result2)		  'a', 'b' => result2;
 (else result)			  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)		for (var1 = init1 then step1,
     (var2 init2 step2))	     var2 = init2 then step2,
    (test result)		     until: test)
  body				  body
)				finally result
				end for

Predefined functions

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

(not obj)			~ obj  or ~obj
(boolean? obj)			instance?(obj, <boolean>)

(eqv? x y)			x == y
(eq? x y)			N/A
(equal? x y)			x = y

(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) or head(ls) := val
(set-cdr! ls val)		tail-setter(val, ls) or tail(ls) := val
(cadadr ls)			N/A
(null? obj)	     literally  instance?(obj, <empty-list>)
			    or  obj = #()
  but the most common usage is  empty?(ls)
(list? obj)	 approximately  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: \==)

(symbol? obj)			instance?(obj, <symbol>)
(symbol->string sym)		as(<string>, sym)
(string->symbol str)		as(<symbol>, str)

(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>)
			    or  integral?(num)
(= n1 n2)			n1 = n2  or  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  or  -x
(expt 2 16)			2 ^ 16
[Most of the standard Scheme numeric functions (e.g. max, remainder)
 are defined simlarly in Dylan.  I see no need to list them all here.]

(char? obj)			instance?(obj, <character>)
(char=? char1 char2)		char1 = char2  or  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)

(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)  or  str[k]
(string-set! str k char)	element-setter(char, str, k)
			    or  str[k] := char
(string=? str1 str2)		str1 = str2
(string<? str1 str2)		str1 < str2
etc.
(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)
			    or  copy-sequence(str)
(string-fill! str char)		fill!(str, char)

(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)  or  vec[k]
(vector-set! vec k obj)		element-setter(obj, vec, k)
			    or  vec[k] := obj
(vector->list vec)		as(<list>, vec)
(list>vector list)		as(<vector>, list)
(vector-fill! vec obj)		fill!(vec, obj)

(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 I 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			block (k)
  (lambda (k)			  body
    body))			end block

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