![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Читаю про тайпклассы и имплиситы в скале:
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ДенегЗаОбслуживание" и все, ничего не упадет, кому надо - обратятся.
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ДенегЗаОбслуживание" и все, ничего не упадет, кому надо - обратятся.
no subject
Date: 2013-10-11 07:11 am (UTC)В скале придется делать аналогично и implicits помещать в структуре данных вместе со значением, которое им будет обрабатываться. Получается не столь элегантно, но и проблема, в общем то, надуманная.
no subject
Date: 2013-10-11 07:49 am (UTC){-# LANGUAGE ExistentialQuantification #-}
module Main where
--Чтобы тип элементов списка сделать разным - надо тип и vtable сначала слепить вместе:
data Showable = forall a . Show a => Showable a
-- Потом в список напихивать инстансы именно этой обертки (в этот момент мы как раз берем этот vtable и слепляем с инстансом):
myList = [Showable 1, Showable "test"]
-- А потом уже писать функции типа [Showable] -> String:
test :: [Showable] -> String
test = concatMap (\(Showable item) -> show item)
main = print $ test myList
no subject
Date: 2013-10-11 07:51 am (UTC)no subject
Date: 2013-10-11 08:10 am (UTC)Во-первых ты не таскаешь vtable повсюду. В большинстве случаев экзистенциальные типы не нужны, нужный vtable выпаливается при компиляции, и может даже это оптимизируется. В отличии от дотнетов и яв, где у тебя каждый интерфейс - это плюс один указатель к каждому объекту в любом раскладе.
Во-вторых обертка обычно не такая прям и простая. И вообще эта гибкость с тем куда и зачем пихать vtable - она весьма в тему.
no subject
Date: 2013-10-11 08:11 am (UTC)no subject
Date: 2013-10-11 08:13 am (UTC)На питончике - запросто.
no subject
Date: 2013-10-11 07:55 am (UTC)