Functions are the building blocks of any Phel program. Here you'll learn how to define them, name things, and scope your variables.
Exercise 1: Use def to create a binding called greeting with the value "Hello, Phel!". Then evaluate greeting.
(def greeting "Hello, Phel!")
greeting
# => "Hello, Phel!"
def creates a global binding — a name associated with a value.
Learn more: Global and Local Bindings
Exercise 2: Use defn to define a function hello that takes no arguments and returns "hello!".
(hello) # => "hello!"
(defn hello [] "hello!")
defn is short for "define function". The [] is the parameter list (empty here), and the last expression is the return value.
Learn more: Functions and Recursion
Exercise 3: Define a function double that takes a number and returns it multiplied by 2.
(double 5) # => 10
(defn double [n] (* n 2))
Learn more: Functions and Recursion
Exercise 4: Add a docstring to double. Then use (doc double) to see it.
(defn double
"Multiplies the given number by 2."
[n]
(* n 2))
(doc double)
Docstrings are placed between the function name and the parameter list. They help other developers (and your future self!) understand what a function does.
Learn more: Functions and Recursion
Exercise 5: Use let to create a local binding name with value "world", then return the string "Hello, world!" using str.
(let [name "world"]
(str "Hello, " name "!"))
# => "Hello, world!"
let creates bindings that only exist within its body. This keeps your code clean and avoids polluting the global scope.
Learn more: Global and Local Bindings
Exercise 6: Use let to bind multiple values and compute a result. Calculate the area of a rectangle with width 5 and height 3.
(let [width 5
height 3]
(* width height))
# => 15
You can create multiple bindings in a single let. Later bindings can reference earlier ones.
Learn more: Global and Local Bindings
Exercise 7: Create an anonymous function that adds 10 to a number. Test it by calling it with 5. Try both the fn form and the short | form.
# Using fn
((fn [x] (+ x 10)) 5)
# => 15
# Using the short form
(|(+ $ 10) 5)
# => 15
Anonymous functions are useful when you need a quick one-off function (especially with map, filter, etc.). The | form uses $ for the first argument, $1 for the second, and so on.
Learn more: Functions and Recursion
Exercise 8: Define a function greet that takes a name and an optional greeting (defaulting to "Hello"):
(greet "Ada") # => "Hello, Ada!"
(greet "Ada" "Welcome") # => "Welcome, Ada!"
Hint: use a rest parameter or multiple arities.
(defn greet
[name & [greeting]]
(let [g (or greeting "Hello")]
(str g ", " name "!")))
The & [greeting] captures extra arguments via destructuring. or provides the default value when greeting is nil.
Learn more: Functions and Recursion, Destructuring
Exercise 9: Implement a factorial function using recursion.
(factorial 5) # => 120
(defn factorial [n]
(if (<= n 1)
1
(* n (factorial (dec n)))))
This is classic recursion: the function calls itself with a smaller input until it reaches the base case (n <= 1).
Learn more: Functions and Recursion