Functions in Dylan
Learn how to define and use functions in Dylan - define function, generic functions and methods, return values, keyword parameters, recursion, multiple values, closures, and higher-order functions
Functions are where Dylan’s multi-paradigm character becomes obvious. Dylan is object-oriented, functional, and procedural all at once, and its function model reflects that blend. You can write plain named functions like you would in C or Python, but you can also attach multiple methods to a single generic function and let the runtime pick the right one based on the types of all the arguments — a feature called multiple dispatch, inherited from Common Lisp’s CLOS.
Like its Lisp ancestors, Dylan treats functions as first-class values. A function can be stored in a variable, passed as an argument, returned from another function, and built on the fly as an anonymous method. Functions also have no return keyword: the value of the last expression in the body is what the function returns, and the optional => (...) clause documents (and can constrain) those return values.
In this tutorial you’ll define functions with define function, add methods to generic functions for multiple dispatch, return more than one value at once, use keyword parameters with defaults, write recursion, and finish with closures and higher-order functions. We’ll go well beyond the one-line greet from the Hello World page.
Defining Functions, Returning Values, and Recursion
The define function form creates a named function. Parameters are listed with optional :: type declarations, and the => (...) clause names the return values. Because the last expression is returned automatically, a one-line body needs no return.
Dylan also distinguishes a plain function from a generic function. When you write define method with the same name more than once, each method joins one generic function, and Dylan selects the matching method by the runtime types of the arguments. The example below shows both styles, plus multiple return values via values and a recursive factorial.
Create a file named functions.dylan:
| |
define functiondefines a plain function;define methodadds a method to a generic function of the same name.=> (result :: <integer>)documents and constrains the return value. Use=> ()when a function returns nothing useful.- Multiple dispatch: calling
describe-numberruns the<integer>method or the<float>method depending on the argument’s actual type. values(a, b)returns two results, andlet (lo, hi) = ...destructures them.#key greeting = "Hello"makesgreetingoptional; at the call site you pass it asgreeting: "Welcome".
Closures and Higher-Order Functions
Functions in Dylan are values like any other, so you can pass them around and return them. An anonymous function is written method (args) ... end. A function that returns another function creates a closure — the inner method “remembers” the variables that were in scope when it was created. Functions that accept or return other functions are higher-order functions, and Dylan’s collection library leans on them heavily with map, reduce, and choose.
Create a file named closures.dylan:
| |
method (x) ... endis an anonymous function value; it needs no name and can be passed directly tomap.make-adderreturns amethodthat closes overn, soadd5always adds 5 — that captured environment is the closure.map,reduce, andchooseare higher-order functions from Dylan’s collection library that take a function as an argument.\+turns the+operator into an ordinary function value you can hand toreduce.
Running with Docker
The Docker image compiles and runs the Dylan source file in the mounted directory. Create and run one example at a time — keep a single .dylan source in the directory, then replace it to try the next example.
| |
Expected Output
Running functions.dylan:
square(7) = 49
42 is an integer
3.5 is a float
factorial(5) = 120
min = 4, max = 9
Hello, World!
Welcome, Dylan!
Running closures.dylan:
add5(10) = 15
apply-twice(add5, 10) = 20
squares = #(1, 4, 9, 16, 25)
sum = 15
evens = #(2, 4)
Key Concepts
define functioncreates a plain named function, whiledefine methodadds a method to a generic function that can have many implementations.- Multiple dispatch selects the method to run based on the runtime types of all arguments, not just a receiver object — a defining feature Dylan shares with CLOS.
- No
returnkeyword — a function evaluates to the value of its last expression; the=> (...)clause names and constrains the results. valuesreturns multiple results at once, destructured at the call site withlet (a, b) = ....#keyparameters are optional and can supply defaults, passed by name (greeting: "Welcome") when calling.- Recursion is natural and idiomatic; always provide a base case (here,
n <= 1) to terminate. - Functions are first-class values — store them in variables, pass them as arguments, and return them, using
method (args) ... endfor anonymous functions. - Closures capture surrounding variables, and higher-order functions like
map,reduce, andchooseuse functions as data to drive Dylan’s collection processing.
Running Today
All examples can be run using Docker:
docker pull codearchaeology/dylan:latest
Comments
Loading comments...
Leave a Comment