mirror of
https://github.com/github/semantic.git
synced 2024-11-25 11:04:00 +03:00
Merge pull request #142 from github/unfold-diffs
Construct Free by unfolding
This commit is contained in:
commit
00242d48e4
@ -21,7 +21,7 @@ public enum Cofree<A, B> {
|
||||
|
||||
/// Constructs a cofree by coiteration.
|
||||
///
|
||||
/// 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.
|
||||
/// 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.
|
||||
public static func coiterate(annotate: B -> Syntax<B, A>)(_ seed: B) -> Cofree {
|
||||
|
@ -115,6 +115,18 @@ public enum Free<A, B>: CustomDebugStringConvertible, SyntaxConvertible {
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Anamorphism
|
||||
|
||||
extension Free {
|
||||
/// Anamorphism over `Free`.
|
||||
///
|
||||
/// Unfolds a tree bottom-up by recursively applying `transform` to a series of values starting with `seed`. Since `Syntax.Leaf` does not recur, this will halt when it has produced leaves for every branch.
|
||||
public static func ana<Seed>(transform: Seed -> Syntax<Seed, A>)(_ seed: Seed) -> Free {
|
||||
return (Roll <<< { $0.map(ana(transform)) } <<< transform)(seed)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Free where B: PatchType, B.Element == Cofree<A, ()> {
|
||||
public typealias Term = B.Element
|
||||
|
||||
|
@ -42,7 +42,7 @@ public struct Interpreter<Term: TermType> {
|
||||
|
||||
/// Diff `a` against `b`, if comparable.
|
||||
private func recur(a: Term, _ b: Term) -> Diff? {
|
||||
if equal(a, b) { return Diff(b) }
|
||||
if equal(a, b) { return Diff.ana(Term.unwrap)(b) }
|
||||
guard comparable(a, b) else { return nil }
|
||||
|
||||
let algorithm: Algorithm<Term, Diff>
|
||||
|
@ -7,18 +7,22 @@ public protocol TermType {
|
||||
|
||||
|
||||
extension TermType {
|
||||
public static func unwrap(term: Self) -> Syntax<Self, LeafType> {
|
||||
return term.unwrap
|
||||
}
|
||||
|
||||
/// Catamorphism over `TermType`s.
|
||||
///
|
||||
/// Folds the tree encoded by the receiver into a single value by recurring top-down through the tree, applying `transform` to leaves, then to branches, and so forth.
|
||||
public func cata<Result>(transform: Syntax<Result, LeafType> -> Result) -> Result {
|
||||
return self |> ({ $0.unwrap } >>> { $0.map { $0.cata(transform) } } >>> transform)
|
||||
return self |> (Self.unwrap >>> { $0.map { $0.cata(transform) } } >>> transform)
|
||||
}
|
||||
|
||||
/// Paramorphism over `TermType`s.
|
||||
///
|
||||
/// Folds the tree encoded by the receiver into a single value by recurring top-down through the tree, applying `transform` to leaves, then to branches, and so forth. Each recursive instance is made available in the `Syntax` alongside the result value at that node.
|
||||
public func para<Result>(transform: Syntax<(Self, Result), LeafType> -> Result) -> Result {
|
||||
return self |> ({ $0.unwrap } >>> { $0.map { ($0, $0.para(transform)) } } >>> transform)
|
||||
return self |> (Self.unwrap >>> { $0.map { ($0, $0.para(transform)) } } >>> transform)
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user