Skip to content

Instantly share code, notes, and snippets.

@luizmb
Last active July 20, 2020 14:25
Show Gist options
  • Save luizmb/fb405dc5e9dfaa264c5e57947cc985b0 to your computer and use it in GitHub Desktop.
Save luizmb/fb405dc5e9dfaa264c5e57947cc985b0 to your computer and use it in GitHub Desktop.
Comparison between Binding and Endo when lifting by WritableKeyPath
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