Skip to content

Instantly share code, notes, and snippets.

@bkase
Created November 2, 2019 23:28
Show Gist options
  • Save bkase/f9e338729eb0ef036b4e5b5b81684fc5 to your computer and use it in GitHub Desktop.
Save bkase/f9e338729eb0ef036b4e5b5b81684fc5 to your computer and use it in GitHub Desktop.
Comonadic UIs in SwiftUI with Bow
import Bow
import SwiftUI
public typealias Component<W: Comonad, V: View> =
Kind<W, SwiftUIBackendOf<CoOf<W, ()>, V>>
func const<A,B>(_ x: A) -> (B) -> A { return { _ in x } }
public final class ComponentView<W: Comonad, V: View>: View {
private var component: Component<W, V>
init(component: Component<W, V>) {
self.component = component
}
private func send(m: CoOf<W, ()>) {
self.component =
Co<W, ()>.pair().zap(
self.component.duplicate()
.map(const), ga: m)
}
public var body: V {
return SwiftUIBackend
.fix(component.extract())
.component(send)
}
}
import Bow
import SwiftUI
enum CoStore { // isomorphic to State monad afaik
static func modify<S>(_ f: @escaping (S) -> S) -> Co<StorePartial<S>, ()> {
Co { w in
let store = Store.fix(w)
return store.render(f(store.state))(())
}
}
}
@available(OSX 10.15, *)
func counter() -> Component<StorePartial<Int>, Button<Text>> {
return Store(state: 0) { count in
SwiftUIBackend { send in
Button<Text>("Total: \(count)") {
send(CoStore.modify{$0+1})
}
}
}
}
import Bow
import BowEffects
import SwiftUI
@available(OSX 10.15, *)
public final class ForSwiftUIBackend<V: View> {}
@available(OSX 10.15, *)
public typealias SwiftUIBackendOf<A, V: View> = Kind<ForSwiftUIBackend<V>, A>
@available(OSX 10.15, *)
public class SwiftUIBackend<A, V: View> : SwiftUIBackendOf<A, V> {
public static func fix(_ ui : SwiftUIBackendOf<A, V>) -> SwiftUIBackend<A, V> {
ui as! SwiftUIBackend<A, V>
}
let component : (@escaping (A) -> ()) -> V
init(_ component: @escaping (@escaping (A) -> ()) -> V) {
self.component = component
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment