1
1
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:
Josh Vera 2015-10-23 10:59:29 -04:00
commit 00242d48e4
4 changed files with 20 additions and 4 deletions

View File

@ -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 syntaxs 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 syntaxs 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`, its 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 {

View File

@ -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

View File

@ -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>

View File

@ -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)
}