mirror of
https://github.com/github/semantic.git
synced 2025-01-04 13:34:31 +03:00
Allow recurrence to opt out of comparing nodes by returning nil
.
This commit is contained in:
parent
873a8e668f
commit
90b22cf9a8
@ -78,7 +78,7 @@ public enum Algorithm<A, B> {
|
||||
|
||||
|
||||
/// Evaluates the encoded algorithm, returning its result.
|
||||
public func evaluate(equals: (A, A) -> Bool, recur: (Term, Term) -> Diff) -> B {
|
||||
public func evaluate(equals: (A, A) -> Bool, recur: (Term, Term) -> Diff?) -> B {
|
||||
func replace(a: Term, _ b: Term) -> Diff {
|
||||
return .Pure(.Replace(a, b))
|
||||
}
|
||||
@ -94,10 +94,10 @@ public enum Algorithm<A, B> {
|
||||
|
||||
switch (a.out, b.out) {
|
||||
case let (.Indexed(a), .Indexed(b)) where a.count == b.count:
|
||||
return f(.Indexed(zip(a, b).map(recur))).evaluate(equals, recur: recur)
|
||||
return f(.Indexed(zip(a, b).map { recur($0, $1) ?? replace($0, $1) })).evaluate(equals, recur: recur)
|
||||
|
||||
case let (.Keyed(a), .Keyed(b)) where Array(a.keys) == Array(b.keys):
|
||||
return f(.Keyed(Dictionary(elements: b.keys.map { ($0, recur(a[$0]!, b[$0]!)) }))).evaluate(equals, recur: recur)
|
||||
return f(.Keyed(Dictionary(elements: b.keys.map { ($0, recur(a[$0]!, b[$0]!) ?? replace(a[$0]!, b[$0]!)) }))).evaluate(equals, recur: recur)
|
||||
|
||||
default:
|
||||
// This must not call `recur` with `a` and `b`, as that would infinite loop if actually recursive.
|
||||
@ -113,7 +113,7 @@ public enum Algorithm<A, B> {
|
||||
// Essentially [set reconciliation](https://en.wikipedia.org/wiki/Data_synchronization#Unordered_data) on the keys, followed by recurring into the values of the intersecting keys.
|
||||
let deleted = Set(a.keys).subtract(b.keys).map { ($0, Diff.Pure(Patch.Delete(a[$0]!))) }
|
||||
let inserted = Set(b.keys).subtract(a.keys).map { ($0, Diff.Pure(Patch.Insert(b[$0]!))) }
|
||||
let patched = Set(a.keys).intersect(b.keys).map { ($0, recur(a[$0]!, b[$0]!)) }
|
||||
let patched = Set(a.keys).intersect(b.keys).map { ($0, recur(a[$0]!, b[$0]!) ?? replace(a[$0]!, b[$0]!)) }
|
||||
return f(Dictionary(elements: deleted + inserted + patched)).evaluate(equals, recur: recur)
|
||||
|
||||
case let .Roll(.ByIndex(a, b, f)):
|
||||
@ -123,7 +123,7 @@ public enum Algorithm<A, B> {
|
||||
}
|
||||
|
||||
extension Algorithm where A: Equatable {
|
||||
public func evaluate(recur: (Term, Term) -> Diff) -> B {
|
||||
public func evaluate(recur: (Term, Term) -> Diff?) -> B {
|
||||
return evaluate(==, recur: recur)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/// Computes the SES (shortest edit script), i.e. the shortest sequence of diffs (`Free<A, Patch<A>>`) for two arrays of terms (`Fix<A>`) which would suffice to transform `a` into `b`.
|
||||
///
|
||||
/// This is computed w.r.t. an `equals` function, which computes the equality of leaf nodes within terms, and a `recur` function, which produces diffs representing matched-up terms.
|
||||
public func SES<A>(a: [Fix<A>], _ b: [Fix<A>], equals: (A, A) -> Bool, recur: (Fix<A>, Fix<A>) -> Free<A, Patch<A>>) -> [Free<A, Patch<A>>] {
|
||||
public func SES<A>(a: [Fix<A>], _ b: [Fix<A>], equals: (A, A) -> Bool, recur: (Fix<A>, Fix<A>) -> Free<A, Patch<A>>?) -> [Free<A, Patch<A>>] {
|
||||
typealias Term = Fix<A>
|
||||
typealias Diff = Free<A, Patch<A>>
|
||||
|
||||
@ -55,7 +55,7 @@ public func SES<A>(a: [Fix<A>], _ b: [Fix<A>], equals: (A, A) -> Bool, recur: (F
|
||||
if let right = right, down = down, diagonal = diagonal {
|
||||
// nominate the best edge to continue along
|
||||
let (best, diff, _) = min(
|
||||
(diagonal, recur(a[i], b[j]), costOfStream(diagonal)),
|
||||
(diagonal, recur(a[i], b[j]) ?? .Pure(.Replace(a[i], b[j])), costOfStream(diagonal)),
|
||||
(right, Diff.Pure(Patch.Delete(a[i])), costOfStream(right)),
|
||||
(down, Diff.Pure(Patch.Insert(b[j])), costOfStream(down))) { $0.2 < $1.2 }
|
||||
return cons(diff, rest: best)
|
||||
|
Loading…
Reference in New Issue
Block a user