Mapping over an array would generate one element for each element in the array. Can we map over an optional to generate non-optional values? If we have some, map it; otherwise, return none. Let's examine the following code:
func mapOptionals<T, V>(transform: (T) -> V, input: T?) -> V? {
switch input {
case .some(let value): return transform(value)
case .none: return .none
}
}
Our input variable is a generic optional and we have a transform function that takes input and transforms it into a generic type. The result will be a generic optional type. In the function body, we use pattern matching to return the respective values. Let's test this function:
class User {
var name: String?
}
We create a class named User with an optional variable. We use the variable as follows:
func extractUserName(name: String) -> String {
return "(name)"
}
var nonOptionalUserName: String {
let user = User()
user.name = "John Doe"
let someUserName = mapOptionals(transform: extractUserName,
input: user.name)
return someUserName ?? ""
}
print(nonOptionalUserName)
The result will be a non-optional String. Our mapOptionals function is similar to the fmap function in Haskell, which is defined as the <^> operator.
Let's convert this function to the operator:
precedencegroup AssociativityLeft {
associativity: left
}
infix operator <^> : AssociativityLeft
func <^><T, V>(transform: (T) -> V, input: T?) -> V? {
switch input {
case .some(let value): return transform(value)
case .none: return .none
}
}
Here, we've just defined an infix operator and defined the respective function. Let's try this function to see if it provides the same result:
var nonOptionalUserName2: String {
let user = User()
user.name = "John Doe"
let someUserName = extractUserName <^> user.name
return someUserName ?? ""
}
print(nonOptionalUserName2)
The result is identical to our previous example, but the code is more readable, so we may prefer to use it instead.