Skip to content

Instantly share code, notes, and snippets.

@orionll
Last active June 9, 2020 12:46
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save orionll/0f60e891fe7ac306a002 to your computer and use it in GitHub Desktop.
Save orionll/0f60e891fe7ac306a002 to your computer and use it in GitHub Desktop.
Typeclass example
// Тайпкласс 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!:)
}
@cypok
Copy link

cypok commented Nov 21, 2014

А на практике в Scala получалось использовать?

@orionll
Copy link
Author

orionll commented Nov 21, 2014

Я на практике вообще на Scala ничего не писал кроме пары мелких программ не для production

@ezhulenev
Copy link

У нас на практике все примерно так и есть. Очень много тайпклассов и иплиситов. Полет нормальный.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment