/// The fixpoint of `Syntax`. /// /// `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` is represented by a `Fix` which in turn contains a `Syntax`. 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` rather than provided by a type parameter `F` applied to `Fix`. public enum Fix: CustomDebugStringConvertible, CustomDocConvertible, SyntaxConvertible { /// A recursive instantiation of `Syntax`, unrolling another iteration of the recursive type. indirect case In(Syntax) public var out: Syntax { switch self { case let .In(s): return s } } // MARK: CustomDebugStringConvertible public var debugDescription: String { return ".In(\(String(reflecting: out)))" } // MARK: CustomDocConvertible public var doc: Doc { return out.doc } // MARK: SyntaxConvertible public init(syntax: Syntax) { self = .In(syntax) } } // MARK: - Equality extension Fix { public static func equals(param: (A, A) -> Bool)(_ left: Fix, _ right: Fix) -> Bool { return Syntax.equals(ifLeaf: param, ifRecur: equals(param))(left.out, right.out) } } public func == (left: Fix, right: Fix) -> Bool { return Fix.equals(==)(left, right) } // MARK: - Hashing extension Fix { public func hash(param: A -> Hash) -> Hash { return out.hash(ifLeaf: param, ifRecur: { $0.hash(param) }) } } extension Fix where A: Hashable { public var hash: Hash { return hash(Hash.init) } } // MARK: - JSON extension Fix { public func JSON(ifLeaf: A -> Doubt.JSON) -> Doubt.JSON { return out.JSON(ifLeaf: ifLeaf, ifRecur: { $0.JSON(ifLeaf) }) } } extension Fix where A: CustomJSONConvertible { public var JSON: Doubt.JSON { return JSON { $0.JSON } } }