Phel has powerful built-in data structures: vectors, maps, sets, and keywords. Let's explore how to create them, access their contents, and discover that they're all immutable.
Exercise 1: Define a vector with the elements 2, "nice", and true.
[2 "nice" true]
# or
(vector 2 "nice" true)
Vectors are ordered collections that can hold any mix of types. Square brackets [] are the most common way to create them.
Learn more: Data Structures
Exercise 2: Define a vector that contains the keywords :hello and :world.
[:hello :world]
Keywords are lightweight identifiers that start with :. They're often used as map keys or as enum-like values.
Learn more: Basic Types
Exercise 3: Create a map with keys :name and :age, with values "Ada" and 36.
{:name "Ada" :age 36}
# or
(hash-map :name "Ada" :age 36)
Maps are key-value collections. Keyword keys are idiomatic in Phel.
Learn more: Data Structures
Exercise 4: Create a set containing the numbers 1, 2, 3, and 2. How many elements does it have?
(set 1 2 3 2)
# => (set 1 2 3) — duplicates are removed!
(count (set 1 2 3 2))
# => 3
Sets are unordered collections of unique values. Adding a duplicate has no effect.
Learn more: Data Structures
Exercise 5: Use the get function to retrieve the second element from the vector [10 20 30].
(get [10 20 30] 1)
# => 20
Vector indices are zero-based, so index 1 is the second element.
Learn more: Data Structures
Exercise 6: Given this map, retrieve the value for :name in three different ways:
(def person {:name "Ada" :age 36})
(def person {:name "Ada" :age 36})
# Way 1: using get
(get person :name) # => "Ada"
# Way 2: using the map as a function
(person :name) # => "Ada"
# Way 3: using the keyword as a function
(:name person) # => "Ada"
All three are equivalent. Using keywords as functions (:name person) is the most idiomatic style.
Learn more: Data Structures
Exercise 7: Use get-in to retrieve the value :treasure from this nested structure:
(def dungeon {:description "dark cave"
:rooms [{:contents :monster}
nil
{:contents [:trinket :treasure]}]})
(get-in dungeon [:rooms 2 :contents 1])
# => :treasure
get-in navigates nested structures using a vector of keys/indices. It works through any combination of maps and vectors.
Learn more: Data Structures
Exercise 8: Use put to add :email "ada@example.com" to the person map. What does put return? What is person after the call?
(def person {:name "Ada" :age 36})
(def person {:name "Ada" :age 36})
(put person :email "ada@example.com")
# => {:name "Ada" :age 36 :email "ada@example.com"}
person
# => {:name "Ada" :age 36} — unchanged!
Phel data structures are immutable. put returns a new map — it never modifies the original. This is a core principle that makes your code predictable and safe.
Learn more: Data Structures
Exercise 9: Use push to add the number 4 to the vector [1 2 3]. Then use count to verify the length of both the original and the new vector.
(def nums [1 2 3])
(def more-nums (push nums 4))
(count nums) # => 3 (original unchanged)
(count more-nums) # => 4
more-nums # => [1 2 3 4]
Again, push returns a new vector. The original is untouched.
Learn more: Data Structures
Exercise 10: Use contains? to check if the set #{:apple :banana :cherry} contains :banana. Then check for :grape.
(def fruits (set :apple :banana :cherry))
(contains? fruits :banana) # => true
(contains? fruits :grape) # => false
contains? is the natural way to check set membership.
Learn more: Data Structures
Exercise 11: Use keys and values on the map {:a 1 :b 2 :c 3}. What do you get?
(keys {:a 1 :b 2 :c 3}) # => (:a :b :c)
(values {:a 1 :b 2 :c 3}) # => (1 2 3)
These are handy when you need to work with just the keys or just the values of a map.
Learn more: Data Structures