forked from orion/obsidian
56 lines
2.0 KiB
Markdown
56 lines
2.0 KiB
Markdown
Single [[Functions|Functions]] [[Defining/Pattern Matching|implementations]] may have 1 or more guard clauses.
|
|
|
|
> [!info]
|
|
> [[case .. of]] expressions can also use guard clauses.
|
|
|
|
These allow functions to switch on boolean expressions based on the inputs, and can often take up less space than explicit [[Expressions/if .. then .. else ..]] expressions.
|
|
|
|
Guard patterns are placed after the function arguments and take the form `| <Boolean expr> = <body>`. There can be any number of guard patterns, as long as all cases are exhaustively covered.
|
|
|
|
### Example
|
|
Strings can't be structurally pattern matched, so in order to ask if a string starts with a substring we need to call a function like `Data.String.Utils.startsWith`.
|
|
|
|
We could do this with `if then else`:
|
|
|
|
```haskell
|
|
ensureLeadingSlash :: String -> String
|
|
ensureLeadingSlash str =
|
|
if String.Util.startsWith "/" then
|
|
str
|
|
else
|
|
"/" <> str
|
|
```
|
|
|
|
Alternatively, we could implement this with guard patterns:
|
|
```haskell
|
|
ensureLeadingSlash :: String -> String
|
|
ensureLeadingSlash str
|
|
| String.Util.startsWith "/" str = str
|
|
| otherwise = "/" <> str
|
|
```
|
|
|
|
When the first pattern `String.Util.startsWith "/" str` returns `true`, the function will use `... = str`. Otherwise, it will prepend `/` to `str`.
|
|
|
|
> [!tip]
|
|
> `otherwise` is simply an alias for `true`, specifically for better-reading fallthrough guard patterns.
|
|
|
|
Much less often, but occasionally useful is the ability to structurally pattern match in a guard clause:
|
|
|
|
```haskell
|
|
ensureLeadingSlashM :: Maybe String -> String
|
|
ensureLeadingSlashM mstr
|
|
| Just s <- mstr, String.Util.startsWith "/" s = s
|
|
| otherwise = ""
|
|
```
|
|
|
|
Here the bit `Just s <- mstr` is saying "when `mstr` is `Just s`..."
|
|
|
|
then `String.Util.startsWith "/" s` says "and `s` starts with `"/"`..."
|
|
|
|
`| Just s <- mstr, startsWith "/" s = s`
|
|
"when `mstr` is `Just s` and `s` starts with `"/"`, return s"
|
|
|
|
`| otherwise = ""`
|
|
otherwise return `""`
|
|
|
|
You can have any number of comma-separated guard bindings before the last boolean expression. |