raulraja
09/13/2020, 6:13 PM@given
; in contrast to scala, given implicits in Kotlin follow coherence rules like sub-typing. This means that only authors of the type class or data type are allowed to provide the instance that proofs the conformance to the protocol and that resolution is not scoped but global.
Beside this rule meta allows users to override any type locally if the instance is internal
this allows you to change behaviours ad-hoc locally but won’t allow you to export a canonical one for others to consume and therefore it preserves coherence in the same way sub-typing does.
A given style type class may look like this:
interface Eq<A> {
fun A.eq(other: A): Boolean
}
object StringEq : Eq<String> {
override fun String.eq(other: String): Boolean =
this == other
}
fun <A> Eq<A>.areEq(a: A, b: A): Boolean =
a.eq(b)
fun main() {
println(StringEq.run { areEq("", "") })
}
In meta we are taking this further by using the Curry howard correspondonce to simply stablish the relationship between types and you can do this like this if you want to use @Given
@Given
object StringEq : Eq<String> {
override fun String.eq(other: String): Boolean =
this == other
}
fun <A> areEq(a: A, b: A, eq: EQ<A> = given()): Boolean =
eq.run { a.eq(b) }
fun main() {
println(areEq("", "")) //
}
you can require any typed value for which a provider instance is declared by using given()
in any expression position not just constructors or fields.
Alternatively you can just project the syntax directly by establishing a coercion or extension proof between the types you care:
fun interface Eq<A> {
fun A.eq(other: A): Boolean
}
/**
* Proof projects all members of Eq<String> over values of String,
* enables [eq] syntax and tell the type checker String is a subtype of Eq<String> for
* all implicit expression replacement purposes
*/
@Coercion
fun String.eqProof(): Eq<String> =
Eq { this == it }
fun main() {
println("".eq("")) // proof removes "".eqProof().eq("")
}