Last active
June 9, 2020 12:46
-
-
Save orionll/0f60e891fe7ac306a002 to your computer and use it in GitHub Desktop.
Typeclass example
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
// Тайпкласс Animal (для полноты картины добавил метод hello, иначе был бы совсем тривиальный пример) | |
// Animal полностью абстрагирован от низлежашего типа A | |
trait Animal[A] { | |
def word: String | |
def talk() { println(word) } | |
def hello(a: A): String | |
} | |
// Обертка над тайпклассом Animal, чтобы можно было писать cat.hello, а не animal.hello(cat) | |
// AnimalOps полностью дублирует методы, определённые в Animal, но также может содержать еще и дополнительные методы. | |
final class AnimalOps[A](val a: A)(implicit val animal: Animal[A]) { | |
def word = animal.word | |
def talk() = animal.talk() | |
def hello = animal.hello(a) | |
} | |
object animal { | |
implicit def toAnimalOps[A](a: A)(implicit animal: Animal[A]) = new AnimalOps(a)(animal) | |
} | |
// Собственно, ADT. Добавил поле name для более наглядного примера. | |
// Заметьте, Cat - ничего не знает про Animal, а Animal ничего не знает про Cat. | |
// Эти сущности могут быть определены независимо, в разных пространствах имен или даже в разных модулях, | |
// в отличие от примера eax, где Cat зависит от Animal через наследование (в этом и отличие тайпкласса | |
// от примеси). | |
case class Cat(val name: String) | |
// Реализация тайпкласса Animal для Cat. Эта сущность может быть определена вообще в третьем модуле | |
trait CatAnimal extends Animal[Cat] { | |
def word = "Meow!" | |
def hello(cat: Cat) = s"Hello, my name is ${cat.name}!" | |
} | |
object cat { | |
implicit val instance = new CatAnimal {} | |
} | |
// Еще одна реализация тайпкласса Animal, которая расширяет CatAnimal. | |
trait HappyCatAnimal extends CatAnimal { | |
override def word = super.word + ":)" // Переопределение методов - зло. Его желательно избегать. | |
} | |
object happyCat { | |
implicit val instance = new HappyCatAnimal {} | |
} | |
// Пример использования Animal и Cat с реализацией CatAnimal | |
object Main extends App { | |
import animal._ | |
import cat._ | |
val cat = new Cat("Kittie") | |
cat.talk() // Печатает Meow! | |
} | |
// Пример использования Animal и Cat уже с реализацией HappyCatAnimal (код идентичен с точностью до импортов) | |
object Main2 extends App { | |
import animal._ | |
import happyCat._ | |
val cat = new Cat("Kittie") | |
cat.talk() // Напечатает Meow!:) | |
} |
Я на практике вообще на Scala ничего не писал кроме пары мелких программ не для production
У нас на практике все примерно так и есть. Очень много тайпклассов и иплиситов. Полет нормальный.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
А на практике в Scala получалось использовать?