1
1
mirror of https://github.com/github/semantic.git synced 2024-11-25 21:43:07 +03:00
semantic/prototype/Doubt/Cofree.swift

63 lines
2.0 KiB
Swift
Raw Normal View History

2015-10-14 16:34:18 +03:00
// Copyright © 2015 GitHub. All rights reserved.
2015-10-14 17:19:02 +03:00
/// The cofree comonad over `Syntax`.
///
/// This is free in the sense of unconstrained rather than zero-cost; its 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.
2015-10-14 16:43:51 +03:00
public enum Cofree<A, B> {
2015-10-14 16:56:46 +03:00
indirect case Unroll(B, Syntax<Cofree, A>)
2015-10-14 16:59:04 +03:00
public var unwrap: Syntax<Cofree, A> {
switch self {
case let .Unroll(_, rest):
return rest
}
}
2015-10-14 17:39:01 +03:00
/// Recursively copies a `Fix<A>` into a `Cofree<A, B>` with a function assigning `B` for every `Fix<A>`.
public init(_ fix: Fix<A>, _ annotate: Fix<A> -> B) {
self = Cofree<A, Fix<A>>.coiterate { $0.out } (fix).map(annotate)
}
2015-10-14 17:39:01 +03:00
public static func coiterate(annotate: B -> Syntax<B, A>)(_ seed: B) -> Cofree {
return .Unroll(seed, annotate(seed).map(coiterate(annotate)))
}
2015-10-14 16:34:18 +03:00
}
2015-10-14 16:43:23 +03:00
2015-10-14 17:09:38 +03:00
// MARK: - Functor
extension Cofree {
public func map<Other>(@noescape transform: B -> Other) -> Cofree<A, Other> {
2015-10-14 17:09:38 +03:00
return .Unroll(transform(extract), unwrap.map { $0.map(transform) })
}
}
2015-10-14 16:43:23 +03:00
// MARK: - Comonad
extension Cofree {
2015-10-14 17:19:38 +03:00
/// Returns the value annotating the syntax tree at this node.
2015-10-14 17:01:19 +03:00
public var extract: B {
2015-10-14 16:43:23 +03:00
switch self {
2015-10-14 16:43:51 +03:00
case let .Unroll(b, _):
2015-10-14 16:43:23 +03:00
return b
}
}
2015-10-14 17:00:16 +03:00
2015-10-14 17:22:04 +03:00
/// Returns a new `Cofree` by recursively applying `transform` to each node, producing the annotations for the copy.
public func extend<Other>(@noescape transform: Cofree -> Other) -> Cofree<A, Other> {
2015-10-14 17:00:16 +03:00
return .Unroll(transform(self), unwrap.map { $0.extend(transform) })
}
2015-10-14 17:03:42 +03:00
2015-10-14 17:23:43 +03:00
/// Returns a new `Cofree` constructed by recursively annotating each subtree with itself.
2015-10-14 17:03:42 +03:00
public var duplicate: Cofree<A, Cofree<A, B>> {
2015-10-14 17:24:16 +03:00
return extend(id)
2015-10-14 17:03:42 +03:00
}
2015-10-14 16:43:23 +03:00
}
2015-10-14 17:24:16 +03:00
import Prelude