Skip to content

Instantly share code, notes, and snippets.

@bkase
Last active December 6, 2019 00:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bkase/86b40d80f3e44594917fd39b8fe1fe02 to your computer and use it in GitHub Desktop.
Save bkase/86b40d80f3e44594917fd39b8fe1fe02 to your computer and use it in GitHub Desktop.
Co.swift seems to work. Read NaturalSubclass.swift for what doesn't work, Natural.swift for what seems to work, and Co_old.swift for where it breaks down
import Bow
// This version of Co seems to work even thoug it's a bit gross to deal with Any
// Think of this as an example of how to deal with rank2 type polymorphism -- you only
// deal with Any in the constructor, even `runCo` has a generic interface.
// newtype Co w a = Co (forall r. w (a -> r) -> r)
public final class ForCo {}
public final class CoPartial<W: Comonad>: Kind<ForCo, W> {}
public typealias CoOf<W: Comonad, A> = Kind<CoPartial<W>, A>
/// (Co w) gives you "the best" pairing monad for any comonad w
/// In other words, an explorer for the state space given by w
public class Co<W: Comonad, A> : CoOf<W, A> {
internal let cow : (Kind<W, (A) -> Any>) -> Any
public static func fix(_ value : CoOf<W, A>) -> Co<W, A> {
value as! Co<W, A>
}
public static func pair() -> Pairing<W, CoPartial<W>> {
Pairing{ wab in
{ cowa in
Co<W, /*A*/Any>.fix(cowa).runCo(wab)
}
}
}
public init(_ cow: @escaping /*forall R.*/(Kind<W, (A) -> /*R*/Any>) -> /*R*/Any) {
self.cow = cow
}
public func runCo<R>(_ w: Kind<W, (A) -> R>) -> R {
unsafeBitCast(self.cow, to:((Kind<W, (A) -> R>) -> R).self) (w)
}
}
extension CoPartial: Functor {
public static func map<A, B>(_ fa: CoOf<W, A>, _ f: @escaping (A) -> B) -> CoOf<W, B> {
Co<W, B> { b in
Co<W, A>.fix(fa).runCo(b.map({$0 <<< f}))
}
}
}
extension CoPartial: Applicative {
public static func ap<A, B>(_ ff: CoOf<W, (A) -> B>, _ fa: CoOf<W, A>) -> CoOf<W, B> {
let f = Co<W, (A) -> B>.fix(ff).cow
let a = Co<W, A>.fix(fa).cow
return Co<W, B> { w in
f(
w.coflatMap{ wf in
{ g in
a(wf.map{$0 <<< g})
}
}
)
}
}
public static func pure<A>(_ a: A) -> CoOf<W, A> {
return Co<W, A> { w in
w.extract()(a)
}
}
}
extension CoPartial: Monad {
public static func flatMap<A, B>(_ fa: CoOf<W, A>, _ f: @escaping (A) -> CoOf<W, B>) -> CoOf<W, B> {
let k: (Kind<W, (A) -> Any>) -> Any = Co<W, A>.fix(fa).cow
return Co<W, B> { w in
k (
w.coflatMap{ wa in
{ a in
Co<W, B>.fix(f(a)).runCo(wa)
}
}
)
}
}
public static func tailRecM<A, B>(_ a: A, _ f: @escaping (A) -> Kind<CoPartial<W>, Either<A, B>>) -> Kind<CoPartial<W>, B> {
fatalError("TODO")
}
}
import Bow
/// `Co w` gives you the monad that pairs with the comonad `w`, think of it as the monad used to explore the state space induced by `w`
/// `newtype Co w a = Co (forall r. w (a -> r) -> r)`
// get the existential in there once the type constructor is fully applied
public final class WithWitness<X, E>{}
public final class ForCo {}
public final class CoPartial<W, E: CoExistentialWitness>: Kind<ForCo, WithWitness<W, E>> where E.W == W {}
public typealias CoOf<W, A, E: CoExistentialWitness> = Kind<CoPartial<W, E>, A> where E.W == W
public protocol CoExistentialWitness {
associatedtype W: Comonad
associatedtype A
func apply<R>(_ a : Kind<W, (A) -> R>) -> R
}
// in order to map, ap, bind, etc. we also have to change our witness
public struct MapCoExistentialWitness<E: CoExistentialWitness, B>: CoExistentialWitness {
public typealias W = E.W
public typealias A = B
public let witness: E
public let f: (E.A) -> B
public func apply<R>(_ b : Kind<W, (B) -> R>) -> R {
self.witness.apply(b.map({$0 <<< self.f}))
}
}
public struct ApCoExistentialWitness<E: CoExistentialWitness, B>: CoExistentialWitness {
public typealias W = E.W
public typealias A = B
public let witness: E
public let ff: CoOf<W, (E.A) -> B, MapCoExistentialWitness<E, (E.A) -> B>>
public func apply<R>(_ b : Kind<W, (B) -> R>) -> R {
let f = Co<W, (E.A) -> B, MapCoExistentialWitness<E, (E.A) -> B>>.fix(ff)
return f.witness.apply(
b.coflatMap{ wf in
{ g in
self.witness.apply(wf.map{$0 <<< g})
}
}
)
}
}
public class Co<W, A, E: CoExistentialWitness> : CoOf<W, A, E> where E.W == W, E.A == A {
public let witness: E
public static func fix(_ value : CoOf<W, A, E>) -> Co<W, A, E> {
value as! Co<W, A, E>
}
public init(witness: E) {
self.witness = witness
}
// this is the function that we can't implement with the subclass approach as seen in Day.swift
// but here it works!
public func runCo<R>(_ w: Kind<W, (A) -> R>) -> R {
self.witness.apply(w)
}
}
// Unfortunately, we get a bit stuck here
extension CoPartial: Functor {
// this is the map we want to implement
// Note: `CoOf<W, A, E>` as defined above doesn't work here in place of `Kind<CoPartial<W, E>, A>` due to the where clause in the typealias (I think)
public static func map<A, B>(_ fa: Kind<CoPartial<W, E>, A>, _ f: @escaping (A) -> B) -> Kind<CoPartial<W, E>, B> {
fatalError("Can't implement the map we need")
}
// this is the one we can implement
// more like map on some sort of indexed functor?
public static func map<A, B>(_ fa: CoOf<W, A, E>, _ f: @escaping (A) -> B) -> CoOf<W, B, MapCoExistentialWitness<E, B>> where E.A == A, E.W == W {
Co<W, B, MapCoExistentialWitness<E, B>>(witness: MapCoExistentialWitness(witness: Co.fix(fa).witness, f: f))
}
}
// it seems like Ap, Bind, etc would work if only we could deal with that annoying `E` parameter...
import Bow
/// Natural transformation: `type Natural f g = forall x. f x -> g x` aka `f ~> g`
// get the existential in there once the type constructor is fully applied
public final class WithWitness<X, E>{}
public final class ForNatural {}
public final class NaturalPartial<F: Functor>: Kind<ForNatural, F> {}
public class NaturalOf<F: Functor, G: Functor, E: NaturalExistentialWitness>: Kind<NaturalPartial<F>, WithWitness<G, E>> {}
public protocol NaturalExistentialWitness {
// the rank1 foralls go here
associatedtype F: Functor
associatedtype G: Functor
// the rank2 foralls go here
func apply<A>(_ a : Kind<F, A>) -> Kind<G, A>
}
class Natural<F, G, E: NaturalExistentialWitness>: NaturalOf<F, G, E> where E.F == F, E.G == G {
let witness: E
init(witness: E) {
self.witness = witness
}
public static func fix(_ value : NaturalOf<F, G, E>) -> Natural<F, G, E> {
value as! Natural<F, G, E>
}
func run<A>(_ a: Kind<F, A>) -> Kind<G, A> {
self.witness.apply(a)
}
}
// example
// existential witnesses are types
// witness for "Id ~> Id"
class NaturalWitnessIdId: NaturalExistentialWitness {
typealias F = ForId
typealias G = ForId
func apply<A>(_ a: IdOf<A>) -> IdOf<A> {
Id.fix(a)
}
}
let ididTransformation = Natural<ForId, ForId, NaturalWitnessIdId>(witness: NaturalWitnessIdId())
// The inner forall works!
print(ididTransformation.run(Id<Int>(4)))
print(ididTransformation.run(Id<String>("hello")))
import Bow
/// Natural transformation: `type Natural f g = forall x. f x -> g x` aka `f ~> g`
// Here we'll use the Day.swift approach, and it doesn't work
public final class ForNatural {}
public final class NaturalPartial<F: Functor>: Kind<ForNatural, F> {}
public typealias NaturalOf<F: Functor, G: Functor> = Kind<NaturalPartial<F>, G>
class Natural<F: Functor, G: Functor>: NaturalOf<F, G> {
// this is not really a true rank2 forall as we'll see below
static func from<A>(f: @escaping (Kind<F, A>) -> Kind<G, A>) -> Natural<F, G> {
DefaultNatural<F,G,A>(f: f)
}
// the problem is this function -- we can't just cast because `DefaultNatural` cast only succeeds if you use the same `A` that it was initialized with
func run<A>(a: Kind<F, A>) -> Kind<G, A> {
(self as! DefaultNatural<F, G, A>).f(a)
}
}
class DefaultNatural<F: Functor, G: Functor, A>: Natural<F, G> {
let f : (Kind<F, A>) -> Kind<G, A>
init(f: @escaping (Kind<F, A>) -> Kind<G, A>) {
self.f = f
}
}
// the compiler makes us specialize `Id` here to something (here I picked Any),
// but I want to say "forall a"
let ididTransform = Natural<ForId, ForId>.from(f: { Id<Any>.fix($0) })
print(ididTransform.run(a: Id<Int>(4)))
// Could not cast value of type 'BowTestProject.DefaultNatural<Bow.ForId, Bow.ForId, Any>' (0x7fff98b9a518) to 'BowTestProject.DefaultNatural<Bow.ForId, Bow.ForId, Swift.Int>' (0x7fff98b9abe0).
print(ididTransform.run(a: Id<String>("Hello")))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment