protocol Mappable<F<_>> {
static func map<A, B>(_ fa: F<A>, _ f: (A) -> B) -> F<B>
}
extension Array: Mappable<Array> {
static func map<A, B>(_ fa: Array<A>, _ f: (A) -> B) -> Array<B> {
fa.map(f)
}
}
extension Optional: Mappable<Optional> {
static func map<A, B>(_ fa: Optional<A>, _ f: (A) -> B) -> Optional<B> {
fa.map(f)
}
}
extension Task: Mappable<Task> where Failure == Error {
static func map<A, B>(_ fa: Task<A, Never>, _ f: @escaping (A) -> B) -> Task<B, Error> {
Task {
let a = await fa.value
return f(a)
}
}
}
extension Result: Mappable<Result> where Failure == Error {
static func map<A, B>(_ fa: Result<A, Error>, _ f: (A) -> B) -> Result<B, Error> {
fa.map(f)
}
}
extension<A> F<A> where F: Mappable<F> {
func fmap<B>(_ f: @escaping (A) -> B) -> F<B> {
F.map(self, f)
}
}
Explanation:
If you're unfamiliar with HKTs (higher kinded types), you can think of them as
generics for generics.
A generic type like `T` can be `String`, `Int`, `List<String>`, or `Option<Int>`.
A generic that itself is "also generic" would be `F<_>`, and `F` can a type
constructor like `List` or `Option`. These are types that take generics. This is
the only version that can define a generic `F` that is later filled with a
type (specifically `F<Int>` in the above example).