2015-11-04 20:43:50 +03:00
|
|
|
|
/// A `Location` is a structure similar to a `Lens` which allows introspection of & update to subtrees of some tree.
|
|
|
|
|
///
|
|
|
|
|
/// In the former case, a `Location` is essentially an implementation of a [Zipper][], allowing exploration into and out of nodes, as well as to adjacent nodes.
|
|
|
|
|
///
|
2015-11-04 20:50:34 +03:00
|
|
|
|
/// [Hinze & Jeuring][] then extended this to support replacing the focused node. `Location` implements their approach (see §5, “A Read-write Web”).
|
2015-11-04 20:43:50 +03:00
|
|
|
|
///
|
|
|
|
|
/// This is also closely related to [McBride][]’s observations about the derivative of regular types.
|
|
|
|
|
///
|
|
|
|
|
/// [Zipper]: https://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/huet-zipper.pdf
|
|
|
|
|
/// [Hinze & Jeuring]: https://github.com/github/semantic-diff/files/27297/Weaving.a.Web.pdf
|
|
|
|
|
/// [McBride]: http://strictlypositive.org/diff.pdf
|
2015-11-04 20:11:18 +03:00
|
|
|
|
public struct Location<A>: SequenceType {
|
2015-11-04 20:43:46 +03:00
|
|
|
|
/// Construct a `Location` representing some position within a tree.
|
2015-11-05 20:07:59 +03:00
|
|
|
|
public init(it: A, into: A -> Location?, outOf: A -> Location?, left: A -> Location?, right: A -> Location?) {
|
2015-11-04 20:11:18 +03:00
|
|
|
|
self.it = it
|
|
|
|
|
_left = left
|
|
|
|
|
_right = right
|
2015-11-05 20:07:59 +03:00
|
|
|
|
_outOf = outOf
|
2015-11-05 20:06:04 +03:00
|
|
|
|
_into = into
|
2015-11-04 20:11:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-04 20:43:46 +03:00
|
|
|
|
/// The node currently in focus.
|
2015-11-04 20:11:18 +03:00
|
|
|
|
public let it: A
|
|
|
|
|
|
2015-11-05 20:08:46 +03:00
|
|
|
|
/// Returns the `Location` representing the contents of `it`, or `nil` if `it` is a leaf.
|
2015-11-05 20:05:43 +03:00
|
|
|
|
public var into: Location? { return _into(it) }
|
2015-11-04 20:11:18 +03:00
|
|
|
|
|
2015-11-05 20:09:28 +03:00
|
|
|
|
/// Returns the `Location` representing the parent of `it` in the current exploration, or `nil` if the receiver is the `root`.
|
2015-11-05 20:06:54 +03:00
|
|
|
|
public var outOf: Location? { return _outOf(it) }
|
2015-11-04 20:11:18 +03:00
|
|
|
|
|
2015-11-05 20:10:17 +03:00
|
|
|
|
/// Returns the `Location` which immediately precedes the receiver within its parent in the current exploration, or `nil` if the receiver is the `root` or the first child of its parent.
|
2015-11-05 00:15:26 +03:00
|
|
|
|
public var left: Location? { return _left(it) }
|
2015-11-04 20:11:18 +03:00
|
|
|
|
|
2015-11-05 20:10:42 +03:00
|
|
|
|
/// Returns the `Location` which immediately follows the receiver within its parent in the current exploration, or `nil` if the receiver is the `root` or the last child of its parent.
|
2015-11-05 00:15:26 +03:00
|
|
|
|
public var right: Location? { return _right(it) }
|
2015-11-04 20:11:18 +03:00
|
|
|
|
|
2015-11-04 20:43:37 +03:00
|
|
|
|
/// The root `Location` in the current exploration.
|
2015-11-04 20:11:18 +03:00
|
|
|
|
public var root: Location {
|
2015-11-05 20:06:39 +03:00
|
|
|
|
return outOf?.root ?? self
|
2015-11-04 20:11:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the logically next `Location` after the receiver in a pre-order depth-first traversal.
|
|
|
|
|
public var next: Location? {
|
2015-11-05 20:05:28 +03:00
|
|
|
|
return into ?? nextAfter
|
2015-11-04 20:11:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the logically next `Location` after the receiver and its children in a pre-order depth-first traversal.
|
|
|
|
|
private var nextAfter: Location? {
|
2015-11-05 20:06:39 +03:00
|
|
|
|
return right ?? outOf?.nextAfter
|
2015-11-04 20:11:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-11-04 20:43:37 +03:00
|
|
|
|
/// Return a new `Location` by replacing the current value with a new one produced by `f`.
|
2015-11-04 20:11:18 +03:00
|
|
|
|
public func modify(@noescape f: A -> A) -> Location {
|
2015-11-05 20:07:59 +03:00
|
|
|
|
return Location(it: f(it), into: _into, outOf: _outOf, left: _left, right: _right)
|
2015-11-04 20:11:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public typealias Weave = A -> Unweave
|
|
|
|
|
public typealias Unweave = (A -> Location?) -> Location?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MARK: - Constructors
|
|
|
|
|
|
2015-11-05 20:07:59 +03:00
|
|
|
|
public static func nullary(outOf: A -> Location?) -> Location? {
|
2015-11-04 20:11:18 +03:00
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-05 20:07:59 +03:00
|
|
|
|
public static func unary(t1: A, _ weave: Weave, _ reconstruct: A -> A)(_ outOf: A -> Location?) -> Location? {
|
|
|
|
|
return Location(flip(weave), { $0[0] } >>> reconstruct >>> outOf, [t1])
|
2015-11-04 20:11:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-05 20:07:59 +03:00
|
|
|
|
public static func binary(t1: A, _ t2: A, _ weave: Weave, _ reconstruct: (A, A) -> A)(_ outOf: A -> Location?) -> Location? {
|
|
|
|
|
return Location(flip(weave), { ($0[0], $0[1]) } >>> reconstruct >>> outOf, [t1, t2])
|
2015-11-04 20:11:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-05 20:07:59 +03:00
|
|
|
|
public static func ternary(t1: A, _ t2: A, _ t3: A, _ weave: Weave, _ reconstruct: (A, A, A) -> A)(_ outOf: A -> Location?) -> Location? {
|
|
|
|
|
return Location(flip(weave), { ($0[0], $0[1], $0[2]) } >>> reconstruct >>> outOf, [t1, t2, t3])
|
2015-11-04 20:11:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-05 20:07:59 +03:00
|
|
|
|
public static func variadic<C: MutableCollectionType where C.Generator.Element == A, C.Index: BidirectionalIndexType>(ts: C, _ weave: Weave, _ reconstruct: C -> A)(_ outOf: A -> Location?) -> Location? {
|
|
|
|
|
return Location(flip(weave), reconstruct >>> outOf, ts)
|
2015-11-05 00:34:20 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-05 20:07:59 +03:00
|
|
|
|
public static func variadic<Key>(ts: [Key:A], _ weave: Weave, _ reconstruct: [Key:A] -> A)(_ outOf: A -> Location?) -> Location? {
|
|
|
|
|
return Location(flip(weave), Dictionary.init >>> reconstruct >>> outOf, Array(ts))
|
2015-11-05 18:33:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-04 20:11:18 +03:00
|
|
|
|
public static func explore(weave: Weave)(_ a : A) -> Location {
|
2015-11-05 20:07:59 +03:00
|
|
|
|
return Location(it: a, into: flip(weave)(explore(weave) >>> Optional.Some), outOf: const(nil), left: const(nil), right: const(nil))
|
2015-11-04 20:11:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MARK: - Implementation details
|
|
|
|
|
|
2015-11-05 20:07:59 +03:00
|
|
|
|
private init?<C: MutableCollectionType where C.Generator.Element == A, C.Index: BidirectionalIndexType>(_ weave: (A -> Location?) -> A -> Location?, _ outOf: C -> Location?, _ ts: C) {
|
2015-11-05 19:45:46 +03:00
|
|
|
|
func update(index: C.Index, _ ts: C)(_ f: C -> Location?)(_ a: A) -> Location? {
|
2015-11-05 00:47:39 +03:00
|
|
|
|
guard ts.indices.contains(index) else { return nil }
|
2015-11-05 00:34:03 +03:00
|
|
|
|
var copy = ts
|
|
|
|
|
copy[index] = a
|
2015-11-05 19:29:29 +03:00
|
|
|
|
return f(copy)
|
2015-11-05 00:34:03 +03:00
|
|
|
|
}
|
2015-11-05 00:47:39 +03:00
|
|
|
|
func into(index: C.Index)(_ ts: C) -> Location? {
|
|
|
|
|
guard ts.indices.contains(index) else { return nil }
|
2015-11-05 20:07:59 +03:00
|
|
|
|
return Location(it: ts[index], into: weave(update(index, ts)(into(index))), outOf: update(index, ts)(outOf), left: update(index, ts)(into(index.predecessor())), right: update(index, ts)(into(index.successor())))
|
2015-11-05 00:34:03 +03:00
|
|
|
|
}
|
2015-11-05 00:47:39 +03:00
|
|
|
|
guard let location = into(ts.startIndex)(ts) else { return nil }
|
2015-11-05 00:34:03 +03:00
|
|
|
|
self = location
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-05 20:07:59 +03:00
|
|
|
|
private init?<C: MutableCollectionType, Key where C.Generator.Element == (Key, A), C.Index: BidirectionalIndexType>(_ weave: (A -> Location?) -> A -> Location?, _ outOf: C -> Location?, _ ts: C) {
|
2015-11-05 19:45:53 +03:00
|
|
|
|
func update(index: C.Index, _ ts: C)(_ f: C -> Location?)(_ key: Key)(_ a: A) -> Location? {
|
2015-11-05 18:33:43 +03:00
|
|
|
|
guard ts.indices.contains(index) else { return nil }
|
|
|
|
|
var copy = ts
|
|
|
|
|
copy[index] = (key, a)
|
2015-11-05 19:31:21 +03:00
|
|
|
|
return f(copy)
|
2015-11-05 18:33:43 +03:00
|
|
|
|
}
|
|
|
|
|
func into(index: C.Index)(_ ts: C) -> Location? {
|
|
|
|
|
guard ts.indices.contains(index) else { return nil }
|
|
|
|
|
let (key, value) = ts[index]
|
2015-11-05 20:07:59 +03:00
|
|
|
|
return Location(it: value, into: weave(update(index, ts)(into(index))(key)), outOf: update(index, ts)(outOf)(key), left: update(index, ts)(into(index.predecessor()))(key), right: update(index, ts)(into(index.successor()))(key))
|
2015-11-05 18:33:43 +03:00
|
|
|
|
}
|
|
|
|
|
guard let location = into(ts.startIndex)(ts) else { return nil }
|
|
|
|
|
self = location
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-04 20:11:18 +03:00
|
|
|
|
|
2015-11-05 20:05:43 +03:00
|
|
|
|
private let _into: A -> Location?
|
2015-11-05 20:06:54 +03:00
|
|
|
|
private let _outOf: A -> Location?
|
2015-11-05 00:14:43 +03:00
|
|
|
|
private let _left: A -> Location?
|
|
|
|
|
private let _right: A -> Location?
|
|
|
|
|
|
|
|
|
|
|
2015-11-04 20:11:18 +03:00
|
|
|
|
// MARK: SequenceType
|
|
|
|
|
|
|
|
|
|
public func generate() -> AnyGenerator<Location> {
|
|
|
|
|
var current: Location? = self
|
|
|
|
|
return anyGenerator {
|
|
|
|
|
let next = current
|
|
|
|
|
current = current?.next
|
|
|
|
|
return next
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Flipping of curried functions.
|
|
|
|
|
private func flip<A, B, C>(f: A -> B -> C)(_ b: B)(_ a: A) -> C {
|
|
|
|
|
return f(a)(b)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import Prelude
|