Last active
January 25, 2023 17:47
-
-
Save atierian/bd46b3f20799259c112f3bafc29ddf60 to your computer and use it in GitHub Desktop.
(ab)using enum pattern matching to lift generic types to specific types and vice-versa in a type-safe way
This file contains hidden or 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
// MARK: Interface Module | |
struct Request<Output> { | |
let kind: Kind | |
enum Kind { | |
case one((Int) -> Output) | |
case two((String) -> Output) | |
} | |
} | |
extension Request where Output == Int { | |
static func exampleOne() -> Self { | |
.init(kind: .one({ $0 })) | |
} | |
} | |
extension Request where Output == String { | |
static func exampleTwo() -> Self { | |
.init(kind: .two({ $0 })) | |
} | |
} | |
protocol Thing { | |
func doThing<Output>( | |
_ request: Request<Output> | |
) -> Output | |
} | |
// MARK: Implementation Module | |
struct Concrete: Thing { | |
func doThing<Output>( | |
_ request: Request<Output> | |
) -> Output { | |
switch request.kind { | |
case .one(let lift): | |
return lift(42) | |
case .two(let lift): | |
return lift("hello, world!") | |
} | |
} | |
} | |
// MARK: Callsite | |
let thing: Thing = Concrete() | |
thing.doThing(.exampleOne()) | |
thing.doThing(.exampleTwo()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment