Created
November 21, 2014 09:59
-
-
Save anonymous/40a9adf0afcd1ca4d357 to your computer and use it in GitHub Desktop.
Typeclass example
This file contains hidden or 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() | |
} | |
// Пример использования Animal и Cat уже с реализацией HappyCatAnimal (код идентичен с точностью до импортов) | |
object Main2 extends App { | |
import animal._ | |
import happyCat._ | |
val cat = new Cat("Kittie") | |
cat.talk() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment