Last active
January 7, 2018 20:43
-
-
Save pteasima/336dafec2f01ec9f0f7cd3c2656f7436 to your computer and use it in GitHub Desktop.
tagless-map-problem
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
protocol Effect { | |
associatedtype Action | |
static var none: Self { get } | |
static func batch(_ effects: [Self]) -> Self | |
// ! What should we return? Effect has associated types. Effect<B>, Self<B> are not possible. | |
// Feels like a usecase for type-erasure but didnt get me anywhere (+ I feel like a type-erased AnyEffect defeats the purpose of tagless) | |
//func map<B>(_ transform: @escaping (Action) -> B) -> ??? | |
// this works but is too general, we want to keep OtherEffect fixed to the same implementation as Self | |
func map<OtherEffect>(_ transform: @escaping (Action) -> OtherEffect.Action) -> OtherEffect where OtherEffect: Effect | |
} | |
struct Execute<A> { | |
let run: (_ callback: @escaping (A) -> ()) -> () | |
} | |
extension Execute: Effect { | |
typealias Action = A | |
static var none: Execute<A> { | |
return Execute { _ in () } | |
} | |
static func batch(_ effects: [Execute<A>]) -> Execute<A> { | |
return Execute { callback in | |
for c in effects { | |
c.run(callback) | |
} | |
} | |
} | |
// ugly runtime typechecking. Lucking we have .none so we dont have to trap, but I still dont like this | |
func map<OtherEffect>(_ transform: @escaping (A) -> OtherEffect.Action) -> OtherEffect where OtherEffect : Effect { | |
guard OtherEffect.self == Execute<OtherEffect.Action>.self else { | |
assertionFailure() | |
return .none | |
} | |
return Execute<OtherEffect.Action> { callback in | |
self.run { callback(transform($0)) } | |
} as! OtherEffect | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment