T>>Это лечение симптомов, а не проблемы. "Костыль". L>А у меня вот не получается в одном неймспейсе определить несколько классов с одним именем. Приходится по разным разносить — это костыль?
Это толстый тролль. Тут даже отвечать ничего не надо.
Может быть, по-вашему, несколько одинаковых имён для частей типа (record syntax) в разных типах это нонсенс, вы так не пишете и разнести по разным модулям (только из-за ограничений языка) — не чуждо вашей природе. Моей чуждо. Это что-то типа могут ли люди с полностью одинаковыми ФИО сесть в одно такси. Редко встречается и когда произойдёт, они просто сядут в разные, никаких проблем. Но осадок остаётся, логики не видно.
Здравствуйте, Temoto, Вы писали:
T>Может быть, по-вашему, несколько одинаковых имён для частей типа (record syntax) в разных типах это нонсенс, вы так не пишете и разнести по разным модулям (только из-за ограничений языка) — не чуждо вашей природе. Моей чуждо. Это что-то типа могут ли люди с полностью одинаковыми ФИО сесть в одно такси. Редко встречается и когда произойдёт, они просто сядут в разные, никаких проблем. Но осадок остаётся, логики не видно.
Это не "часть типа" (record syntax — всего лишь сахар), а полноценная функция. В Haskell строгая типизация, для ad-hoc полиморфизма есть классы типов. Моя аналогия с классами подчёркивает именно этот факт. Что ты пытаешься сказать своей?
T>>Может быть, по-вашему, несколько одинаковых имён для частей типа (record syntax) в разных типах это нонсенс, вы так не пишете и разнести по разным модулям (только из-за ограничений языка) — не чуждо вашей природе. Моей чуждо. Это что-то типа могут ли люди с полностью одинаковыми ФИО сесть в одно такси. Редко встречается и когда произойдёт, они просто сядут в разные, никаких проблем. Но осадок остаётся, логики не видно.
L>Это не "часть типа" (record syntax — всего лишь сахар), а полноценная функция. В Haskell строгая типизация, для ad-hoc полиморфизма есть классы типов. Моя аналогия с классами подчёркивает именно этот факт. Что ты пытаешься сказать своей?
Именно эта "полноценность", то есть, что эта функция находится в глобальном namespace и есть проблема.
Имеется тип
data Maybe a = Just a | Nothing
. Значение Just 3, лично я, рассматриваю, как две части, несущие отдельную информацию. Just (как и Nothing) несёт информацию о том, что это значение типа Maybe. 3 это вторая часть значения, несёт отдельную информацию.
Теперь рассмотрим гипотетический тип
data FIO = FIO { first :: String, last :: String }
. Значение FIO "vasya" "pupkin" я рассматриваю, как состоящее из трёх частей. И функция first — это getter второй части ("vasya"). Если вы согласны с такими терминами, объясните, какой смысл в глобальном getter-е, который работает с одним конкретным типом. Вот если б можно было делать оверлоадинг по типам, т.е. first FIO и first BIO это разные функции, тогда проблемы нет.
Где тут не подходит аналогия с классами. В том, что классы типов вроде как глобальная вещь. Если что-то сравниваемо, то оно Eq. Если из чего-то можно взять часть с именем first, то оно может быть FIO, может быть тысячей других типов.
Возможно, вы имели в виду другое. Вы пишете свой класс JSON, я пишу свой, у нас разное видение методов, которые он должен содержать. Действительно, не получится нам жить в одном неймспейсе, увышка. Но по-моему, разница с record syntax здесь очевидна. То есть глобальность классов гораздо более логична, чем глобальность getter-ов record-ов.
Здравствуйте, Temoto, Вы писали:
T>Теперь рассмотрим гипотетический тип
data FIO = FIO { first :: String, last :: String }
. Значение FIO "vasya" "pupkin" я рассматриваю, как состоящее из трёх частей. И функция first — это getter второй части ("vasya"). Если вы согласны с такими терминами, объясните, какой смысл в глобальном getter-е, который работает с одним конкретным типом. Вот если б можно было делать оверлоадинг по типам, т.е. first FIO и first BIO это разные функции, тогда проблемы нет.
Потому что я не рассматриваю его как getter, который не существует без некоего объекта. Потому что для меня это полноценный гражданин, а не его пальто. Вряд ли мне потребуется функция, которая работает одинаково и с FIO и с BIO, т.к. first у них ну очень разные операции, и использовать я их буду в разных местах. Именно поэтому и называться у меня они будут по-разному.
T>Где тут не подходит аналогия с классами. В том, что классы типов вроде как глобальная вещь. Если что-то сравниваемо, то оно Eq. Если из чего-то можно взять часть с именем first, то оно может быть FIO, может быть тысячей других типов.
В случае (==) семантика одна для разных типов, это сравнение, что такое first для FIO, и что он для Pair/List/BIO? Это разные вещи. И называться они должны по разному. Что такое map first?
T>Возможно, вы имели в виду другое. Вы пишете свой класс JSON, я пишу свой, у нас разное видение методов, которые он должен содержать. Действительно, не получится нам жить в одном неймспейсе, увышка. Но по-моему, разница с record syntax здесь очевидна. То есть глобальность классов гораздо более логична, чем глобальность getter-ов record-ов.
У записей нет геттеров, забудь ОО.
У классов нет методов, забудь ОО.
Глобальность классов самих по себе не важна. Важна глобальность перегружаемых функций. Аналогично глобальности меток для полей записи (а не геттеров).
Ещё аналогия
class Named n where
type E n
first :: n -> E n
last :: n -> E n
class CanSetFirst c where
type F c
first :: c -> F c -> c
Две функции с одним именем и разной семантикой. В разных классах. Что изменится, если мы поместим их в разные записи?
Подчеркну, я понимаю твою точку зрения. Но она идёт от ОО. А на Haskell не нужен ОО-дизайн.
На этот счёт было много разговоров (сходу вспоминается extensible records), но пока в Haskell ничего не изменили. По мне, так если каким либо образом метки вынесут из неймспейса функций, то это будет очень неверный шаг.
T>>Где тут не подходит аналогия с классами. В том, что классы типов вроде как глобальная вещь. Если что-то сравниваемо, то оно Eq. Если из чего-то можно взять часть с именем first, то оно может быть FIO, может быть тысячей других типов.
L>В случае (==) семантика одна для разных типов, это сравнение, что такое first для FIO, и что он для Pair/List/BIO? Это разные вещи. И называться они должны по разному. Что такое map first?
map first непонятно что. Почему? Потому что first в глобальном пространстве имён. map FIO.first (любые вариации типа map FIO $ first, map first $> FIO, неважно) это понятно что такое.
T>>Возможно, вы имели в виду другое. Вы пишете свой класс JSON, я пишу свой, у нас разное видение методов, которые он должен содержать. Действительно, не получится нам жить в одном неймспейсе, увышка. Но по-моему, разница с record syntax здесь очевидна. То есть глобальность классов гораздо более логична, чем глобальность getter-ов record-ов.
L>У записей нет геттеров, забудь ОО.
Это не ОО, это что-то из common sense, просто я использовал термин из ОО. Геттер это функция, которая читает часть сложного значения. Вся разница с ООП только в синтаксисе. Там x.first, а тут first x. Просто в ООП геттер ещё и в другом неймспейсе.
L>У классов нет методов, забудь ОО.
Это опять не из ОО, это официальная хацкельская терминология.
L>Глобальность классов самих по себе не важна. Важна глобальность перегружаемых функций. Аналогично глобальности меток для полей записи (а не геттеров).
L>Ещё аналогия
[...] L>Две функции с одним именем и разной семантикой. В разных классах. Что изменится, если мы поместим их в разные записи?
Да-да! Вот если б точно такая же перегрузка была бы и для записей — всё было бы шоколадно. Подозреваю, что для этого record syntax должен прозрачно генерить класс на каждый тип записи, и, наверное, это дорого.
L>Подчеркну, я понимаю твою точку зрения. Но она идёт от ОО. А на Haskell не нужен ОО-дизайн.
Может быть я себя обманываю, но мне кажется, что она не идёт от ОО. Я не хочу Java классов, методов объектов, public/private и пр.
L>На этот счёт было много разговоров (сходу вспоминается extensible records), но пока в Haskell ничего не изменили. По мне, так если каким либо образом метки вынесут из неймспейса функций, то это будет очень неверный шаг.
Здравствуйте, Temoto, Вы писали:
T>map first непонятно что. Почему? Потому что first в глобальном пространстве имён. map FIO.first (любые вариации типа map FIO $ first, map first $> FIO, неважно) это понятно что такое.
А, понял теперь о чём ты. Такого предложения я не слышал. Придётся всегда рядом с first писать FIO? Чем это отличается от fioFirst?
T>Это опять не из ОО, это официальная хацкельская терминология.
Да, сорри.
T>Да-да! Вот если б точно такая же перегрузка была бы и для записей — всё было бы шоколадно. Подозреваю, что для этого record syntax должен прозрачно генерить класс на каждый тип записи, и, наверное, это дорого.
Такое предложение было. Можно реализовать на TH.
T>Может быть я себя обманываю, но мне кажется, что она не идёт от ОО. Я не хочу Java классов, методов объектов, public/private и пр.
Здравствуйте, Temoto, Вы писали: T>Это не ОО, это что-то из common sense, просто я использовал термин из ОО. Геттер это функция, которая читает часть сложного значения. Вся разница с ООП только в синтаксисе. Там x.first, а тут first x. Просто в ООП геттер ещё и в другом неймспейсе.
Какие еще записи? АТД! И разбирать их паттерн-матчингом, никаких геттеров.
T>>map first непонятно что. Почему? Потому что first в глобальном пространстве имён. map FIO.first (любые вариации типа map FIO $ first, map first $> FIO, неважно) это понятно что такое.
L>А, понял теперь о чём ты. Такого предложения я не слышал. Придётся всегда рядом с first писать FIO? Чем это отличается от fioFirst?
Повторением "fio" в определении типа.
data LongType = Constructor { longtypeFirst::String, longtypeBob::Int }
Здравствуйте, Temoto, Вы писали:
L>>А, понял теперь о чём ты. Такого предложения я не слышал. Придётся всегда рядом с first писать FIO? Чем это отличается от fioFirst?
T>Повторением "fio" в определении типа.
T>
Рекомендую не заморачиваться. Реального выигрыша не будет, т.к. это даже не ad-hoc полиморфизм — не будет общих функций, работающих над обоими first. Код не уменьшится.