The CoflatMap type class, a weaker version of Comonad,
exposing coflatMap, but not extract.
This type class is exposed in addition to Comonad because
there are data types for which we can't implement extract, but
that could still benefit from an coflatMap definition.
Note that having a CoflatMap instance implies that a
Functor implementation is also available, which is why
CoflatMap is a subtype of Functor.
Implementation notes
Even though in TypeScript the Funfix library is using abstract class to
express type classes, when implementing this type class it is recommended
that you implement it as a mixin using "implements", instead of extending
it directly with "extends". See
TypeScript: Mixins
for details and note that we already have applyMixins defined.
Implementation example:
import {
HK, CoflatMap,
registerTypeClassInstance,
applyMixins
} from"funfix"// Type alias defined for readability.// HK is our encoding for higher-kinded types.type BoxK<T> = HK<Box<any>, T>
class Box<T> implements HK<Box<any>, T> {
constructor(public value: T) {}
// Implements HK<Box<any>, A>, not really needed, but useful in order// to avoid type casts. Note these can and should be undefined:
readonly _funKindF: Box<any>
readonly _funKindA: T
}
class BoxCoflatMap implements CoflatMap<Box<any>> {
map<A, B>(fa: BoxK<A>, f: (a: A) => B): Box<B> {
consta = (fa as Box<A>).valuereturnnewBox(f(a))
}
coflatMap<A, B>(fa: BoxK<A>, ff: (a: BoxK<A>) => B): BoxK<B> {
returnnewBox(Success(ff(fa)))
}
coflatten<A>(fa: BoxK<A>): BoxK<BoxK<A>> {
returnnewBox(Success(fa))
}
}
// Atthemomentofwriting, thiscallisnotneeded, butitis
// recommendedanywaytofuture-proofthecode ;-)
applyMixins(BoxCoflatMap, [CoflatMap])
// RegisteringglobalCoflatMapinstanceforBox, neededinorder
// forthe `coflatMapOf(Box)` callstoworkregisterTypeClassInstance(CoflatMap)(Box, new BoxCoflatMap())
We are using implements in order to support multiple inheritance and to
avoid inheriting any static members. In the Flow definitions (e.g.
.js.flow files) for Funfix these type classes are defined with
"interface", as they are meant to be interfaces that sometimes have
default implementations and not classes.
Credits
This type class is inspired by the equivalent in Haskell's
standard library and the implementation is inspired by the
Typelevel Cats project.
The
CoflatMaptype class, a weaker version of Comonad, exposingcoflatMap, but notextract.This type class is exposed in addition to
Comonadbecause there are data types for which we can't implementextract, but that could still benefit from ancoflatMapdefinition.MUST obey the laws defined in CoflatMapLaws.
Note that having a
CoflatMapinstance implies that a Functor implementation is also available, which is whyCoflatMapis a subtype ofFunctor.Implementation notes
Even though in TypeScript the Funfix library is using
abstract classto express type classes, when implementing this type class it is recommended that you implement it as a mixin using "implements", instead of extending it directly with "extends". See TypeScript: Mixins for details and note that we already haveapplyMixinsdefined.Implementation example:
import { HK, CoflatMap, registerTypeClassInstance, applyMixins } from "funfix" // Type alias defined for readability. // HK is our encoding for higher-kinded types. type BoxK<T> = HK<Box<any>, T> class Box<T> implements HK<Box<any>, T> { constructor(public value: T) {} // Implements HK<Box<any>, A>, not really needed, but useful in order // to avoid type casts. Note these can and should be undefined: readonly _funKindF: Box<any> readonly _funKindA: T } class BoxCoflatMap implements CoflatMap<Box<any>> { map<A, B>(fa: BoxK<A>, f: (a: A) => B): Box<B> { const a = (fa as Box<A>).value return new Box(f(a)) } coflatMap<A, B>(fa: BoxK<A>, ff: (a: BoxK<A>) => B): BoxK<B> { return new Box(Success(ff(fa))) } coflatten<A>(fa: BoxK<A>): BoxK<BoxK<A>> { return new Box(Success(fa)) } } // At the moment of writing, this call is not needed, but it is // recommended anyway to future-proof the code ;-) applyMixins(BoxCoflatMap, [CoflatMap]) // Registering global CoflatMap instance for Box, needed in order // for the `coflatMapOf(Box)` calls to work registerTypeClassInstance(CoflatMap)(Box, new BoxCoflatMap())We are using
implementsin order to support multiple inheritance and to avoid inheriting anystaticmembers. In the Flow definitions (e.g..js.flowfiles) for Funfix these type classes are defined with "interface", as they are meant to be interfaces that sometimes have default implementations and not classes.Credits
This type class is inspired by the equivalent in Haskell's standard library and the implementation is inspired by the Typelevel Cats project.