Created
January 21, 2023 13:16
-
-
Save matux/befabd629b6c1b06b29b0d7ecabc7381 to your computer and use it in GitHub Desktop.
Arrow is the algebraic representation of function.
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
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