Last active
January 10, 2021 23:36
-
-
Save drawers/7a193b4a36d43815280cd23336ef9337 to your computer and use it in GitHub Desktop.
Higher kinds tl;dr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// I want to parameterize a container F as well as the contents A | |
Mappable<F<A>> | |
// but type parameters can't have type parameters in Kotlin :-( | |
// Instead of a type parameter of a type parameter, | |
// what if I just use two type parameters? | |
Mappable<Kind<F,A>> | |
// now I need to apply this to Option and String | |
Mappable<Kind</*put Option here somehow*/, String>> | |
// But Option needs a type parameter. | |
// I can't do: | |
Mappable<Kind<Option<*>>, String> | |
// since type params can't have type params :-( | |
// I'll define a witness with no type params called "ForOption" | |
class ForOption private constructor() { companion object } | |
// I can use type aliases to make OptionOf<A> mean Kind<ForOption, A> | |
typealias OptionOf<A> = arrow.Kind<ForOption, A> | |
// and I need a way to get from Kind<ForOption, A> to Option<A>: | |
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE") | |
inline fun <A> OptionOf<A>.fix(): Option<A> = | |
this as Option<A> | |
// Now I can write: | |
Mappable<Kind<ForOption, String>> | |
// The witness is tedious to write by hand so I will use code-generation to make it ;-) | |
// @higherkind tells the annotation processor to emit the witness for my concrete container `Option<out A>` | |
@higherkind | |
sealed class Option<out A> : OptionOf<A> | |
// I want my Mappable container to share extension functions that call Mappable's `map` via code generation | |
// @extension tells the annotation processor to generate extension functions on Mappable<ForOption> from Mappable<Kind<F,A>> | |
@extension | |
interface OptionMappable : Mappable<ForOption> { | |
override fun <A, B> OptionOf<A>.map(f: (A) -> B): Option<B> = | |
fix().map(f) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment