Skip to content

Commit ffea702

Browse files
committed
blog: Pattern Matching
1 parent 8bc5e87 commit ffea702

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed
File renamed without changes.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
+++
2+
title = "Pattern Matching: Writing Cleaner Code with Less Conditional Logic"
3+
aliases = [ "/blog/pattern-matching" ]
4+
+++
5+
6+
Remember those giant `if/elseif/else` ladders we write in PHP? They start off harmless and suddenly fill half a file. Phel ships with friendlier tools so you can keep the logic flat and readable. We will look at the two big helpers - [`case`](/documentation/control-flow/#case) and [`cond`](/documentation/control-flow/#cond) - and how they feel when you are new to Lisp syntax.
7+
8+
## When plain `if` gets messy
9+
10+
Here is the classic situation: a small payload comes from an API and you branch on it. In PHP you might write a long `if/elseif`. In Phel it can look like this:
11+
12+
```phel
13+
(defn classify [event]
14+
(if (= (:type event) :created)
15+
"Fresh!"
16+
(if (= (:type event) :updated)
17+
(if (:urgent? event)
18+
"Update (urgent)"
19+
"Update (normal)")
20+
(if (= (:type event) :deleted)
21+
"Gone."
22+
"Unknown..."))))
23+
```
24+
25+
It works, but the intent hides in the nesting. Pattern matching lets us tell the same story with fewer twists.
26+
27+
## `case`: think `switch`, but without fall-through
28+
29+
When you compare one value against known constants, reach for [`case`](/documentation/control-flow/#case). It feels like PHP's `switch`, minus the accidental fall-through.
30+
31+
```phel
32+
(defn classify [event]
33+
(case (:type event)
34+
:created "Fresh!"
35+
:updated (if (:urgent? event)
36+
"Update (urgent)"
37+
"Update (normal)")
38+
:deleted "Gone."
39+
(str "Unknown: " (:type event))))
40+
```
41+
42+
Every branch lives on a single level, and the final expression works as a default. No more scrolling to match up closing parentheses.
43+
44+
## `cond`: guard clauses without the ladder
45+
46+
Sometimes you check different conditions in order: heavy parcel, express flag, cancel flag, and so on. [`cond`](/documentation/control-flow/#cond) does exactly that. Give it pairs of condition and result; it returns the first match.
47+
48+
```phel
49+
(defn shipping-label [order]
50+
(cond
51+
(:cancelled? order) "Skip shipping, order cancelled."
52+
(> (:weight order) 30) "Send with freight carrier."
53+
(:express? order) "Upgrade to express."
54+
:else "Regular parcel."))
55+
```
56+
57+
Think of it as stacked `elseif` blocks with no braces to juggle. Drop in `:else` for the fallback and you are done.
58+
59+
## Bonus: friendly destructuring
60+
61+
Pattern matching gets even nicer when you unpack data while you branch. Vectors are like PHP arrays with numeric keys, and maps are like associative arrays. You can pull values out right where you need them.
62+
63+
```phel
64+
(defn handle-message [[kind payload]]
65+
(case kind
66+
:email (let [{:keys [to subject]} payload]
67+
(str "Email to " to " about " subject))
68+
:sms (let [{:keys [to text]} payload]
69+
(str "SMS to " to ": " text))
70+
:push (let [{:keys [device title]} payload]
71+
(str "Push notification for " device " -> " title))
72+
(str "Unknown message: " kind)))
73+
```
74+
75+
`[kind payload]` pulls the first two items out of the vector, and `{:keys [...]}` plucks values from the map by name. No manual `get` calls, no index juggling.
76+
77+
## When to pick what
78+
79+
- **Use `case`** when you would normally reach for `switch` in PHP. One value, many constants.
80+
- **Use `cond`** when each branch has its own test, especially guard clauses.
81+
- **Stick with `if`** for single true/false checks or very hot loops.
82+
- **Layer in destructuring** whenever naming parts of the data makes each branch easier to read.
83+
84+
Once you start matching patterns instead of stacking `if`s, your Phel code reads like a short list of rules. Try it on the next feature that touches conditional logic - you will not miss the ladder.

0 commit comments

Comments
 (0)