// Copyright © 2015 GitHub. All rights reserved. /// The cofree comonad over `Syntax`. /// /// This is “free” in the sense of “unconstrained” rather than “zero-cost”; it’s the comonad obtained by taking a functor (in this case `Syntax`) and adding the minimum necessary details (the `B` paired with it) to satisfy the comonad laws. /// /// This type is dual to `Free`. Where `Free` is inhabited by syntax trees where some terms are replaced with `B`s, `Cofree` is inhabited by syntax trees where all terms are annotated with `B`s. In Doubt, this allows us to e.g. annotate terms with source range information, categorization, etc. public enum Cofree { indirect case Unroll(B, Syntax) public var unwrap: Syntax { switch self { case let .Unroll(_, rest): return rest } } } // MARK: - Functor extension Cofree { public func map(@noescape transform: B -> Other) -> Cofree { return .Unroll(transform(extract), unwrap.map { $0.map(transform) }) } } // MARK: - Comonad extension Cofree { /// Returns the value annotating the syntax tree at this node. public var extract: B { switch self { case let .Unroll(b, _): return b } } public func extend(@noescape transform: Cofree -> Other) -> Cofree { return .Unroll(transform(self), unwrap.map { $0.extend(transform) }) } public var duplicate: Cofree> { return .Unroll(self, unwrap.map { $0.duplicate }) } }