Skip to main content

First Steps

You will learn

  • Read a form: the first item is the operation, the rest are its arguments
  • Write nested math without precedence rules
  • Build strings with str and print them with println
  • Compare values with =, <, and predicates like nil?
  • Read an error message and use it to fix your code
Progress 0/14

This is your first contact with a Lisp. The syntax looks strange for about ten minutes, then it becomes the simplest syntax you have used. Open a REPL (or the browser REPL) and type every example. Guess first, then run: a wrong guess teaches you more than a right one.

Reading a form

Phel code is made of forms. A form in parentheses is a call: the first item is the operation, and the rest are its arguments. There are no commas and no operator precedence.

(+ 1 2) ; => 3

Read it as "add 1 and 2". In PHP you would write 1 + 2.

Exercise 1 Predict easy

What does this return?

(+ 1 2 3 4)
Solution
(+ 1 2 3 4) ; => 10

+ takes any number of arguments. In PHP you would need three + signs; in Phel you write the operation once.

Exercise 2 Fill in easy

Replace ___ so the form returns 42.

(* 6 ___)
Solution
(* 6 7) ; => 42

* multiplies all its arguments.

Exercise 3 Predict easy

Forms can contain other forms. Phel evaluates the inner form first, then uses its result. What does this return?

(* 2 (+ 3 4))
Solution
(* 2 (+ 3 4)) ; => 14

Read from the inside out: (+ 3 4) becomes 7, then (* 2 7) becomes 14.

Nesting instead of precedence

PHP has rules that say * runs before +. Phel has no such rules. The parentheses show the order, so you never have to remember it.

(+ 2 (* 3 4)) ; PHP: 2 + 3 * 4   => 14
(* (+ 2 3) 4) ; PHP: (2 + 3) * 4 => 20

Exercise 4 Write easy

Write this PHP expression as a Phel form:

(3 + 4.0 / 5) * 6

The result should be 22.8.

Hint

Start with the innermost part, 4.0 / 5, and wrap outwards.

Solution
(* (+ 3 (/ 4.0 5)) 6) ; => 22.8

Each pair of parentheses is one step. (/ 4.0 5) is 0.8, (+ 3 0.8) is 3.8, and (* 3.8 6) is 22.8.

Learn more: Arithmetic operators

Numbers

Phel has integers (42), floats (4.2), and rationals (1/2). Dividing two integers does not lose precision: when the result is not a whole number, you get an exact fraction.

(/ 1 3)     ; => 1/3
(+ 1/2 1/4) ; => 3/4

Exercise 5 Predict easy

Predict each result, then run them one by one.

(/ 10 5)
(/ 10 4)
(/ 10.0 4)
Solution
(/ 10 5)   ; => 2
(/ 10 4)   ; => 5/2
(/ 10.0 4) ; => 2.5

10 / 4 is not a whole number, so Phel keeps it as the exact fraction 5/2. PHP would give you the float 2.5. Put a float in (10.0) and you get a float out.

Learn more: Numbers

Strings and printing

Strings use double quotes. str joins any number of values into one string. println writes a line to the screen.

(str "Phel " "is " "fun") ; => "Phel is fun"
(println "Hi")            ; prints Hi, returns nil

Exercise 6 Fill in easy

Replace ___ so the form returns "Hello, Phel".

(str "Hello" ___ "Phel")
Solution
(str "Hello" ", " "Phel") ; => "Hello, Phel"

str glues its arguments together in order. In PHP you would write "Hello" . ", " . "Phel".

Exercise 7 Predict easy

str also accepts values that are not strings. What does this print, and what does the whole form return?

(println (str "Total: " (+ 1 2)))
Hint

There are two answers: what shows on the screen, and the value of the println form itself.

Solution
(println (str "Total: " (+ 1 2)))
; prints: Total: 3
; => nil

str turns the number 3 into text. println prints the line, then returns nil, which means "no value". Printing is a side effect; the return value is something else.

Keywords, nil, and booleans

A keyword starts with a colon, like :admin. It is a name that stands for itself, often used as a label. nil means "nothing". true and false are booleans. type tells you what kind of value you have, and it answers with a keyword.

(type "hi") ; => :string

Exercise 8 Predict easy

Predict the result of each form.

(type 42)
(type 4.2)
(type 1/2)
(type :admin)
(type nil)
(type false)
Solution
(type 42)     ; => :int
(type 4.2)    ; => :float
(type 1/2)    ; => :ratio
(type :admin) ; => :keyword
(type nil)    ; => :nil
(type false)  ; => :boolean

When a value behaves in a way you do not expect, type is the first thing to check.

Learn more: Keywords

Comparing values

= checks if values are equal. <, >, <=, and >= compare numbers. Like +, they accept more than two arguments. not= is the opposite of =.

(= 5 (+ 2 3)) ; => true
(< 1 2)       ; => true

Exercise 9 Predict medium

Predict each result. Two of them may surprise a PHP developer.

(= "abc" "abc")
(= 1 1.0)
(= "1" 1)
(< 1 2 3)
(< 1 3 2)
(not= :a :b)
Hint

(< a b c) asks "is each value smaller than the next one?". And = never converts types.

Solution
(= "abc" "abc") ; => true
(= 1 1.0)       ; => false
(= "1" 1)       ; => false
(< 1 2 3)       ; => true
(< 1 3 2)       ; => false
(not= :a :b)    ; => true

= is strict, like PHP's ===: an int and a float are different values, and so are a string and a number. (< 1 2 3) checks the whole chain, so (< 1 3 2) is false because 3 is not smaller than 2.

Learn more: Equality and comparison

Asking questions with predicates

A predicate is a function that answers yes or no. By convention its name ends with ?.

(string? "hi") ; => true
(int? "42")    ; => false

Exercise 10 Predict medium

Predict each result.

(nil? nil)
(nil? 0)
(nil? false)
(int? 4.0)
(float? 4.0)
(keyword? :a)
Hint

nil? is true for one value only.

Solution
(nil? nil)    ; => true
(nil? 0)      ; => false
(nil? false)  ; => false
(int? 4.0)    ; => false
(float? 4.0)  ; => true
(keyword? :a) ; => true

0 and false are values, not "nothing", so they are not nil. And 4.0 is a float even though it looks whole.

Learn more: Nil, true, false

Exercise 11 Write medium

Write one form that returns true when the result of (/ 10 4) is a rational number. Use type, =, and a keyword.

Hint

You already know what (type 1/2) returns. Compare against that keyword.

Solution
(= (type (/ 10 4)) :ratio) ; => true

Inside out: (/ 10 4) is 5/2, type gives :ratio, and = compares two keywords. Three small forms make one question.

Reading errors

Errors are part of the work. A Phel error tells you three things: what went wrong, where (file and line), and often a hint for the fix. Read the first line first; it is usually enough.

[PHEL100] Unterminated list starting at line 2. Did you forget a closing ')'?

The next three exercises break on purpose. Run each one, read the message, then fix the code.

Exercise 12 Fix medium

This form has a typo. Run it and read the error. What does Phel suggest? Fix the form.

(prinltn "Hello, Phel")
Hint

Look for the words "Did you mean".

Solution

Phel says:

[PHEL001] Cannot resolve symbol 'prinltn'. Did you mean 'print', 'printf', or 'println'?
(println "Hello, Phel")

"Cannot resolve symbol" means Phel does not know that name. It points at the exact spot with ^^^ and lists names that look close.

Exercise 13 Fix medium

A PHP developer wrote this. Run it and read the error. Why is 1 in the message? Fix the form.

(1 + 2)
Hint

Which item in a form does Phel treat as the operation?

Solution

Phel says:

[PHEL011] Value 1 of type int is not callable.
(+ 1 2) ; => 3

Phel always calls the first item of a form. Here the first item is 1, and a number cannot be called. Move the operation to the front.

Exercise 14 Fix hard

This should return "Total: 5", but it fails. Run it, read the error, and fix it.

(+ "Total: " 5)
Hint

The message says what + expected. Which function from this module joins text?

Solution

Phel says:

Expected a number, got string
(str "Total: " 5) ; => "Total: 5"

+ is only for numbers, and Phel does not convert types for you. To build text, use str, the way you would use . in PHP.

Learn more: Strings

What you can do now

  • You can read any Phel form from the inside out
  • You can turn a PHP expression like 2 + 3 * 4 into prefix notation
  • You know the basic values: numbers, strings, keywords, nil, true, and false
  • You can ask questions about values with =, comparisons, predicates, and type
  • You can read an error message, find the line, and fix the cause