metaclass: (Default)
[personal profile] metaclass
Читаю про тайпклассы и имплиситы в скале:
http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html

Не совсем понимаю один момент. В статье мы вызываем функцию (printLabel) для объекта, конкретная реализация которой ищется компилятором в виде имплисита в скале или в реализации тайпкласса в хаскеле. Но это все, условно говоря "раннее связывание", на этапе компиляции.

А вот если мы ходим сделать универсальную функцию вроде "на входе список объектов, на выходе - список строковых представлений", причем, во-первых, объекты сами по себе ни от чего типа "Object с методом printLabel" не наследуются и интерфейсов соответствующих не реализуют (ну, скажем объект - это Anemic Data Model, тупая запись с полями и прочее POCO/POJO вообще), а printLabel реализована вот как в статье - в отдельном связанном объекте-адаптере - то как, во-первых, мы запишем тип такой функции, а во вторых - как мы ее реализуем?

В хаскеле можно было намутить чего-то с соответствующим тайпклассом и экзистенциальными типами ("список любых объектов, у которых есть тайпкласс LabelMaker"). А с трейтами и прочей скалой чего можно сделать?

На мирных языках типа жабе, C# или дельфей - придется вообще делать диспетчеризацию по типу и глобальный словарь вида "тип->функция", регистрировать в нем функции печати(в F# pretty printer вроде так и реализован), но это никаких статических гарантий правильности вообще не даст. Впрочем, в стиле "хуяк-хуяк и в продакшен" это не проблема - для всех типов, где мы не нашли функцию - выводим надпись "ИмяТипа_ОбратитесьВОбслуживающуюОрганизациюЕслиВыВидитеЭтоИЗаплатите100500ДенегЗаОбслуживание" и все, ничего не упадет, кому надо - обратятся.

Date: 2013-10-11 07:18 am (UTC)
From: [identity profile] bydl0coder.livejournal.com
Да хз, я в типах не секу. Мне больше подход "хуяк-хуяк" нравится.

Date: 2013-10-11 07:33 am (UTC)
From: [identity profile] xeno-by.livejournal.com
Если что, здесь преимущества нет. Все может быть реализовано на тайпклассах:
trait Printable[T] {
  def print(x: T): String
}

class Person(val name: String)
object Person {
  // если использовать правильные макросы, то это определение вообще не нужно
  implicit val personIsPrintable = new Printable[Person] {
    def print(p: Person) = p.name
  }
}

object Test extends App {
  def printList[T: Printable](xs: List[T]) = xs.map(implicitly[Printable[T]].print(_))
  val books = List(new Person("Iceberg Slim"))
  printList(books)
}
Здесь есть два момента, которые я бы хотел прокомментировать:
1) Компаньон соответствующего типа включается в имплисит скоуп этого типа, поэтому имплиситы, объявленные в компаньоне, автоматически находятся компилятором без импортов (implicits without import tax).
2) В последнее время (пару лет как минимум) в коммьюнити выработалось довольно стремное отношение к implicit conversions / implicit classes. Доводы обычные - если злоупотреблять манкипатчингом, то потом тяжело разобраться какие методы откуда приходят. Поэтому народ обычно предпочитает альтернативные решения.

Profile

metaclass: (Default)
metaclass

April 2017

S M T W T F S
      1
2345678
9101112 131415
16171819202122
23242526272829
30      

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Sep. 28th, 2025 03:08 pm
Powered by Dreamwidth Studios