-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Abhijit Sarkar
committed
Dec 21, 2024
1 parent
bc4c7f9
commit 72a9350
Showing
4 changed files
with
120 additions
and
1 deletion.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package ch04 | ||
|
||
final case class Cat(name: String, age: Int, color: String) | ||
|
||
object Cat: | ||
given catDisplay: Display[Cat]: | ||
def display(cat: Cat): String = | ||
val name = Display.display(cat.name) | ||
val age = Display.display(cat.age) | ||
val color = Display.display(cat.color) | ||
s"$name is a $age year-old $color cat." |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package ch04 | ||
|
||
trait Display[A]: | ||
def display(value: A): String | ||
|
||
|
||
object Display: | ||
given stringDisplay: Display[String]: | ||
def display(input: String): String = input | ||
|
||
given intDisplay: Display[Int]: | ||
def display(input: Int): String = input.toString | ||
|
||
def display[A](input: A)(using p: Display[A]): String = | ||
p.display(input) | ||
|
||
def print[A](input: A)(using Display[A]): Unit = | ||
println(display(input)) | ||
|
||
object DisplaySyntax: | ||
extension [A](value: A)(using p: Display[A]) | ||
def display: String = p.display(value) | ||
def print: Unit = Display.print(value) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import ch04.DisplaySyntax.* | ||
import ch04.Display | ||
|
||
/* | ||
components that make up a type class: | ||
- A trait, which is the type class | ||
- Type class instances, which are given instances. | ||
- Type class usage, which uses using clauses. | ||
Type classes can be composed from components using type class composition. | ||
We can view type classes as marrying codata with tools to select and compose implementations based on type. | ||
We can also view type classes as shifting implementation from the definition site to the call site. | ||
Finally, can see type classes as a mechanism for ad-hoc polymorphism, | ||
allowing us to define common functionality for otherwise unrelated types. | ||
*/ | ||
given Display[ch04.Cat] with | ||
def display(cat: ch04.Cat): String = | ||
val name = cat.name.display | ||
val age = cat.age.display | ||
val color = cat.color.display | ||
s"$name is a $age year-old $color cat." | ||
|
||
ch04.Cat("Garfield", 41, "ginger and black").display | ||
|
||
trait Animal | ||
trait Cat extends Animal | ||
trait DomesticShorthair extends Cat | ||
|
||
trait Inv[A]: | ||
def result: String | ||
|
||
object Inv: | ||
given Inv[Cat] with | ||
def result = "Invariant" | ||
|
||
def apply[A](using instance: Inv[A]): String = | ||
instance.result | ||
|
||
trait Co[+A]: | ||
def result: String | ||
|
||
object Co: | ||
given Co[Cat] with | ||
def result = "Covariant" | ||
|
||
def apply[A](using instance: Co[A]): String = | ||
instance.result | ||
|
||
trait Contra[-A]: | ||
def result: String | ||
|
||
object Contra: | ||
given Contra[Cat] with | ||
def result = "Contravariant" | ||
|
||
def apply[A](using instance: Contra[A]): String = | ||
instance.result | ||
|
||
// Works! | ||
Inv[Cat] | ||
// res1: String = "Invariant" | ||
Co[Animal] | ||
// res2: String = "Covariant" | ||
Co[Cat] | ||
// res3: String = "Covariant" | ||
Contra[DomesticShorthair] | ||
// res4: String = "Contravariant" | ||
Contra[Cat] | ||
// res5: String = "Contravariant" | ||
|
||
// Don't work! | ||
|
||
// With invariance any type that is not Cat will fail. | ||
// Inv[Animal] | ||
// Inv[DomesticShorthair] | ||
|
||
// Covariance fails for any subtype of the type for which the instance is declared. | ||
// Co[DomesticShorthair] | ||
|
||
// Contravariance fails for any supertype of the type for which the instance is declared. | ||
// Contra[Animal] |