Skip to content

Instantly share code, notes, and snippets.

@matux
Created January 21, 2023 13:16
Show Gist options
  • Save matux/befabd629b6c1b06b29b0d7ecabc7381 to your computer and use it in GitHub Desktop.
Save matux/befabd629b6c1b06b29b0d7ecabc7381 to your computer and use it in GitHub Desktop.
Arrow is the algebraic representation of function.
import Swift
public typealias Λ = Arrow // Capital lambda Λ, a computationally aware λ.
/// Λrrow ∎ A general interface to represent a computation.
///
/// Arrows are a new abstract view of computation, defined by John Hughes [Hug00].
/// They serve much the same purpose as monads -- providing a common structure
/// for libraries -- but are more general. In particular they allow notions of
/// computation that may be partially static (independent of the input) or may
/// take multiple inputs. If your application works fine with monads, you might
/// as well stick with them. But if you're using a structure that's very like a
/// monad, but isn't one, maybe it's an arrow.
///
/// - SeeAlso:
/// http://www.cse.chalmers.se/~rjmh/afp-arrows.pdf
/// https://wiki.haskell.org/Arrow_tutorial
/// https://wiki.haskell.org/Category:Arrow
///
/// ### Translation from Mathematician to Person
///
/// An Arrow wraps a function so you can do fp stuff with them.
///
/// ### Legend
///
/// typealias Λ<(A) -> B> = Arrow<(A) -> B> // An Arrow wraps over a λ
/// typealias λa.b = (A) -> B // A λ (or lambda abstraction) generalizes a func
/// typealias ƒ = { x in ƒ(x) } // An ƒ is a pure function
///
/// ### Nominative complicatives
///
/// Unfortunately, like tuples, functions in Swift are structural/non-nominal
/// types, they have no declarative representation in the type system, therefore,
/// they can't be extended, among other things.
/// - SeeAlso:
/// https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#extensions-of-structural-types
/// https://en.wikipedia.org/wiki/Nominal_type_system
/// https://en.wikipedia.org/wiki/Structural_type_system
///
/// Alternatively,
/// you may head to [https://goo.gl/DZugN5].
/// But you didn't hear this from me...
///
/// - SeeAlso:
/// http://www.haskell.org/arrows/
/// https://www.stackage.org/haddock/lts-12.25/base-4.11.1.0/src/Control-Arrow.html
/// http://hackage.haskell.org/package/data-aviary-0.4.0/docs/Data-Aviary-Functional.html
public struct Arrow: Category {
public static var empty = Arrow()
/// ────────────────────────────────────────────────────────────────────·
/// Category |
///
/// ────────────────────────────────────────────────────────────────────·
/// Arrow | The basic arrow typeclass.
///
/// compose/arr ∀ f g . (arr f) ◦ (arr g) = arr (f ◦ g)
/// fst/arr ∀ f . fst (arr f) = arr (fst f)
/// snd/arr ∀ f . snd (arr f) = arr (snd f)
/// product/arr ∀ f g . arr f *** arr g = arr (f *** g)
/// fanout/arr ∀ f g . arr f &&& arr g = arr (f &&& g)
/// compose/fst ∀ f g . (fst f) ◦ (fst g) = fst (f ◦ g)
/// compose/snd ∀ f g . (snd f) ◦ (snd g) = snd (f ◦ g)
/// Lift a function to an arrow.
/// Ordinary functions are arrows.
/// (arr) :: 𝐴𝑟𝑟𝑜𝑤 𝛬 => (𝐵 -> 𝐶) -> 𝛬 𝐵 𝐶
/// Send the first component of the input through the argument arrow, and
/// copy the rest unchanged to the output.
/// (fst) :: 𝐴𝑟𝑟𝑜𝑤 𝛬 => 𝛬 𝐵 𝐶 -> 𝛬 (𝐵, 𝐷) (𝐶, 𝐷)
/// fst = (*** id)
/// A mirror image of `fst`.
/// (snd) :: 𝐴𝑟𝑟𝑜𝑤 𝛬 => 𝛬 𝐵 𝐶 -> 𝛬 (𝐷, 𝐵) (𝐷, 𝐶)
/// snd = (id ***)
/// Split the input between the two argument arrows and combine their
/// output. Note that this is in general not a functor.
/// (***) :: 𝐴𝑟𝑟𝑜𝑤 𝛬 => 𝛬 𝐵 𝐶 -> 𝛬 𝐵' 𝐶' -> 𝛬 (𝐵, 𝐵') (𝐶, 𝐶')
/// f *** g = fst f >>> arr swap >>> fst g >>> arr swap
/// where swap ~(x,y) = (y,x)
/// Fanout: send the input to both argument arrows and combine their output.
/// (&&&) :: 𝐴𝑟𝑟𝑜𝑤 𝛬 => 𝛬 𝐵 𝐶 -> 𝛬 𝐵 𝐶' -> 𝛬 𝐵 (𝐶, 𝐶')
/// f &&& g = arr { b -> (b, b) } >>> f *** g
/// ────────────────────────────────────────────────────────────────────·
/// Kleisli |
///
/// Pre-composition with a pure function.
/// (^>>) :: 𝐴𝑟𝑟𝑜𝑤 𝛬 => (𝐴 ⟶ 𝐵) ⟶ 𝛬 𝐵 𝐶 ⟶ 𝛬 𝐴 𝐶
/// ƒ ^>> Λ = arr ƒ >>> Λ
/// Post-composition with a pure function.
/// (>>^) :: 𝐴𝑟𝑟𝑜𝑤 𝛬 => 𝛬 𝐴 𝐵 ⟶ (𝐵 ⟶ 𝐶) ⟶ 𝛬 𝐴 𝐶
/// Λ >>^ ƒ = Λ >>> arr ƒ
/// Pre-composition with a pure function (right-to-left variant).
/// (<<^) :: 𝐴𝑟𝑟𝑜𝑤 𝛬 => 𝛬 𝐵 𝐶 ⟶ (𝐴 ⟶ 𝐵) ⟶ 𝛬 𝐴 𝐶
/// Λ <<^ ƒ = Λ <<< arr ƒ
/// Post-composition with a pure function (right-to-left variant).
/// (^<<) :: 𝐴𝑟𝑟𝑜𝑤 𝛬 => (𝐵 ⟶ 𝐶) → 𝛬 𝐴 𝐵 → 𝛬 𝐴 𝐶
/// ƒ ^<< Λ = arr ƒ <<< Λ
/// ────────────────────────────────────────────────────────────────────·
/// Choice | Arrow notation for 𝑖𝑓 and 𝑠𝑤𝑖𝑡𝑐ℎ constructs (Choice)
///
/// left/arr ∀ f . left (arr f) = arr (left f)
/// 𝐶ℎ𝑜𝑖𝑐𝑒 𝑎 ⇒ left f = f +++ id
/// 𝐾𝑙𝑒𝑖𝑠𝑙𝑖 𝑎 ⇒ left f = f +++ arr id
/// right/arr ∀ f . right (arr f) = arr (right f)
/// 𝐶ℎ𝑜𝑖𝑐𝑒 𝑎 ⇒ right f = id +++ f
/// 𝐾𝑙𝑒𝑖𝑠𝑙𝑖 𝑎 ⇒ right f = arr id +++ f
/// splat/arr ∀ f g . arr f +++ arr g = arr (f +++ g)
/// 𝐶ℎ𝑜𝑖𝑐𝑒 𝑎 ⇒ f +++ g = (Left ◦ f) ||| (Right ◦ g)
/// 𝐾𝑙𝑒𝑖𝑠𝑙𝑖 𝑎 ⇒ f +++ g = (f >>> arr Left) ||| (g >>> arr Right)
/// fanin/arr ∀ f g . arr f ||| arr g = arr (f ||| g)
/// 𝐶ℎ𝑜𝑖𝑐𝑒 𝑎 ⇒ (|||) = either
/// 𝐾𝑙𝑒𝑖𝑠𝑙𝑖 𝑎 ⇒ 𝑎 f ||| 𝑎 g = 𝑎 (either f g)
/// compose/left ∀ f g . lft f ◦ lft g = lft (f ◦ g)
/// compose/right ∀ f g . rgt f ◦ rgt g = rgt (f ◦ g)
/// Feed marked inputs through the argument arrow, passing the rest through
/// unchanged to the output.
/// left :: 𝐶ℎ𝑜𝑖𝑐𝑒 𝑎 𝐵 𝐶 → 𝑎 (𝐸𝑖𝑡ℎ𝑒𝑟 𝐵 𝐷) (𝐸𝑖𝑡ℎ𝑒𝑟 𝐶 𝐷)
/// (lft) = (+++ id)
/// A mirror image of 'left'.
/// right :: 𝐶ℎ𝑜𝑖𝑐𝑒 𝑎 𝐵 𝐶 → 𝑎 (𝐸𝑖𝑡ℎ𝑒𝑟 𝐷 𝐵) (𝐸𝑖𝑡ℎ𝑒𝑟 𝐷 𝐶)
/// (rgt) = (id +++)
/// Split the input between the two argument arrows, retagging and merging
/// their outputs. Note that this is in general not a functor.
/// (+++) :: 𝐶ℎ𝑜𝑖𝑐𝑒 𝑎 ⇒ 𝑎 𝐵 𝐶 → a 𝐵' 𝐶' → 𝑎 (𝐸𝑖𝑡ℎ𝑒𝑟 𝐵 𝐵') (𝐸𝑖𝑡ℎ𝑒𝑟 𝐶 𝐶')
/// f +++ g = left f >>> arr mirror >>> left g >>> arr mirror
/// where
/// mirror :: Either x y → Either y x
/// mirror (Left x) = Right x
/// mirror (Right y) = Left y
/// Fanin: Split the input between the two argument arrows and merge their
/// outputs.
/// (|||) :: 𝐶ℎ𝑜𝑖𝑐𝑒 𝑎 ⇒ 𝑎 𝐵 𝐷 → 𝑎 𝐶 𝐷 → 𝑎 (Either B C) D
/// f ||| g = f +++ g >>> arr untag
/// where
/// untag (Left x) = x
/// untag (Right y) = y
/// ──────────────────────────────────────────────────────────────────·
/// Apply | Arrow notation for 𝑎𝑝𝑝𝑙𝑖𝑐𝑎𝑡𝑖𝑜𝑛 of arrow inputs to other inputs.
///
/// The 'ArrowApply' class is equivalent to 'Monad': any monad gives rise
/// to a 'Kleisli' arrow, and any instance of 'ArrowApply' defines a monad.
///
/// (app) :: 𝐴𝑟𝑟𝑜𝑤 𝑎 ⇒ 𝑎 (𝑎 𝐵 𝐶, 𝐵) 𝐶
/// app (f, x) = f x
/// app = Kleisli { (Kleisli f, x) ⟼ f x }
/// ArrowMonad
}
// MARK: - ArrowApply . Kleisli
extension Arrow {
/// join :: m (m -> a) -> m -> a
///
/// join λ = { a in λ(a, a) }
/// = Aviary.warbler⠀curry(ƒ)
@_transparent
@inline(__always)
public static func join<A, B>(
_ λ: @escaping (A, A) -> B
) -> (A) -> B {
return λ ◦ dupe
}
/// join :: m (m -> a) -> m -> a
@_transparent
@inline(__always)
public static func join<A, B>(
_ λ: @escaping (A) -> (A) -> B
) -> (A) -> B {
return uncurry(λ) ◦ dupe
}
}
// MARK: - Strong
/// Fanout: send the input to both argument arrows and combine their output.
///
/// Given two functions with the same domain but differing codomain, apply each
/// function to the given value argument and combine the both results in a pair.
///
/// `&&&` arises naturally as the factorizer of `f` and `g`, which are the
/// projections of `𝐴` resulting from the product of `𝐵` and `𝐶`. Such that,
/// for any `𝐴` projected by the product of `𝐵` and `𝐶`, there is a unique
/// morphism (cool for function) `&&&` from `𝐶` that factorizes the projections.
///
/// ┎─╼ f a -> b ╾─╖
/// f &&& g :: a ━━┫ ╠═╸(b, c)
/// ┖─╼ g a -> c ╾─╜
///
/// - SeeAlso:
/// `Combinators.swift:factorize`
/// http://www.cs.man.ac.uk/~hsimmons/MAGIC-CATS/Lecture-09.pdf
@_transparent
public func &&& <A, B, C>(
f: @escaping (A) -> B,
g: @escaping (A) -> C
) -> (A) -> (B, C) {
return { a in (f(a), g(a)) }
}
/// Fanout overload to prevent tuple nesting, ie. (b, (c, d)).
@_transparent
public func &&& <A, B, C, D>(
f: @escaping (A) -> B,
g: @escaping (A) -> (C, D)
) -> (A) -> (B, C, D) {
return { a in g(a) |> { (f(a), $0.0, $0.1) } }
//f &&& g >>> { ($0.0, $0.1.0, $0.1.1) }
}
/// Fanout overload to prevent tuple nesting, ie. (b, (c, d)).
@_transparent
public func &&& <A, B, C, D, E>(
f: @escaping (A) -> B,
g: @escaping (A) -> (C, D, E)
) -> (A) -> (B, C, D, E) {
return { a in g(a) |> { (f(a), $0.0, $0.1, $0.2) } }
}
/// Split the input between the two argument arrows and combine their
/// output. Note that this is in general not a functor.
///
/// `***` can be conceptualized as the cartesian product of two objects that
/// result in two distinct objects each with their own projections giving
/// rise to a unique morphism that factorizes these projections while preserving
/// their distinctiveness.
///
/// ┎── a ╾─ f(a) -> c ╾─╖
/// f *** g :: (a, b)╺━┫ ╠═╸(c, d)
/// ┖── b ╾─ g(b) -> d ╾─╜
@_transparent
public func *** <A, B, C, D>(
f: @escaping (A) -> C,
g: @escaping (B) -> D
) -> (A, B) -> (C, D) {
return { a, b in (f(a), g(b)) }
}
/// Distribute: Overload to prevent tuple nesting, ie. (b, (c, d)).
@_transparent
public func *** <A, B, C, D, E>(
f: @escaping (A) -> C,
g: @escaping (B) -> (D, E)
) -> ((A, B)) -> (C, D, E) {
return { ab in
let gab = g(ab.1)
return (f(ab.0), gab.0, gab.1)
//f *** g >>> { ($0.0, $0.1.0, $0.1.1) }
}
}
/// Split the input between the two argument arrows and combine their
/// output. Note that this is in general not a functor.
///
/// Overload to prevent tuple nesting, ie. (b, (c, d)).
@_transparent
public func *** <A, B, C, D, E, F>(
f: @escaping (A) -> C,
g: @escaping (B) -> (D, E, F)
) -> ((A, B)) -> (C, D, E, F) {
return f *** g >>> { ($0.0, $0.1.0, $0.1.1, $0.1.2) }
}
/// ∏ ∎ Split the input sequentially to the arrow given by duplicating it and
/// combining their output.
///
/// ┎── π₁ fst -> b₁ ╾─╖
/// π ∏ a (,) :: π ━━┫ ╠═╸b (,)
/// ┖── π₂ snd -> b₂ ╾─╜
@_transparent
@inline(__always)
public func *** <A, B>(
π: (A) -> B,
a: (A, A)
) -> (B, B) {
return (π(a.0), π(a.1))
}
/// Π ∎ Split the input sequentially to the side effect given by duplicating it
/// and discarding the void pair.
///
/// ┎── π₁ . fst -> () ╾─╖
/// π ∏ a (,) :: π ━━┫ ╠═╸()
/// ┖── π₂ . snt -> () ╾─╜
//@_transparent
//@inline(__always)
//public func *** <A>(π: (A) -> (), a: (A, A)) {
// π(a.0); π(a.1)
//}
extension Arrow {
/// λSplit ∎ Split the input by duplicating an arrow.
///
/// Duplicate the argument arrow, split the input between the duplication
/// and combine the output in a pair.
///
/// ┎╼ λ a′ -> b′ ╾╖
/// (a′, a″)╺┫ ╠╸(b′, b″)
/// ┖╼ λ a″ -> b″ ╾╜
///
/// split λ = λ *** λ
/// split λ = join(***)(λ)
@_transparent
@inline(__always)
public static func split<A, B>(
_ λ: @escaping (A) -> B
) -> (A, A) -> (B, B) {
return λ *** λ
}
/// Apply Send both argument values to a side effects sequentially and discard
/// both results.
///
/// Duplicate the argument arrow, split the input between the duplication
/// and combine the output in a pair.
///
/// ┎╼ λ a′ -> b′ ╾╖
/// (a′, a″)╺┫ ╠╸(b′, b″)
/// ┖╼ λ a″ -> b″ ╾╜
@_transparent
@inline(__always)
public static func split<A>(
_ λ: @escaping (A) -> ()
) -> (A, A) -> () {
return { x, y in const(())((λ *** λ)(x, y)) }
}
}
// MARK: - Choice
/// Fanin: Split the input between two argument arrows and merge their outputs.
///
/// Where `&&&` is the product factorization, `|||` is the coproduct
/// factorization which in arrows, results in the computational representation
/// of choice.
///
/// ┈┄╴a ╾─ ƒ a -> c ╾─┒ ╔══ Either a -> c ══╕
/// f ||| g :: ┣━━━╣ ├─╸ c
/// ┈┄╴b ╾─ ƒ b -> c ╾─┚ ╚══ Either b -> c ══╛
@_transparent
@inline(__always)
public func ||| <A, B, C>(
_ ƒ: @escaping (A) -> C,
_ g: @escaping (B) -> C
) -> (Either<A, B>) -> C {
return { $0.switchCase(preference: ƒ, alternative: g) }
}
/// Fanin: Split the input between two argument arrows and merge their outputs.
///
/// Where `&&&` is the product factorization, `|||` is the coproduct
/// factorization which in arrows, results in the computational representation
/// of choice.
///
/// ┈┄╴a ╾─ ƒ a -> c ╾─┒ ╔══ Either a -> c ══╕
/// f ||| g :: ┣━━━╣ ├─╸ c
/// ┈┄╴b ╾─ ƒ b -> c ╾─┚ ╚══ Either b -> c ══╛
@_transparent
@inline(__always)
public func ||| <A, C>(
_ ƒ: @escaping (A) -> C,
_ g: @escaping () -> C
) -> (A?) -> C {
return Either.init >>> ƒ ||| g
}
/// Splat: Split the input between both argument arrows, then retag and merge
/// their outputs into Eithers.
///
/// ┈┄╴a ╾─ ƒ a -> b ╾─┒ ╔══ Either a -> b ══╗
/// f +++ g :: ┣━━━╣ ╠═╸|||╺─ Either(b, d)
/// ┈┄╴c ╾─ g c -> d ╾─┚ ╚══ Either b -> d ══╝
@_transparent
@inline(__always)
public func +++ <A, B, C, D>(
ƒ: @escaping (A) -> B,
g: @escaping (C) -> D
) -> (Either<A, C>) -> (Either<B, D>) {
return Either.preference ◦ ƒ ||| Either.alternative ◦ g
}
// MARK: - ☠︎ Graveyard ☠︎
//extension Arrow {
//
// /// Fanout by duplicating the single argument arrow computation.
// ///
// /// ┎─╼ a ╾─╼ λ(a) -> b′ ╾──╖
// /// fanout λ :: (a)╺━┫ ╠═╸(b′, b″)
// /// ┖─╼ a ╾─╼ λ(a) -> b″ ╾──╜
// ///
// /// fanout λ a = split(λ, duplicate a)
// /// fanout λ a = join(&&&)⠀λ a
// /// fanout λ a = (λ &&& λ)(a)
// @available(*, unavailable, message: "Use duplicate(x)")
// public static func fanout<A, B>(
// _ λ: (A) -> B,
// _ a: A
// ) -> (B, B) {
// //return nonescaping(join(&&&)) { $0(λ)(a) }
// return duplicate(λ(a))
// }
//
// /// ┎─╼ a ╾─╼ λ(a) -> b′ ╾──╖
// /// fanout λ :: (a)╺━┫ ╠═╸(b′, b″)
// /// ┖─╼ a ╾─╼ λ(a) -> b″ ╾──╜
// ///
// /// fanout λ = λ &&& λ
// /// fanout λ = λ >>> duplicate = { a in duplicate(λ(a)) }
// /// fanout λ = λ >>> ƒid &&& ƒid
// /// fanout λ = curry(fanout)(λ)
// /// fanout λ = join(&&&)(λ)
// /// fanout λ = { aa in (ƒ(aa.0, aa.1), ƒ(aa.0, aa.1)) }
// @available(*, unavailable, message: "Use duplicate(x)")
// public static func fanout<A, B>(
// _ λ: @escaping (A) -> B
// ) -> (A)-> (B, B) {
// return λ &&& λ
// }
//
// //
// public static func __λfanout<A, B>(
// _ λ: @escaping (A) -> (A) -> B
// ) -> (A) -> (B, B) {
// return { a in (λ(a)(a), λ(a)(a)) }
// }
//
// public static func __bifanout<A, B>(
// _ λ: @escaping (A, A) -> B
// ) -> ((A, A)) -> (B, B) {
// return join(&&&)(λ) // aa in (ƒ(aa.0, aa.1), ƒ(aa.0, aa.1))
// }
//}
// MARK: - Universal isomorphism (Curry)
// - Note: Mostly research
// https://en.wikipedia.org/wiki/Category_of_relations
// https://en.wikipedia.org/wiki/Hom_functor#Internal_Hom_functor
// https://en.wikipedia.org/wiki/Apply
// https://en.wikipedia.org/wiki/Currying
// https://en.wikipedia.org/wiki/Simply_typed_lambda_calculus
// https://en.wikipedia.org/wiki/Exponential_object
// https://en.wikipedia.org/wiki/Tensor-hom_adjunction
// https://en.wikipedia.org/wiki/Hermitian_adjoint
// https://en.wikipedia.org/wiki/Adjoint_functors
// https://en.wikipedia.org/wiki/Function_space
// https://en.wikipedia.org/wiki/List_of_exponential_topics
// https://en.wikipedia.org/wiki/Category:Exponentials
// https://en.wikipedia.org/wiki/Exponentiation
// The Arrow category possesses an internal Hom functor making it a closed
// category
//prefix operator ¢/
//postfix operator ⁄¢
//
//// MARK: - curry
//
//public prefix func ¢/ <A, B, Γ>(_ λ: @escaping (A, B) -> Γ) -> (A) -> (B) -> Γ { return *ƒ }
//public postfix func /¢ <A, B, Γ>(_ λ: @escaping (A, B) -> Γ) -> (A) -> (B) -> Γ { return *ƒ }
//public prefix func ¢/ <A, B, C, Γ>(_ λ: @escaping (A, B, C) -> Γ) -> (A) -> (B) -> (C) -> Γ { return *ƒ }
//public postfix func /¢ <A, B, C, Γ>(_ λ: @escaping (A, B, C) -> Γ) -> (A) -> (B) -> (C) -> Γ { return *ƒ }
//extension Arrow {
// // bind :: Monad m => (a -> m b) -> m a -> m b
// @_transparent
// public func ƒbind <A, B, C>(
// λ: @escaping (B) -> (A) -> C,
// g: @escaping (A) -> B
// ) -> (A) -> C {// ƒ(g(a))(a)
// return { a in ƒ⠀g(a)⠀a }
// }
// @_transparent
// public static func first<A, A', B>(
// _ pair: (α: A, β: B)
// ) -> (_ λ: (A) -> A') -> (A', B) {
// return { ƒ in (ƒ⠀pair.α, pair.β) }
// }
//
// @_transparent
// public static func second<A, B, B'>(
// _ pair: (α: A, β: B)
// ) -> (_ g: (B) -> B') -> (A, B') {
// return { g in (pair.α, g⠀pair.β) }
// }
// MARK: - ArrowBind
// return :: a -> m a
// @_transparent
// public static func ƒreturn<A, B>(
// _ α: A
// ) -> ((A) -> B) -> B {
// return { ƒ in ƒ⠀α }
// }
//}
//public let split = curry((***)) // TODO: arrow *** curry won't work
//@_transparent
//public func split <A, B, A', B'>(
// λ: @escaping (A) -> B
//) -> (@escaping (A') -> B') -> (A, A') -> (B, B') {
// return { g in { α, α' in (ƒ⠀α, g⠀α') } }
//}
// MARK: - ArrowApply
//class Arrow a => ArrowApply a where
// app :: a (a b c, b) c
//
//instance ArrowApply (->) where
// app (f,x) = f x
//
//instance Monad m => ArrowApply (Kleisli m) where
// app = Kleisli (\(Kleisli f, x) -> f x)
//
// | The 'ArrowApply' class is equivalent to 'Monad': any monad gives rise
// to a 'Kleisli' arrow, and any instance of 'ArrowApply' defines a monad.
// MARK: - ArrowMonad
//instance Arrow a => Functor (ArrowMonad a) where
// fmap f (ArrowMonad m) = ArrowMonad $ m >>> arr f
//instance Arrow a => Applicative (ArrowMonad a) where
// pure x = ArrowMonad (arr (const x))
// ArrowMonad f <*> ArrowMonad x = ArrowMonad (f &&& x >>> arr (uncurry id))
//instance ArrowApply a => Monad (ArrowMonad a) where
// ArrowMonad m >>= f = ArrowMonad $
// m >>> arr (\x -> let ArrowMonad h = f x in (h, ())) >>> app
//// (>>=) :: m a(ab) -> (a(b) -> m b(ac)) -> m b(ac)
//@_transparent
//public func >>= <A, B, C>(
// λ: @escaping (A) -> B,
// g: @escaping (B) -> (A) -> C
//) -> (A) -> C {
// return { α in (ƒ >>> g)⠀α⠀α }
//}
//// (=>>) :: Comonad w => (w a -> b) -> w a -> w b
//@_transparent
//public static func =>> <A, B, C>(
// λ: @escaping (A) -> (B) -> C,
// g: @escaping (A) -> B
//) -> (A) -> C {
// return ƒ ◦ duplicate
// //map(ƒ) ◦ duplicate
//}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment