diff --git a/prototype/Doubt/Cofree.swift b/prototype/Doubt/Cofree.swift index f9f478631..72f9b9d19 100644 --- a/prototype/Doubt/Cofree.swift +++ b/prototype/Doubt/Cofree.swift @@ -124,7 +124,7 @@ extension CofreeType { /// /// This is an _anamorphism_ (from the Greek “ana,” “upwards”; compare “anabolism”), a generalization of unfolds over regular trees (and datatypes isomorphic to them). The initial seed is used as the annotation of the returned value. The continuation of the structure is unpacked by applying `annotate` to the seed and mapping the resulting syntax’s values recursively. In this manner, the structure is unfolded bottom-up, starting with `seed` and ending at the leaves. /// - /// As this is the dual of `Free.iterate`, it’s unsurprising that we have a similar guarantee: coiteration is linear in the size of the constructed tree. + /// As this is the dual of `cata`, it’s unsurprising that we have a similar guarantee: coiteration is linear in the size of the constructed tree. public static func ana(unfold: Annotation -> Syntax)(_ seed: Annotation) -> Self { return (Introduce(seed) <<< { $0.map(ana(unfold)) } <<< unfold) <| seed } diff --git a/prototype/Doubt/Free.swift b/prototype/Doubt/Free.swift index f8b3c3a32..7162cc19c 100644 --- a/prototype/Doubt/Free.swift +++ b/prototype/Doubt/Free.swift @@ -26,14 +26,14 @@ public enum Free: CustomDebugStringConvertible { /// /// `Pure` values are simply unpacked. `Roll` values are mapped recursively, and then have `transform` applied to them. /// - /// This forms a _catamorphism_ (from the Greek “cata”, “downwards”; compare “catastrophe”), a generalization of folds over regular trees (and datatypes isomorphic to them). It operates at the leaves first, and then branches near the periphery, recursively collapsing values by whatever is computed by `transform`. Catamorphisms are themselves an example of _recursion schemes_, which characterize specific well-behaved patterns of recursion. This gives `iterate` some useful properties for computations performed over trees. + /// This forms a _catamorphism_ (from the Greek “cata”, “downwards”; compare “catastrophe”), a generalization of folds over regular trees (and datatypes isomorphic to them). It operates at the leaves first, and then branches near the periphery, recursively collapsing values by whatever is computed by `transform`. Catamorphisms are themselves an example of _recursion schemes_, which characterize specific well-behaved patterns of recursion. This gives `cata` some useful properties for computations performed over trees. /// - /// Due to the character of recursion captured by catamorphisms, `iterate` ensures that computation will not only halt, but will further be linear in the size of the receiver. (Nesting a call to `iterate` will therefore result in O(n²) complexity.) This guarantee is achieved by careful composition of calls to `map` with recursive calls to `iterate`, only calling `transform` once the recursive call has completed. `transform` is itself non-recursive, receiving a `Syntax` whose recurrences have already been flattened to `Value`. + /// Due to the character of recursion captured by catamorphisms, `cata` ensures that computation will not only halt, but will further be linear in the size of the receiver. (Nesting a call to `cata` will therefore result in O(n²) complexity.) This guarantee is achieved by careful composition of calls to `map` with recursive calls to `cata`, only calling `transform` once the recursive call has completed. `transform` is itself non-recursive, receiving a `Syntax` whose recurrences have already been flattened to `Value`. /// - /// The linearity of `iterate` in the size of the receiver makes it trivial to compute said size, by counting leaves as 1 and summing branches’ children: + /// The linearity of `cata` in the size of the receiver makes it trivial to compute said size, by counting leaves as 1 and summing branches’ children: /// /// func size(free: Free) -> Int { - /// return free.iterate { flattenedSyntax in + /// return free.cata { flattenedSyntax in /// switch flattenedSyntax { /// case .Leaf: /// return 1 @@ -45,19 +45,19 @@ public enum Free: CustomDebugStringConvertible { /// } /// } /// - /// While not every function on a given `Free` can be computed using `iterate`, these guarantees of termination and complexity, as well as the brevity and focus on the operation being performed n times, make it a desirable scaffolding for any function which can. + /// While not every function on a given `Free` can be computed using `cata`, these guarantees of termination and complexity, as well as the brevity and focus on the operation being performed n times, make it a desirable scaffolding for any function which can. /// /// For a lucid, in-depth tutorial on recursion schemes, I recommend [Patrick Thomson](https://twitter.com/importantshock)’s _[An Introduction to Recursion Schemes](http://patrickthomson.ghost.io/an-introduction-to-recursion-schemes/)_ and _[Recursion Schemes, Part 2: A Mob of Morphisms](http://patrickthomson.ghost.io/recursion-schemes-part-2/)_. - public func iterate(transform: Syntax -> Value) -> Value { + public func cata(transform: Syntax -> Value) -> Value { return analysis( ifPure: id, - ifRoll: { $1.map { $0.iterate(transform) } } >>> transform) + ifRoll: { $1.map { $0.cata(transform) } } >>> transform) } /// Reduces the receiver top-down, left-to-right, starting from an `initial` value, and applying `combine` to successive values. public func reduce(initial: Value, combine: (Value, Value) -> Value) -> Value { - return iterate { + return cata { switch $0 { case .Leaf: return initial @@ -122,11 +122,11 @@ extension Free where Value: PatchType, Value.Element == Cofree { public typealias Term = Value.Element public func merge(transform: Value -> Term) -> Term { - return map(transform).iterate { Cofree((), $0) } + return map(transform).cata { Cofree((), $0) } } public func merge(transform: Value -> Term?) -> Term? { - return map(transform).iterate(Free.discardNullTerms) + return map(transform).cata(Free.discardNullTerms) } private static func discardNullTerms(syntax: Syntax) -> Term? { diff --git a/prototype/Doubt/Syntax.swift b/prototype/Doubt/Syntax.swift index 2ef0ff97b..0f97e0d2b 100644 --- a/prototype/Doubt/Syntax.swift +++ b/prototype/Doubt/Syntax.swift @@ -38,7 +38,7 @@ public enum Syntax: CustomDebugStringConvertible { /// Hylomorphism through `Syntax`. /// -/// A hylomorphism (from the Aristotelian philosophy that form and matter are one) is a function of type `A → B` whose call-tree is linear in the size of the nodes produced by `up`. Conceptually, it’s the composition of a catamorphism (see also `TermType.cata`, `Free.iterate`) and an anamorphism (see also `ana`), but is implemented by [Stream fusion](http://lambda-the-ultimate.org/node/2192) and as such enjoys O(n) time complexity, O(1) size complexity, and small constant factors for both (modulo inadvisable implementations of `up` and `down`). +/// A hylomorphism (from the Aristotelian philosophy that form and matter are one) is a function of type `A → B` whose call-tree is linear in the size of the nodes produced by `up`. Conceptually, it’s the composition of a catamorphism (see also `cata`) and an anamorphism (see also `ana`), but is implemented by [Stream fusion](http://lambda-the-ultimate.org/node/2192) and as such enjoys O(n) time complexity, O(1) size complexity, and small constant factors for both (modulo inadvisable implementations of `up` and `down`). /// /// Hylomorphisms are used to construct diffs corresponding to equal terms; see also `CofreeType.zip`. /// @@ -49,7 +49,7 @@ public func hylo(down: Syntax -> B, _ up: A -> Syntax