Случаем, вы не пересмотрели рекламы, «где маленькие зверьки заворачивают шоколад в фольгу»?
Однако в реальной жизни, шоколад так не делают.
И элементы памяти тоже так не делают.
P.S. Представил себе, как сотни миллионов 6-гранных элементов памяти одновременно по-миллисекундно переключают мостики. ))
Код на Хаскеле несколько отличается от ООП-шного.
И развитие кода тоже имеет несоответствия.
В основном код излишне общ.
И в большинстве случаев достаточно просто использовать код.
При этом нет нужны во всяких фабриках и фабриках фабрик.
Из-за обобщённости нет необходимости изменять поведение, достаточно дописать функционал.
Если и нужно менять, то в основном, добавляется очень малое количество кода — до нескольких строчек.
Хотя конечно же, если код не оптимальный — изменения могут быть существенными.
Необходимо отметить, на Хаскеле данными могут быть не только данными, а и действиями, или совокупностью.
Скрытый текст
Например, монады — это данные, с которыми можно работать в императивном стиле, стрелки — данные, с которыми можно работать как блок-схемами, линзы — данные, с которыми можно работать как с объектами.
Поэтому на Хаскеле не надо отдельно заниматься данными, отдельно действиями, отдельно архитектурой.
Если интересна именно эволюция кода, советую почитать интересную статью автора библиотеки, где он описывает, что он добавил в неё. pipes-3.3.0:…
отрывок
pipes-2.4 впервые идентифицировал существование трёх дополнительных категорий, два из которых я назвал «request» и «respond». Эти категории очень полезны, особенное, если можно использовать ListT с обоими. Но я открыл, что нельзя использовать (/>/) и (\>\) композиции операторов для некоторых прокси-траснформеров, особенно
MaybeP
EitherP
StateP
WriterP
Это очень разочаровывало и казалось действительно странным, что прокси-трансформер может поднять одинаковость этих категорий (т.е. request и respond), но не всегда может поднять соответственную им композицию операторов.
Я принял временное решение, отделить (/>/) и (\>\) в отдельный ListT класс типов.
…
(работая с pipes-directory и ExceptionP обнаружилось), ExceptionP — это всего лишь синоним EitherP, а EitherP не имплементировал ListT класс, а это означало, что я не мог использовать монаду ProduceT. Поэтому я пересмотрел EitherP и открыл, что есть закон, по которому можно сделать инстанс EitherP для ListT, тот, который я искал ранее. Более того, я мог использовать то же самое для применения MaybeP к ListT.
А это означало, что только 2 прокси-трансформера остались без импементирования ListT:
StateP
WriterP
Кроме того, WriterP внутренне определялся под полом через StateP, означая, что если я смогу найти решение по StateP, я смогу объединить ListT назад к Proxy классу.
Попутно, работая с pipes-parse, я открыл несколько неверных частных случаев для StateP, которые давали неверное поведение. Также оказалось, что и WriterP тоже давал неверное поведение в широких вариантах случаев.
Это означало, что я имплементировал оба этих прокси-трансформера неверно, поскольку оба давали много неверных результатов для многих случаев. И оба этих трансформера не могли быть подключены к ListT.
Это наблюдение позволило мне открыть правильное решение: разрешить StateP и WriterP делится эффектами глобально в линии (pipeline), вместо локально.
Это решение фиксировало обе проблемы:
— оба могли имплементировать List и подчинялись законам ListT
— Оба давали правильное поведение во всех частных случаях.
Вследствие этого, я снова объединил ListT к классу Proxy и объединил request и respond к их соответствующим композитным операторам.
Ну, и сейчас все прокси-трансформеры поднимают все четыре категории верно.
Да, это наиболее близко.
Разница заключается в доступе изменения данных.
Интерфейсы дают доступ лишь к прописанным(в интерфейсе) полям, а инстансы — ко всем полям.
Пы.Сы. Кстати, в Хаскеле есть свои Генерики. Даже не один, а 3 направления
— Generic
— Template
— Data
Хаскель не объектно-ориентированный язык.
В нём нет объектов вообще.
Покажу пример 1+3+4:
Функция
mechanic :: Movement m => m ->m
instance Movement (Double,Double) where
move (x, y) = (x + dx, y+dy)
instance Movement FlowerVector where
move (FlowerVector {..}) = FlowerVector {x = x + dx, y = y + dy,
flower_x = flower_x - dx, flower_y = flower_x - dy,
flower = flower}
Можете добавить свои данные. Например, как зависит цвет, форма цветка в зависимости от тех или иных событий.
Можно вообще любые данные обрабатывать, только надо написать экземпляр instance Movement MyData
1)Более простой вариант — объект Механика, принимающий на вход(сеттер) массив пар чисел, и на выходе(геттер) — новые пересчитанный массив пар чисел.
2)Усложнённый вариант Механики, возвращающий несвязанный массив пар чисел.
Объект Вектора с Хризантемкой:
3)Простой вариант — у каждого Вектора своя хризантема.
4)Усложнённый вариант — при этом хризантема во время движения должна крутиться в противофазно, относительно Вектора, к которому прикреплена.
1+3 можно исправить расширенными методами.
2+3, 1+4 лишь в некоторых случаях можно тоже, но так вряд ли кто будет делать. Будут уже править
Указатели впервые появились не в С, а (из распространенных языков) в PL/1.
Гм, просмотрел я «PL/I: Language Specifications. 1965» — не нашёл там такого.
Появились впервые в ассемблере.
В Алголе-68 есть что-то, а Паскаль куда более близкий к современному понимаю указателей, он не до конца их добавил.
И уже Си их добавил в самодостаточном варианте.
Безусловно, DSL — всего лишь способ не думать о мелочах.
Эллочке-людоедке хватило 30 слов, что бы общаться. Это и есть DSL
Но для того, что бы общаться нормально, всё равно придётся выучить язык поболе.
Однако, выводы разнятся.
Я бы не сказал, что развитие DSL языков будет решением проблем. Имхо, это перекладывание проблем с одних плеч(базового языка программирования) на другие (DSL-языки). А их тоже надо как-то развивать. Сейчас ведь тоже многие DSL-языки находятся на уровне ассемблера — можно только пользоваться встроенными командами.
Условно говоря, можно посмотреть на многие объекты как на фреймворки. Их используют, а не правят. Если не походят — просто не используют.
Прежде всего это касается чужих и нетривиальных объектов.
У нас один разработчик написал класс Вектор.
Второй разработчик написал класс Механика (например, для игр).
Мы (третий разработчик) молимся, что бы у нас вышел паттерн Адаптер, что бы Вектор подошёл к Механике.
Ок, вышло. (эта ситуация сама по себе показательна, могло и не выйти)
Но нам нужны не Вектора (слишком банально для заказчика), а Вектор с Хризантемкой.
Тут уже полный тупик — в Механику уже никаких цветочков не вставишь.
И тут приходится выкручиваться: либо отказываться от цветочков, либо изменять Механику, либо добавлять всевозможные костыли.
Модули первого порядка и path-dependent types в скале — это одно и то же, на сколько я это понимаю.
Если это так, то это уже есть в статье: модули первого порядка (не знаю как в Скале, а в ОКамле они к тому же могут быть рекурсивными) — достойная функциональная замена объектам.
По мощности они соизмеримы с объектами.
To a.InnerClassName и b.InnerClassName — разные типы.
Верно, а вместе с
val c: a.type = a
a.InnerClassName и с.InnerClassName — одинаковы
Что означает «разрешение ввергнутся во внутреннее пространство объекта другому объекту, поскольку он имеет такой же тип»?
То, что в вышеприведённом примере `а` не отличит себя от `с`.
Собственно, что меняет этот пример, относительно простого объекта?
Мы можем добавить новые методы, использующие интерфейс, который вшит в класс.
Да, это более гибко, чем простой интерфейс, однако, ничего более возможностей вшитого интерфейса мы не получим от объекта.
В этом докладе рассказывается, какие они построили модули первого порядка, которых нет в Стандартном МЛ. Зато почему-то промолчали, что они есть в ОКамле.
И заодно рассказывают, почему классы типов — это так плохо на Хаскеле, зато так классно в Скале.
Что касается path-dependent types — в докладе об этом не сказано.
Тем не менее, path-dependent types — это разрешение ввергнутся во внутреннее пространство объекта другому объекту, поскольку он имеет такой же тип:
res: java.lang.Class[_ <: VariableName.InnerClassName] = class OuterClassName$InnerClassName
На счёт Скала — спасибо, попробую добавить. Эти «путе-зависимые» объекты добавляют межобъектное (одного класса) взаимодействие, но не межклассовое. Правильно?
Зависимые типы — отлично замечено. Я их не рассматривал, так как Agda и Coq используются для доказательств, а не программирования естественных задач.
Лямбда функции, хоть их техническая реализация может отличатся от обычных функций в языке, тем не менее, являются обычными функциями, с такими же возможностями. Были ещё в раннем Лиспе.
Generic — метапрограммирование.
Он не предоставляет новые пользовательские данные.
Он «всего лишь» избавляет от рутины написания порождающих Generic классов
Однако в реальной жизни, шоколад так не делают.
И элементы памяти тоже так не делают.
P.S. Представил себе, как сотни миллионов 6-гранных элементов памяти одновременно по-миллисекундно переключают мостики. ))
И развитие кода тоже имеет несоответствия.
В основном код излишне общ.
И в большинстве случаев достаточно просто использовать код.
При этом нет нужны во всяких фабриках и фабриках фабрик.
Из-за обобщённости нет необходимости изменять поведение, достаточно дописать функционал.
Если и нужно менять, то в основном, добавляется очень малое количество кода — до нескольких строчек.
Хотя конечно же, если код не оптимальный — изменения могут быть существенными.
Необходимо отметить, на Хаскеле данными могут быть не только данными, а и действиями, или совокупностью.
Поэтому на Хаскеле не надо отдельно заниматься данными, отдельно действиями, отдельно архитектурой.
Если интересна именно эволюция кода, советую почитать интересную статью автора библиотеки, где он описывает, что он добавил в неё.
pipes-3.3.0:…
MaybeP
EitherP
StateP
WriterP
Это очень разочаровывало и казалось действительно странным, что прокси-трансформер может поднять одинаковость этих категорий (т.е. request и respond), но не всегда может поднять соответственную им композицию операторов.
Я принял временное решение, отделить (/>/) и (\>\) в отдельный ListT класс типов.
…
(работая с pipes-directory и ExceptionP обнаружилось), ExceptionP — это всего лишь синоним EitherP, а EitherP не имплементировал ListT класс, а это означало, что я не мог использовать монаду ProduceT. Поэтому я пересмотрел EitherP и открыл, что есть закон, по которому можно сделать инстанс EitherP для ListT, тот, который я искал ранее. Более того, я мог использовать то же самое для применения MaybeP к ListT.
А это означало, что только 2 прокси-трансформера остались без импементирования ListT:
StateP
WriterP
Кроме того, WriterP внутренне определялся под полом через StateP, означая, что если я смогу найти решение по StateP, я смогу объединить ListT назад к Proxy классу.
Попутно, работая с pipes-parse, я открыл несколько неверных частных случаев для StateP, которые давали неверное поведение. Также оказалось, что и WriterP тоже давал неверное поведение в широких вариантах случаев.
Это означало, что я имплементировал оба этих прокси-трансформера неверно, поскольку оба давали много неверных результатов для многих случаев. И оба этих трансформера не могли быть подключены к ListT.
Это наблюдение позволило мне открыть правильное решение: разрешить StateP и WriterP делится эффектами глобально в линии (pipeline), вместо локально.
Это решение фиксировало обе проблемы:
— оба могли имплементировать List и подчинялись законам ListT
— Оба давали правильное поведение во всех частных случаях.
Вследствие этого, я снова объединил ListT к классу Proxy и объединил request и respond к их соответствующим композитным операторам.
Ну, и сейчас все прокси-трансформеры поднимают все четыре категории верно.
Разница заключается в доступе изменения данных.
Интерфейсы дают доступ лишь к прописанным(в интерфейсе) полям, а инстансы — ко всем полям.
Пы.Сы. Кстати, в Хаскеле есть свои Генерики. Даже не один, а 3 направления
— Generic
— Template
— Data
В нём нет объектов вообще.
Покажу пример 1+3+4:
Функция
Можете добавить свои данные. Например, как зависит цвет, форма цветка в зависимости от тех или иных событий.
Можно вообще любые данные обрабатывать, только надо написать экземпляр
instance Movement MyData
1)Более простой вариант — объект Механика, принимающий на вход(сеттер) массив пар чисел, и на выходе(геттер) — новые пересчитанный массив пар чисел.
2)Усложнённый вариант Механики, возвращающий несвязанный массив пар чисел.
Объект Вектора с Хризантемкой:
3)Простой вариант — у каждого Вектора своя хризантема.
4)Усложнённый вариант — при этом хризантема во время движения должна крутиться в противофазно, относительно Вектора, к которому прикреплена.
1+3 можно исправить расширенными методами.
2+3, 1+4 лишь в некоторых случаях можно тоже, но так вряд ли кто будет делать. Будут уже править
Гм, просмотрел я «PL/I: Language Specifications. 1965» — не нашёл там такого.
Появились впервые в ассемблере.
В Алголе-68 есть что-то, а Паскаль куда более близкий к современному понимаю указателей, он не до конца их добавил.
И уже Си их добавил в самодостаточном варианте.
Эллочке-людоедке хватило 30 слов, что бы общаться. Это и есть DSL
Но для того, что бы общаться нормально, всё равно придётся выучить язык поболе.
Чем-то перекликается с моим Развитие пользовательских типов данных в программировании
Однако, выводы разнятся.
Я бы не сказал, что развитие DSL языков будет решением проблем. Имхо, это перекладывание проблем с одних плеч(базового языка программирования) на другие (DSL-языки). А их тоже надо как-то развивать. Сейчас ведь тоже многие DSL-языки находятся на уровне ассемблера — можно только пользоваться встроенными командами.
Прежде всего это касается чужих и нетривиальных объектов.
У нас один разработчик написал класс Вектор.
Второй разработчик написал класс Механика (например, для игр).
Мы (третий разработчик) молимся, что бы у нас вышел паттерн Адаптер, что бы Вектор подошёл к Механике.
Ок, вышло. (эта ситуация сама по себе показательна, могло и не выйти)
Но нам нужны не Вектора (слишком банально для заказчика), а Вектор с Хризантемкой.
Тут уже полный тупик — в Механику уже никаких цветочков не вставишь.
И тут приходится выкручиваться: либо отказываться от цветочков, либо изменять Механику, либо добавлять всевозможные костыли.
Можно, если эти реализации закрыты для экспорта/импорта друг к другу.
Я даже больше скажу — в Паскале перечисления были с самого начала.
И можно было даже интервалы делать:
Если это так, то это уже есть в статье: модули первого порядка (не знаю как в Скале, а в ОКамле они к тому же могут быть рекурсивными) — достойная функциональная замена объектам.
По мощности они соизмеримы с объектами.
Верно, а вместе с
a.InnerClassName и с.InnerClassName — одинаковы
То, что в вышеприведённом примере `а` не отличит себя от `с`.
Мы можем добавить новые методы, использующие интерфейс, который вшит в класс.
Да, это более гибко, чем простой интерфейс, однако, ничего более возможностей вшитого интерфейса мы не получим от объекта.
И заодно рассказывают, почему классы типов — это так плохо на Хаскеле, зато так классно в Скале.
Что касается path-dependent types — в докладе об этом не сказано.
Тем не менее, path-dependent types — это разрешение ввергнутся во внутреннее пространство объекта другому объекту, поскольку он имеет такой же тип:
Одно можно сказать точно, это попытка ввести хаскелевские классы типов в Скала.
Зависимые типы — отлично замечено. Я их не рассматривал, так как Agda и Coq используются для доказательств, а не программирования естественных задач.
Лямбда функции, хоть их техническая реализация может отличатся от обычных функций в языке, тем не менее, являются обычными функциями, с такими же возможностями. Были ещё в раннем Лиспе.
Он не предоставляет новые пользовательские данные.
Он «всего лишь» избавляет от рутины написания порождающих Generic классов
На счёт Делфи — похоже да, ошибся, исправлю, спасибо