A Dylan Primer for Python Programmers¶
Note
If one column contains N/A, then that language has no corresponding direct way to express what is in the other column.
Literals¶
Python |
Dylan |
---|---|
True
|
#t
|
False
|
#f
|
23
|
23
|
0b1011
|
#b1011
|
0o644
|
#o644
|
0x2A5F
|
#x2A5F
|
6.02e+23
|
6.02e+23 // double float
6.02s+23 // single float
6.02d+23 // double float
|
N/A No individual characters other than integer character codes |
'a'
'\n'
|
'Hello'
'Hello\n'
|
"Hello"
"Hello\n"
|
s = '''Hi, from
python'''
# No Rectangle rule
s = '''
Hi, from
Python
'''
|
let s = """
Hi, from
Dylan
""";
// Rectangle rule support
let s = """
Hi, from
Dylan
""";
|
N/A Not real symbols but strings are interned |
#"apple"
apple:
|
N/A No symbols |
#"two words"
|
(1, 'a', 'dog')
|
N/A No tuples (see multiple values) |
[5, 10, 15]
|
#[5, 10, 15]
|
Syntax¶
Note
In Dylan, any words after an end
(e.g. end method
) are
optional but, if present, must match the corresponding “begin”
word.
Python |
Dylan |
---|---|
var = exp
VAR = exp # Convention
|
let var = exp;
var := exp;
define variable var = exp;
define variable var :: type = exp;
define constant var = exp;
|
f(x, y, z)
|
f(x, y, z)
|
1
2
3
|
begin 1; 2; 3; end
begin 1; 2; 3 end
|
lambda x, y, *z:
print('hello')
return f(x, y, z)
|
method (x, y, #rest z)
format-out("hello");
f(x, y, z)
end method
|
x, y = exp
|
let (x, y) = exp
|
x, y = (5, 6)
f(x, y)
|
let (x, y) = values(5, 6);
f(x, y)
|
def foo():
def f(x):
f-body
def g(y, z):
g-body
body
|
define function foo ()
local method f (x)
f-body
end,
method g (y, z)
g-body
end;
body
end;
|
if test:
then1
then2
else:
else1
else2
|
if (test)
then1;
then2;
else
else1;
else2;
end if
|
a and b and c
|
a & b & c
|
a or b or c
|
a | b | c
|
if test1:
result1
elif test2:
result2
else:
result
|
case
test1 => result1;
test2 => result2;
otherwise => result
end case
|
if exp in (1, 2):
result1
elif exp in ('a', 'b'):
result2
else:
result
|
select (exp)
1, 2 => result1;
'a', 'b' => result2;
otherwise => result
end select
|
c = comparison-func(exp)
if c == 'foo':
result1
elif c == 'bar':
result2
else:
result
|
select (exp by comparison-func)
"foo" => result1;
"bar" => result2;
otherwise => result
end select
|
var1 = init1
var2 = init2
while not test:
body
var1 = step1
var2 = step2
return var1
|
for (var1 = init1 then step1,
var2 = init2 then step2,
until: test)
body
finally var1
end for
|
Predefined functions¶
Boolean functions¶
Python |
Dylan |
---|---|
not obj
|
~ obj
~obj
|
isinstance(obj, bool)
|
instance?(obj, <boolean>)
|
Equivalence predicates¶
Python |
Dylan |
---|---|
x == y
|
x = y
|
x is y
|
x == y
|
Symbols¶
Python |
Dylan |
---|---|
N/A |
instance?(obj, <symbol>)
|
N/A |
as(<string>, sym)
|
as(<symbol>, str)
|
Numerical operations¶
Python |
Dylan |
---|---|
isinstance(obj,
(int, float, complex))
|
instance?(obj, <number>)
|
isinstance(obj, complex)
|
instance?(obj, <complex>)
|
isinstance(obj,
(int, float))
|
instance?(obj, <real>)
|
isinstance(obj, int) or
(isinstance(obj, float) and
obj == int(obj))
|
instance?(obj, <rational>)
|
isinstance(obj, int)
|
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
|
n == 0
0 == 0.0 # True
|
zero?(n)
0 == 0.0 // #f
|
n > 0
|
positive?(n)
|
n < 0
|
negative?(n)
|
i % 2 != 0
|
odd?(i)
|
i % 2 == 0
|
even?(i)
|
1 + 2 + 3
|
1 + 2 + 3
|
1 * 2 * 3
|
1 * 2 * 3
|
5 - 3
|
5 - 3
|
1 / 2 # 0.5
|
1 / 2 // error
1.0 / 2 // 0.5
truncate/(1, 2) // 0
ceiling/(1, 2) // 1
floor/(1,2) // 0
|
-x
|
- x
-x
|
2 ** 16
|
2 ^ 16
|
max(1, 2, 3)
max([1, 2, 3])
|
max(1, 2, 3)
apply(max, #(1, 2, 3))
|
5 % 2
|
remainder(5, 2)
|
Characters¶
Python |
Dylan |
---|---|
isinstance(obj, str) and
len(obj) == 1
|
instance?(obj, <character>)
|
char1 == char2
|
char1 == char2
|
char1 < char2
|
char1 < char2
|
char1 > char2
|
char1 > char2
|
char1 <= char2
|
char1 <= char2
|
char1 >= char2
|
char1 >= char2
|
ord(char)
|
as(<integer>, char)
|
chr(n)
|
as(<character>, n)
|
char.upper()
|
as-uppercase(char)
|
char.lower()
|
as-lowercase(char)
|
Strings¶
Python |
Dylan |
---|---|
isinstance(obj, str)
|
instance?(obj, <string>)
|
'x' * k
|
make(<string>, size: k, fill: char)
|
"".join('a', 'b', 'c'])
|
as(<string>, #['a', 'b', 'c'])
|
len(str)
|
size(str)
str.size
|
str[k]
|
element(str, k)
str[k]
|
# Strings are immutable
|
element-setter(char, str, k)
str[k] := char
|
str1 == str2
|
str1 = str2
|
str1 < str2
|
str1 < str2
|
str[start:end]
|
copy-sequence(str, start: start, end: end)
|
str1 + str2
|
concatenate(str1, str2)
|
list(str)
|
as(<list>, str)
|
list(str)
|
as(<string>, chars)
|
copy(str)
|
shallow-copy(str)
copy-sequence(str)
|
# Strings are immutable
|
fill!(str, char)
|
Vectors¶
Python |
Dylan |
---|---|
isinstance(obj, list)
|
instance?(obj, <vector>)
|
[fill] * k
|
make(<vector>, size: k, fill: fill)
|
[obj, ...]
|
vector(obj, ...)
|
len(vec)
|
size(vec)
vec.size
|
vec[k]
|
element(vec, k)
vec[k]
|
vec[k] = obj
|
element-setter(obj, vec, k)
vec[k] := obj
|
list(vec)
|
as(<list>, vec)
|
# Uses lists for both
list(list)
|
as(<vector>, list)
|
for i in range(len(vec)):
vec[i] = obj
|
fill!(vec, obj)
|
Control Features¶
Python |
Dylan |
---|---|
callable(obj)
|
instance?(obj, <function>)
|
proc(arg1, arg2, *args)
|
apply(proc, arg1, arg2, args)
|
map(proc, list1, list2, ...)
# returns iterator in
# Python 3
|
map(proc, list1, list2, ...)
|
map(proc, vec1, vec2, ...)
|
map(proc, vec1, vec2, ...)
|
map(proc, str1, str2)
|
map(proc, str1, str2)
|
for a,b in zip(list1, list2):
proc(a, b)
|
do(proc, list1, list2)
|
Continuations¶
Python doesn’t have first-class continuations like Scheme’s
call/cc
, and Dylan’s block
syntax is more like structured
exception handling or generators.
Here are approximate equivalents:
Python |
Dylan |
---|---|
def example():
try:
body()
except Error as e:
handle_error()
finally:
cleanup_stuff()
|
block (k)
body
exception (e :: <error>)
handle-error()
cleanup
cleanup-stuff
end block
|
N/A |
define function top ()
block (exit-block)
bar(exit-block);
format-out("You won't see this.\n");
end;
format-out("You WILL see this.\n");
end;
define function bar (thunk)
thunk()
end;
top();
|
Keyword arguments¶
Python |
Dylan |
---|---|
def wrapper_fn (a, b, c, **keys):
do_stuff(a, b, c)
return wrapped_fn(**keys)
def wrapped_fn (one = 1, two = 2, three = 3):
return [one, two, three]
|
define method wrapper-fn (a, b, c, #rest keys)
do-stuff(a, b, c);
apply(wrapped-fn, keys)
end;
define method wrapped-fn
(#key one = 1, two = 2, three = 3)
list(one, two, three)
end;
|
Python collects any number of keyword arguments into a dictionary. In
Dylan, #rest keys
collects the remaining arguments, not into a
dictionary, but into a vector (like a property list or plist):
alternating symbol-value pairs.
Loops¶
for¶
Python |
Dylan |
---|---|
words = ['one', 'two']
for w in words:
print(w, len(w))
|
let words = #("one", "two")
for (w in words)
format-out("%s %d\n", w, w.size)
end;
|
N/A Tail recursion |
iterate loop (words = #("one", "two"))
if (~empty?(words))
let word = head(words);
format-out("%s %d\n", word, word.size);
loop(tail(words))
end
end
|
while¶
Python |
Dylan |
---|---|
a, b = 0, 1
while (a < 10):
print(a)
a, b = b, a+b
|
let (a, b) = values(0, 1);
while (a < 10)
format-out("%d\n", a);
let temp = a;
a := b; b := temp + b;
end
|
N/A Tail recursion |
iterate loop (a = 0, b = 1)
if (a < 10)
format-out("%d\n", a);
loop(b, a + b)
end
end
|
until¶
Python |
Dylan |
---|---|
N/A |
let count = 5;
until (count = 0)
format-out("Count is %d\n", count);
count := count - 1;
end;
|
N/A |
// tail recursion
iterate loop (count = 5)
if (count > 0)
format-out("Count is %d\n", count);
loop(count - 1)
end
end
|
break¶
Python |
Dylan |
---|---|
for i in range(10):
if i == 5:
break
print(i)
|
block(break)
for (i from 0 below 10)
if (i = 5) break() end;
format-out("%d\n", i);
end;
end
|
continue¶
Python |
Dylan |
---|---|
for i in range(5):
if i == 2:
continue
print(i)
|
for (i from 0 below 5)
block(continue)
if (i = 2) continue() end;
format-out("%d\n", i);
end;
end
|
pass¶
Python |
Dylan |
---|---|
if some_condition:
pass
|
if (some-condition)
// do nothing
end
|
match¶
Python |
Dylan |
---|---|
def http_error(status):
match status:
case 400:
return "Bad request"
case 404:
return "Not found"
case _:
return "Something went wrong"
|
define function http-error(status)=>(msg)
select (status)
400 => "Bad request";
404 => "Not found";
otherwise => "Something went wrong";
end
end
|
Python |
Dylan |
---|---|
# point is an (x, y) tuple
def say(point):
match point:
case (0, 0):
print("Origin")
case (0, y):
print(f"Y={y}")
case (x, 0):
print(f"X={x}")
case (x, y):
print(f"X={x}, Y={y}")
case _:
raise ValueError("Not a point")
|
Dylan has no built-in pattern matching but match can be implemented in a library as a macro. |