1
1
mirror of https://github.com/github/semantic.git synced 2024-12-29 18:06:14 +03:00
semantic/prototype/Doubt/Fix.swift
2015-10-09 18:03:23 -04:00

79 lines
2.1 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/// 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 knoteach 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 Swifts 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>`.
public enum Fix<A>: CustomDebugStringConvertible, CustomDocConvertible, SyntaxConvertible {
/// A recursive instantiation of `Syntax`, unrolling another iteration of the recursive type.
indirect case In(Syntax<Fix, A>)
public var out: Syntax<Fix, A> {
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<Fix, A>) {
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 == <A: Equatable> (left: Fix<A>, right: Fix<A>) -> 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 }
}
}