1
1
mirror of https://github.com/github/semantic.git synced 2024-12-01 17:59:10 +03:00

Cofree uses Memo to ensure that statefully-computed subtrees are “ok.”

Randomness is an effect.
This commit is contained in:
Rob Rix 2015-10-16 16:05:37 -04:00
parent e6ec91cd64
commit f4e462eba2

View File

@ -4,18 +4,18 @@
/// ///
/// 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. /// 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<A, B> { public enum Cofree<A, B> {
case Unroll(B, () -> Syntax<Cofree, A>) case Unroll(B, Memo<Syntax<Cofree, A>>)
public var unwrap: Syntax<Cofree, A> { public var unwrap: Syntax<Cofree, A> {
switch self { switch self {
case let .Unroll(_, rest): case let .Unroll(_, rest):
return rest() return rest.value
} }
} }
public init(_ annotation: B, @autoclosure(escaping) _ syntax: () -> Syntax<Cofree, A>) { public init(_ annotation: B, @autoclosure(escaping) _ syntax: () -> Syntax<Cofree, A>) {
self = .Unroll(annotation, syntax) self = .Unroll(annotation, Memo(unevaluated: syntax))
} }
@ -25,7 +25,7 @@ public enum Cofree<A, B> {
/// ///
/// As this is the dual of `Free.iterate`, its unsurprising that we have a similar guarantee: coiteration is linear in the size of the constructed tree. /// As this is the dual of `Free.iterate`, its unsurprising that we have a similar guarantee: coiteration is linear in the size of the constructed tree.
public static func coiterate(annotate: B -> Syntax<B, A>)(_ seed: B) -> Cofree { public static func coiterate(annotate: B -> Syntax<B, A>)(_ seed: B) -> Cofree {
return .Unroll(seed, { annotate(seed).map(coiterate(annotate)) }) return .Unroll(seed, Memo { annotate(seed).map(coiterate(annotate)) })
} }
} }
@ -43,7 +43,7 @@ extension Cofree: CustomDebugStringConvertible {
extension Cofree { extension Cofree {
public func map<Other>(transform: B -> Other) -> Cofree<A, Other> { public func map<Other>(transform: B -> Other) -> Cofree<A, Other> {
return .Unroll(transform(extract), { self.unwrap.map { $0.map(transform) } }) return .Unroll(transform(extract), Memo { self.unwrap.map { $0.map(transform) } })
} }
} }
@ -61,7 +61,7 @@ extension Cofree {
/// Returns a new `Cofree` by recursively applying `transform` to each node, producing the annotations for the copy. /// Returns a new `Cofree` by recursively applying `transform` to each node, producing the annotations for the copy.
public func extend<Other>(transform: Cofree -> Other) -> Cofree<A, Other> { public func extend<Other>(transform: Cofree -> Other) -> Cofree<A, Other> {
return .Unroll(transform(self), { self.unwrap.map { $0.extend(transform) } }) return .Unroll(transform(self), Memo { self.unwrap.map { $0.extend(transform) } })
} }
/// Returns a new `Cofree` constructed by recursively annotating each subtree with itself. /// Returns a new `Cofree` constructed by recursively annotating each subtree with itself.
@ -112,4 +112,5 @@ extension Cofree where B: Categorizable {
} }
import Memo
import Prelude import Prelude