Should be work with 0.18
Destructuring(or pattern matching) is a way used to extract data from a data structure(tuple, list, record) that mirros the construction. Compare to other languages, Elm support much less destructuring but let's see what it got !
myTuple = ("A", "B", "C")
myNestedTuple = ("A", "B", "C", ("X", "Y", "Z"))
let
(a,b,c) = myTuple
in
a ++ b ++ c
-- "ABC" : String
let
(a,b,c,(x,y,z)) = myNestedTuple
in
a ++ b ++ c ++ x ++ y ++ z
-- "ABCXYZ" : String
Make sure to match every tuple(no more no less) or you will get an error like:
let
(a,b) = myTuple
in
a ++ b
-- TYPE MISMATCH :(
In Elm community, the underscore _
is commonly used to bind to unused element.
let
(a,b,_) = myTuple
in
a ++ b
-- "AB" : String
It's also more elegant to decrale some constant of your app using destructuring.
-- with no destructuring
width = 200
height = 100
-- with destrcuturing
(width, height) = (200, 100)
Thanks to @robertjlooby, I learned that we can match exact value of comparable.
This is useful when you want to explicitly renaming the variable in your branches of case .. of
.
isOrdered : (String, String, String) -> String
isOrdered tuple =
case tuple of
("A","B","C") as orderedTuple ->
toString orderedTuple ++ " is an ordered tuple."
(_,_,_) as unorderedTuple ->
toString unorderedTuple ++ " is an unordered tuple."
isOrdered myTuple
-- "(\"A\",\"B\",\"C\") is an ordered tuple."
isOrdered ("B", "C", "A")
-- "(\"B\",\"C\",\"A\") is an unordered tuple."
Exact values of comparables can be used to match when destructuring (also works with String, Char, etc. and any Tuple/List/union type built up of them) - @robertjlooby
Compare to tuple, List almost do not support destructuring. One of the case is used to find the first element of a list by utilizing the cons operator, ie ::
w
myList = ["a", "b", "c"]
first list =
case list of
f::_ -> Just f
[] -> Nothing
first myList
-- Just "a"
This is much more cleaner than using List.head
but at the same time increase codebase complexity. By stacking up the ::
operator, we can also use it to match second or other value.
listDescription : List String -> String
listDescription list =
case list of
[] -> "Nothing here !"
[_] -> "This list has one element"
[a,b] -> "Wow we have 2 elements: " ++ a ++ " and " ++ b
a::b::_ -> "A huge list !, The first 2 are: " ++ a ++ " and " ++ b
myRecord = { x = 3, y = 4 }
sum record =
let
{x,y} = record
in
x + y
sum myRecord
-- 7
Or more cleaner:
sum {x,y} =
x + y
Notice that the variable declared on the left side must match the key of record:
sum {a,b} =
a + b
sum myRecord
-- The argument to function `sum` is causing a mismatch.
As long as our variable match one of the key of record, we can ignore other.
onlyX {x} =
x
onlyX myRecord
-- 3 : number
I don't think Elm support destructuring in nested record (I tried) because Elm encourages sparse record
When destructuring a record, you do not have to declare all fields within the braces. Also, you can alias the whole record while destructuring it as a parameter. This is useful if you need shorthand access to some fields but also to the record as a whole.
- nmk
myRecord = { x = 1, y = 2, z = 3}
computeSomething ({x, y} as wholeRecord) =
-- x and y refer to the x and y fields of the passed in record
-- wholeRecord is the complete record
-- i.e. x and wholeRecord.x refer to the same field
-- but z is only accessible as wholeRecord.z
Again, thanks to @robertjlooby, we can even destruct the arguments of union type.
type MyThing
= AString String
| AnInt Int
| ATuple (String, Int)
unionFn : MyThing -> String
unionFn thing =
case thing of
AString s -> "It was a string: " ++ s
AnInt i -> "It was an int: " ++ toString i
ATuple (s, i) -> "It was a string and an int: " ++ s ++ " and " ++ toString i
The "Nested Record" example seems mislabelled. It looks to be an example of pattern matching on nested union types. Also, giving the type definition of
ParseTree
would help enormously for readability of that example. I don't believe Elm supports destructuring of nested records.Eg: This is not possible, but could reasonably be considered consistent with the syntax for destructuring the top level of a record:
But this is possible:
To be extra clear, you can destructure the top level of a record that happens to be nested, you just can't destructure multiple levels in the one expression.
I'd love to be proven wrong if there's some syntax I'm missing.