1
|
|
import Foundation
|
2
|
|
|
3
|
|
/// An Invariant Functor provides a type the ability to transform its value type into another type. An instance of `Functor` or `Contravariant` are Invariant Functors as well.
|
4
|
|
public protocol Invariant {
|
5
|
|
/// Transforms the value type using the functions provided.
|
6
|
|
///
|
7
|
|
/// The implementation of this function must obey the following laws:
|
8
|
|
///
|
9
|
|
/// imap(fa, id, id) == fa
|
10
|
|
/// imap(imap(fa, f1, g1), f2, g2) == imap(fa, compose(f2, f1), compose(g2, g1))
|
11
|
|
///
|
12
|
|
/// - Parameters:
|
13
|
|
/// - fa: Value whose value type will be transformed.
|
14
|
|
/// - f: Transforming function.
|
15
|
|
/// - g: Transforming function.
|
16
|
|
/// - Returns: A new value in the same context as the original value, with the value type transformed.
|
17
|
|
static func imap<A, B>(_ fa : Kind<Self, A>, _ f : @escaping (A) -> B, _ g : @escaping (B) -> A) -> Kind<Self, B>
|
18
|
|
}
|
19
|
|
|
20
|
|
// MARK: Syntax for Invariant
|
21
|
|
|
22
|
|
public extension Kind where F: Invariant {
|
23
|
|
/// Transforms the value type using the functions provided.
|
24
|
|
///
|
25
|
|
/// This is a conveninece method to call `Invariant.imap` as an instance method.
|
26
|
|
///
|
27
|
|
/// - Parameters:
|
28
|
|
/// - f: Transforming function.
|
29
|
|
/// - g: Transforming function.
|
30
|
|
/// - Returns: A new value in the same context as the original value, with the value type transformed.
|
31
|
1
|
func imap<B>(_ f : @escaping (A) -> B, _ g : @escaping (B) -> A) -> Kind<F, B> {
|
32
|
1
|
return F.imap(self, f, g)
|
33
|
|
}
|
34
|
|
}
|