2015-10-02 20:54:34 +03:00
|
|
|
|
/// The fixpoint of `Syntax`.
|
2015-10-02 20:21:43 +03:00
|
|
|
|
///
|
2015-10-02 20:54:34 +03:00
|
|
|
|
/// `Syntax` is a non-recursive type parameterized by the type of its child nodes. Instantiating it to `Fix` makes it into a recursive tree by “tying the knot”—each child node of `Syntax<Fix, A>` is represented by a `Fix` which in turn contains a `Syntax<Fix, A>`. So in the same way that the `fix` function allows one to tie a non-recursive function into a recursive one, `Fix` allows one to tie a non-recursive type into a recursive one. Unfortunately, due to Swift’s lack of higher-rank types, this cannot currently be abstracted over the type which is made recursive, and thus it is hard-coded to `Syntax<Fix, A>` rather than provided by a type parameter `F` applied to `Fix<F>`.
|
2015-10-10 01:03:23 +03:00
|
|
|
|
public enum Fix<A>: CustomDebugStringConvertible, CustomDocConvertible, SyntaxConvertible {
|
2015-10-02 21:08:03 +03:00
|
|
|
|
/// A recursive instantiation of `Syntax`, unrolling another iteration of the recursive type.
|
2015-10-02 20:21:43 +03:00
|
|
|
|
indirect case In(Syntax<Fix, A>)
|
|
|
|
|
|
2015-10-02 20:42:55 +03:00
|
|
|
|
public var out: Syntax<Fix, A> {
|
2015-10-02 20:21:43 +03:00
|
|
|
|
switch self {
|
|
|
|
|
case let .In(s):
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-06 23:44:00 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MARK: CustomDebugStringConvertible
|
|
|
|
|
|
|
|
|
|
public var debugDescription: String {
|
|
|
|
|
return ".In(\(String(reflecting: out)))"
|
|
|
|
|
}
|
2015-10-07 16:48:07 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MARK: CustomDocConvertible
|
|
|
|
|
|
|
|
|
|
public var doc: Doc {
|
|
|
|
|
return out.doc
|
|
|
|
|
}
|
2015-10-10 01:03:23 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MARK: SyntaxConvertible
|
|
|
|
|
|
|
|
|
|
public init(syntax: Syntax<Fix, A>) {
|
|
|
|
|
self = .In(syntax)
|
|
|
|
|
}
|
2015-10-02 20:21:43 +03:00
|
|
|
|
}
|
2015-10-02 21:17:25 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MARK: - Equality
|
|
|
|
|
|
|
|
|
|
extension Fix {
|
|
|
|
|
public static func equals(param: (A, A) -> Bool)(_ left: Fix, _ right: Fix) -> Bool {
|
2015-10-02 23:28:57 +03:00
|
|
|
|
return Syntax.equals(ifLeaf: param, ifRecur: equals(param))(left.out, right.out)
|
2015-10-02 21:17:25 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-02 21:17:59 +03:00
|
|
|
|
|
|
|
|
|
public func == <A: Equatable> (left: Fix<A>, right: Fix<A>) -> Bool {
|
|
|
|
|
return Fix.equals(==)(left, right)
|
|
|
|
|
}
|
2015-10-02 23:31:10 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MARK: - Hashing
|
|
|
|
|
|
|
|
|
|
extension Fix {
|
|
|
|
|
public func hash(param: A -> Hash) -> Hash {
|
|
|
|
|
return out.hash(ifLeaf: param, ifRecur: { $0.hash(param) })
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-02 23:31:49 +03:00
|
|
|
|
|
|
|
|
|
extension Fix where A: Hashable {
|
2015-10-06 19:59:13 +03:00
|
|
|
|
public var hash: Hash {
|
2015-10-02 23:31:49 +03:00
|
|
|
|
return hash(Hash.init)
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-08 14:23:56 +03:00
|
|
|
|
|
|
|
|
|
|
2015-10-09 15:39:44 +03:00
|
|
|
|
// MARK: - JSON
|
2015-10-08 14:23:56 +03:00
|
|
|
|
|
|
|
|
|
extension Fix {
|
|
|
|
|
public func JSON(ifLeaf: A -> Doubt.JSON) -> Doubt.JSON {
|
2015-10-09 22:29:30 +03:00
|
|
|
|
return out.JSON(ifLeaf: ifLeaf, ifRecur: { $0.JSON(ifLeaf) })
|
2015-10-08 14:23:56 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-09 17:07:00 +03:00
|
|
|
|
|
|
|
|
|
extension Fix where A: CustomJSONConvertible {
|
|
|
|
|
public var JSON: Doubt.JSON {
|
|
|
|
|
return JSON { $0.JSON }
|
|
|
|
|
}
|
|
|
|
|
}
|