Last active
July 20, 2020 14:25
-
-
Save luizmb/fb405dc5e9dfaa264c5e57947cc985b0 to your computer and use it in GitHub Desktop.
Comparison between Binding and Endo when lifting by WritableKeyPath
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import SwiftUI | |
// As pointed by @pointfreeco (no pun intended) here https://twitter.com/pointfreeco/status/1285209505714843648 | |
// these types can't be called Profunctor as they are covariant and contravariant on the very same element (single | |
// generic parameter, instead of 2). That way, function "dimap" here is academically incorrect and either contramap | |
// or pullback should be used, instead. | |
struct Endo<Value> { | |
let run: (Value) -> Value | |
init(_ fn: @escaping (Value) -> Value) { | |
self.run = fn | |
} | |
} | |
// Lift profunctors using pair of functions in opposite direction | |
extension Binding { | |
// pullback would be a better name, check comment on the top | |
func dimap<NewValue>(getter getterMap: @escaping (Value) -> NewValue, setter setterContramap: @escaping (NewValue) -> Value) -> Binding<NewValue> { | |
Binding<NewValue> { | |
getterMap(self.wrappedValue) | |
} set: { | |
self.wrappedValue = setterContramap($0) | |
} | |
} | |
} | |
extension Endo { | |
// pullback would be a better name, check comment on the top | |
func dimap<NewValue>(output outputMap: @escaping (Value) -> NewValue, input inputContramap: @escaping (NewValue) -> Value) -> Endo<NewValue> { | |
Endo<NewValue> { (input: NewValue) -> NewValue in | |
outputMap(self.run(inputContramap(input))) | |
} | |
} | |
} | |
// Lift profunctors using WritableKeyPath | |
extension Binding { | |
// pullback would be a better name, check comment on the top | |
func dimap<NewValue>(_ keyPath: WritableKeyPath<Value, NewValue>) -> Binding<NewValue> { | |
Binding<NewValue> { | |
self.wrappedValue[keyPath: keyPath] | |
} set: { | |
self.wrappedValue[keyPath: keyPath] = $0 | |
} | |
} | |
} | |
extension Endo { | |
// pullback would be a better name, check comment on the top | |
func dimap<NewValue>(_ keyPath: WritableKeyPath<NewValue, Value> /* contravariant WritableKeyPath */) -> Endo<NewValue> { | |
Endo<NewValue> { newValue in | |
var newValueMutable = newValue | |
newValueMutable[keyPath: keyPath] = self.run(newValueMutable[keyPath: keyPath]) | |
return newValueMutable | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment