This episode is for subscribers only. To access it, and all past and future episodes, become a subscriber today!See subscription optionsorLog in
Sign up for our weekly newsletter to be notified of new episodes, and unlock access to any subscriber-only episode of your choosing!Sign up for free episode
In the last episode we explored how functional setters allow us to dive deeper into nested structures to perform transformations while leaving everything else in the structure fixed. We played around with some toy examples, like nested tuples and arrays, and we showed off some pretty impressive stuff, but at the end of the day we aren’t typically transforming tuples. Instead, we have real world data with structs. We want to bring all the ideas from the previous episode into the world of structs so that we can transform a deeply nested struct in a simple, expressive manner. To do this, we are going to leverage Swift’s key paths!
In this episode we used
Dictionary’s subscript key path without explaining it much. For a
one can construct a key path
\.[key] for setting a value associated with
key. What is the
signature of the setter
prop(\.[key])? Explain the difference between this setter and the setter
prop(\.[key]) <<< map, where
map is the optional map.
Set<A> type in Swift does not have any key paths that we can use for adding and removing values.
However, that shouldn’t stop us from defining a functional setter! Define a function
(A) -> ((Bool) -> Bool) -> (Set<A>) -> Set<A>, which is a functional setter that allows one
to add and remove a value
a: A to a set by providing a transformation
(Bool) -> Bool, where the
input determines if the value is already in the set and the output determines if the value should be
Generalizing exercise #1 a bit, it turns out that all subscript methods on a type get a compiler generated key path. Use array’s subscript key path to uppercase the first favorite food for a user. What happens if the user’s favorite food array is empty?
Recall from a previous episode that the free
on arrays has the signature
((A) -> Bool) -> ([A]) -> [A]. That’s kinda setter-like! What does the
prop(\User.favoriteFoods) <<< filter represent?
Result<Value, Error> type, and create
error setters for safely traversing
into those cases.
Is it possible to make key path setters work with
Redefine some of our setters in terms of
inout. How does the type signature and composition change?
Stephen spoke about functional setters at the Functional Swift Conference if you’re looking for more material on the topic to reinforce the ideas.
Conal Elliott describes the setter composition we explored in this episode from first principles, using
Haskell. In Haskell, the backwards composition operator
<<< is written simply as a dot
., which means
g . f is the composition of two functions where you apply
f first and then
g. This means if had
a nested value of type
([(A, B)], C) and wanted to create a setter that transform the
B part, you would
simply write it as
first.map.second, and that looks eerily similar to how you would field access in
the OOP style!