Created
January 29, 2018 04:10
-
-
Save avaidyam/ab1dbf4fda5107b2666aa7a662f528ca to your computer and use it in GitHub Desktop.
Swift (naive) partial application for async functions
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 Dispatch | |
/// Manages async state for a function from its exterior. | |
fileprivate final class AsyncSlot<T> { | |
private let semaphore = DispatchSemaphore(value: 0) | |
private var value: T! = nil | |
fileprivate func fill(_ value: T) { | |
self.value = value | |
self.semaphore.signal() | |
} | |
fileprivate func retrieve() -> T { | |
self.semaphore.wait() | |
return self.value | |
} | |
fileprivate static func perform<X>(_ handler: (AsyncSlot<X>) -> ()) -> X { | |
let slot = AsyncSlot<X>() | |
handler(slot) | |
return slot.retrieve() | |
} | |
} | |
public typealias SyncUnit0_0 = (() -> ()) | |
public typealias AsyncUnit0_0 = (((@escaping () -> Void)) -> Void) | |
public func await(_ f: @escaping AsyncUnit0_0) -> SyncUnit0_0 { | |
return { AsyncSlot<()>.perform { slot in (f() { slot.fill(()) }) } } | |
} | |
public typealias SyncUnit1_0<A> = ((A) -> ()) | |
public typealias AsyncUnit1_0<A> = ((A, (@escaping () -> Void)) -> Void) | |
public func await<A>(_ f: @escaping AsyncUnit1_0<A>) -> SyncUnit1_0<A> { | |
return { a in AsyncSlot<()>.perform { slot in (f(a) { slot.fill(()) }) } } | |
} | |
public typealias SyncUnit2_0<A, B> = ((A, B) -> ()) | |
public typealias AsyncUnit2_0<A, B> = ((A, B, (@escaping () -> Void)) -> Void) | |
public func await<A, B>(_ f: @escaping AsyncUnit2_0<A, B>) -> SyncUnit2_0<A, B> { | |
return { a, b in AsyncSlot<()>.perform { slot in (f(a, b) { slot.fill(()) }) } } | |
} | |
public typealias SyncUnit3_0<A, B, C> = ((A, B, C) -> ()) | |
public typealias AsyncUnit3_0<A, B, C> = ((A, B, C, (@escaping () -> Void)) -> Void) | |
public func await<A, B, C>(_ f: @escaping AsyncUnit3_0<A, B, C>) -> SyncUnit3_0<A, B, C> { | |
return { a, b, c in AsyncSlot<()>.perform { slot in (f(a, b, c) { slot.fill(()) }) } } | |
} | |
public typealias SyncUnit0_1<X> = (() -> (X)) | |
public typealias AsyncUnit0_1<X> = (((@escaping (X) -> Void)) -> Void) | |
public func await<X>(_ f: @escaping AsyncUnit0_1<X>) -> SyncUnit0_1<X> { | |
return { AsyncSlot<(X)>.perform { slot in (f() { x in slot.fill((x)) }) } } | |
} | |
public typealias SyncUnit1_1<A, X> = ((A) -> (X)) | |
public typealias AsyncUnit1_1<A, X> = ((A, (@escaping (X) -> Void)) -> Void) | |
public func await<A, X>(_ f: @escaping AsyncUnit1_1<A, X>) -> SyncUnit1_1<A, X> { | |
return { a in AsyncSlot<(X)>.perform { slot in (f(a) { x in slot.fill((x)) }) } } | |
} | |
public typealias SyncUnit2_1<A, B, X> = ((A, B) -> (X)) | |
public typealias AsyncUnit2_1<A, B, X> = ((A, B, (@escaping (X) -> Void)) -> Void) | |
public func await<A, B, X>(_ f: @escaping AsyncUnit2_1<A, B, X>) -> SyncUnit2_1<A, B, X> { | |
return { a, b in AsyncSlot<(X)>.perform { slot in (f(a, b) { x in slot.fill((x)) }) } } | |
} | |
public typealias SyncUnit3_1<A, B, C, X> = ((A, B, C) -> (X)) | |
public typealias AsyncUnit3_1<A, B, C, X> = ((A, B, C, (@escaping (X) -> Void)) -> Void) | |
public func await<A, B, C, X>(_ f: @escaping AsyncUnit3_1<A, B, C, X>) -> SyncUnit3_1<A, B, C, X> { | |
return { a, b, c in AsyncSlot<(X)>.perform { slot in (f(a, b, c) { x in slot.fill((x)) }) } } | |
} | |
public typealias SyncUnit0_2<X, Y> = (() -> (X, Y)) | |
public typealias AsyncUnit0_2<X, Y> = (((@escaping (X, Y) -> Void)) -> Void) | |
public func await<X, Y>(_ f: @escaping AsyncUnit0_2<X, Y>) -> SyncUnit0_2<X, Y> { | |
return { AsyncSlot<(X, Y)>.perform { slot in (f() { x, y in slot.fill((x, y)) }) } } | |
} | |
public typealias SyncUnit1_2<A, X, Y> = ((A) -> (X, Y)) | |
public typealias AsyncUnit1_2<A, X, Y> = ((A, (@escaping (X, Y) -> Void)) -> Void) | |
public func await<A, X, Y>(_ f: @escaping AsyncUnit1_2<A, X, Y>) -> SyncUnit1_2<A, X, Y> { | |
return { a in AsyncSlot<(X, Y)>.perform { slot in (f(a) { x, y in slot.fill((x, y)) }) } } | |
} | |
public typealias SyncUnit2_2<A, B, X, Y> = ((A, B) -> (X, Y)) | |
public typealias AsyncUnit2_2<A, B, X, Y> = ((A, B, (@escaping (X, Y) -> Void)) -> Void) | |
public func await<A, B, X, Y>(_ f: @escaping AsyncUnit2_2<A, B, X, Y>) -> SyncUnit2_2<A, B, X, Y> { | |
return { a, b in AsyncSlot<(X, Y)>.perform { slot in (f(a, b) { x, y in slot.fill((x, y)) }) } } | |
} | |
public typealias SyncUnit3_2<A, B, C, X, Y> = ((A, B, C) -> (X, Y)) | |
public typealias AsyncUnit3_2<A, B, C, X, Y> = ((A, B, C, (@escaping (X, Y) -> Void)) -> Void) | |
public func await<A, B, C, X, Y>(_ f: @escaping AsyncUnit3_2<A, B, C, X, Y>) -> SyncUnit3_2<A, B, C, X, Y> { | |
return { a, b, c in AsyncSlot<(X, Y)>.perform { slot in (f(a, b, c) { x, y in slot.fill((x, y)) }) } } | |
} | |
public typealias SyncUnit0_3<X, Y, Z> = (() -> (X, Y, Z)) | |
public typealias AsyncUnit0_3<X, Y, Z> = (((@escaping (X, Y, Z) -> Void)) -> Void) | |
public func await<X, Y, Z>(_ f: @escaping AsyncUnit0_3<X, Y, Z>) -> SyncUnit0_3<X, Y, Z> { | |
return { AsyncSlot<(X, Y, Z)>.perform { slot in (f() { x, y, z in slot.fill((x, y, z)) }) } } | |
} | |
public typealias SyncUnit1_3<A, X, Y, Z> = ((A) -> (X, Y, Z)) | |
public typealias AsyncUnit1_3<A, X, Y, Z> = ((A, (@escaping (X, Y, Z) -> Void)) -> Void) | |
public func await<A, X, Y, Z>(_ f: @escaping AsyncUnit1_3<A, X, Y, Z>) -> SyncUnit1_3<A, X, Y, Z> { | |
return { a in AsyncSlot<(X, Y, Z)>.perform { slot in (f(a) { x, y, z in slot.fill((x, y, z)) }) } } | |
} | |
public typealias SyncUnit2_3<A, B, X, Y, Z> = ((A, B) -> (X, Y, Z)) | |
public typealias AsyncUnit2_3<A, B, X, Y, Z> = ((A, B, (@escaping (X, Y, Z) -> Void)) -> Void) | |
public func await<A, B, X, Y, Z>(_ f: @escaping AsyncUnit2_3<A, B, X, Y, Z>) -> SyncUnit2_3<A, B, X, Y, Z> { | |
return { a, b in AsyncSlot<(X, Y, Z)>.perform { slot in (f(a, b) { x, y, z in slot.fill((x, y, z)) }) } } | |
} | |
public typealias SyncUnit3_3<A, B, C, X, Y, Z> = ((A, B, C) -> (X, Y, Z)) | |
public typealias AsyncUnit3_3<A, B, C, X, Y, Z> = ((A, B, C, (@escaping (X, Y, Z) -> Void)) -> Void) | |
public func await<A, B, C, X, Y, Z>(_ f: @escaping AsyncUnit3_3<A, B, C, X, Y, Z>) -> SyncUnit3_3<A, B, C, X, Y, Z> { | |
return { a, b, c in AsyncSlot<(X, Y, Z)>.perform { slot in (f(a, b, c) { x, y, z in slot.fill((x, y, z)) }) } } | |
} |
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 Dispatch | |
public func test(a: Int, b: Int, _ handler: @escaping (Int?) -> ()) { | |
DispatchQueue.global(qos: .background).async { | |
handler(a + b) | |
} | |
} | |
test(a: 1, b: 1) { print("global", $0) } | |
print("main", await(test(a:b:_:))(1, 1)) | |
dispatchMain() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Realistically, you don't even need
AsyncSlot<T>
- just a local tuple(DispatchSemaphore, T)
. The current implementation ofAsyncSlot<T>
can be an issue because it expects that it will first beretrieve()
'ed and thenfill()
'ed, but can't handle anything outside of that exact order. In addition, it creates the semaphore uponinit
, where it may not be needed at all if the order of operations is reversed.