Как стать автором
Обновить
15
0

Пользователь

Отправить сообщение
Если интересно, можно почитать, например тут — trinary.ru
Случаем, вы не пересмотрели рекламы, «где маленькие зверьки заворачивают шоколад в фольгу»?
Однако в реальной жизни, шоколад так не делают.
И элементы памяти тоже так не делают.

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
У нас есть 2 объекта, Механика и Вектор:

1)Более простой вариант — объект Механика, принимающий на вход(сеттер) массив пар чисел, и на выходе(геттер) — новые пересчитанный массив пар чисел.
2)Усложнённый вариант Механики, возвращающий несвязанный массив пар чисел.

Объект Вектора с Хризантемкой:
3)Простой вариант — у каждого Вектора своя хризантема.
4)Усложнённый вариант — при этом хризантема во время движения должна крутиться в противофазно, относительно Вектора, к которому прикреплена.

1+3 можно исправить расширенными методами.
2+3, 1+4 лишь в некоторых случаях можно тоже, но так вряд ли кто будет делать. Будут уже править
Указатели впервые появились не в С, а (из распространенных языков) в PL/1.

Гм, просмотрел я «PL/I: Language Specifications. 1965» — не нашёл там такого.
Появились впервые в ассемблере.
В Алголе-68 есть что-то, а Паскаль куда более близкий к современному понимаю указателей, он не до конца их добавил.
И уже Си их добавил в самодостаточном варианте.
Безусловно, DSL — всего лишь способ не думать о мелочах.
Эллочке-людоедке хватило 30 слов, что бы общаться. Это и есть DSL
Но для того, что бы общаться нормально, всё равно придётся выучить язык поболе.
Интересный взгляд на языки программирования.
Чем-то перекликается с моим Развитие пользовательских типов данных в программировании

Однако, выводы разнятся.
Я бы не сказал, что развитие DSL языков будет решением проблем. Имхо, это перекладывание проблем с одних плеч(базового языка программирования) на другие (DSL-языки). А их тоже надо как-то развивать. Сейчас ведь тоже многие DSL-языки находятся на уровне ассемблера — можно только пользоваться встроенными командами.
Условно говоря, можно посмотреть на многие объекты как на фреймворки. Их используют, а не правят. Если не походят — просто не используют.
Прежде всего это касается чужих и нетривиальных объектов.

У нас один разработчик написал класс Вектор.
Второй разработчик написал класс Механика (например, для игр).
Мы (третий разработчик) молимся, что бы у нас вышел паттерн Адаптер, что бы Вектор подошёл к Механике.
Ок, вышло. (эта ситуация сама по себе показательна, могло и не выйти)

Но нам нужны не Вектора (слишком банально для заказчика), а Вектор с Хризантемкой.
Тут уже полный тупик — в Механику уже никаких цветочков не вставишь.
И тут приходится выкручиваться: либо отказываться от цветочков, либо изменять Механику, либо добавлять всевозможные костыли.
То есть я правильно понимаю, что в хаскеле для одного типа не получится в части программы использовать одну реализацию тайпкласса, а в части — другую?

Можно, если эти реализации закрыты для экспорта/импорта друг к другу.
  module TestZero (Test(..)) where  -- TestZero.hs
     data Test = Test1 | Test2

  module TestOne(testf1)  where     -- TestOne.hs
    import TestZero
    instance Eq Test where
       _ == _ = True
    testf1:: Test -> Test -> Bool
    testf1 = (==)

  module TestTwo(testf2)  where     -- TestTwo.hs
    import TestZero
    instance Eq Test where
      Test1 == Test2 = True
      Test2 == Test1 = True
      _     == _     = False
   testf2:: Test -> Test -> Bool
   testf2 = (==)

  module TestThree  where          -- TestThree.hs
    import TestZero
    import TestOne
    import TestTwo
    test  =  (testf1 Test1 Test2) == (testf2 Test1 Test2)
Вижу, всё таки есть возможность разночтения. Поэтому внёс правку.

Я даже больше скажу — в Паскале перечисления были с самого начала.

И можно было даже интервалы делать:
operations := [etOne .. etThree];
Модули первого порядка и path-dependent types в скале — это одно и то же, на сколько я это понимаю.

Если это так, то это уже есть в статье: модули первого порядка (не знаю как в Скале, а в ОКамле они к тому же могут быть рекурсивными) — достойная функциональная замена объектам.
По мощности они соизмеримы с объектами.

To a.InnerClassName и b.InnerClassName — разные типы.

Верно, а вместе с
val c: a.type = a

a.InnerClassName и с.InnerClassName — одинаковы
Что означает «разрешение ввергнутся во внутреннее пространство объекта другому объекту, поскольку он имеет такой же тип»?

То, что в вышеприведённом примере `а` не отличит себя от `с`.
PS Чего только стоит "#haskellfail" ))
Собственно, что меняет этот пример, относительно простого объекта?

Мы можем добавить новые методы, использующие интерфейс, который вшит в класс.
Да, это более гибко, чем простой интерфейс, однако, ничего более возможностей вшитого интерфейса мы не получим от объекта.
В этом докладе рассказывается, какие они построили модули первого порядка, которых нет в Стандартном МЛ. Зато почему-то промолчали, что они есть в ОКамле.
И заодно рассказывают, почему классы типов — это так плохо на Хаскеле, зато так классно в Скале.

Что касается path-dependent types — в докладе об этом не сказано.
Тем не менее, path-dependent types — это разрешение ввергнутся во внутреннее пространство объекта другому объекту, поскольку он имеет такой же тип:
res: java.lang.Class[_ <: VariableName.InnerClassName] = class OuterClassName$InnerClassName
Хороший вопрос, как отличаются.
Одно можно сказать точно, это попытка ввести хаскелевские классы типов в Скала.
На счёт Скала — спасибо, попробую добавить. Эти «путе-зависимые» объекты добавляют межобъектное (одного класса) взаимодействие, но не межклассовое. Правильно?

Зависимые типы — отлично замечено. Я их не рассматривал, так как Agda и Coq используются для доказательств, а не программирования естественных задач.

Лямбда функции, хоть их техническая реализация может отличатся от обычных функций в языке, тем не менее, являются обычными функциями, с такими же возможностями. Были ещё в раннем Лиспе.
Generic — метапрограммирование.
Он не предоставляет новые пользовательские данные.
Он «всего лишь» избавляет от рутины написания порождающих Generic классов
На счёт Паскаля — да, я об этом написал.
На счёт Делфи — похоже да, ошибся, исправлю, спасибо

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность