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”; 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.
|
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 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>(transform: B -> Other) -> Cofree<A, Other> {
|
|
|
|
|
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:20:05 +03:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
public var duplicate: Cofree<A, Cofree<A, B>> {
|
|
|
|
|
return .Unroll(self, unwrap.map { $0.duplicate })
|
|
|
|
|
}
|
2015-10-14 16:43:23 +03:00
|
|
|
|
}
|