dmz>>В этом конвейре можно настроить все — и поведение, и данные. И даже сделать так, что бы конкретное поведение определялось структурой данных на входе.
NGG>Целиком и полностью согласен и нисколько с этим не спорю. Я только повторяю заезженную истину о том, что дьявол в деталях. NGG>Как делается настройка "и поведения, и данных"?
передачей их в качестве параметров
NGG>Как повторно использовать "труды" настройки?
видимо, речь идёт о partial application?
NGG>А если я напишу класс NGG>сlass TaskNumberOne { NGG>void process(Source inp, Filter filt , Group group_by, Consumer consume) {...} NGG>} NGG>вставив внутрь строчки для органиции потока данных по этой цепочке, я тоже разом решу все возможные проблемы?
да, а разве нет? разница только в том, что на C# это наверно будет достаточно сложная функция
NGG>Ну, так я и прошу озвучить в чём же этот подход заключается, как при его использовании решаются проблемы борьбы со сложностью озвученные в тех же самых шаблонах грасп и т.п. Так же мне интересно, что мешает применять этот "другой" подход, скажем, лабая код на java. Станет ли он сразу не эффективным и почему? Если не станет, то в чём его плюсы перед имеющимся в наличии ООД? Если плюсы есть, то я стану использовать его в повседневной работе и буду рад безмерно.
все три C* языка активно добавляют в свой арсенал ФП фичи. поэтому давайте посмотрим скажем какие проблемы возникнут при использовании ФП подхода в чистом С или C++ 80-х годов:
1) нам нужна передача функций в качестве параметров и возвращение их в качестве результатов. это поддерживается
2) нужна поддержка анонимных лямбд. этого нет — все функции должны быть описаны глобально. но по крайней мере выразительную мощь языка это не изменяет
3) нужна поддержка частичного применения. этого нет
4) нужен двухсторонний автовывод типов с автоматическим обобщением. этого тоже нет, что затрудняет разбиение алгоритмов на множество небольших [глобальных, локальных и анонимных] функций — засребёшься описывать типы всех их параметров и результатов
5) нужно ленивое вычисление. тоже нет
6) ну и самом собой, нужен GC
в остальном ФП подходы вполне применимы и на C* языках
dmz>>В данном топике задачи слишком простые, что бы к ним серьезно применять термин "дизайн". Problem K — уже гораздо интереснее. NGG>Согласен полностью. Простые. Но я же смог показать на простой задаче применение ОО-дизайна. Так же точно, мне думается, не должно быть проблемой продемонстрировать "другой подход к дизайну" на этой же задаче. Некоторые примеры были показаны, я сравнил решения, задал волнующие меня вопросы. Ответы на подобные вопросы по своему решению я могу дать, по чужим — хочу услышать.
моё понимание ФП дизайна — это представить себе, что ты для каждой задачи разрабатываешь свой собственный язык программирования. ты не ограничен определённым набором средств структурирования программы, типа классов или указателей. твоя задача — объяснить компьютеру как решить проблему, используя при этом любой удобный тебе алгоритмический язык. и тут на первое место выходит именно то, как сделать это объяснение наиболее читабельным и сопровождаемым
вот пример. представим классическую gui-библиотеку. реализация диалога настроек на ней может выглядеть так:
1) создаём все необходимые controls
2) заполняем их исходными данными
3) отображаем диалог
4) после нажатия Ok обновляем переменные
удобно ли это? на мой взгляд нет — нужно сгруппировать описание контрола, перевод данных в него и обратно. соответственно ФП-дизайн здесь состоит в создании высокоуровневых контролов, которые несут в себе не только свои данные, но и ассоциированные с ними действия. и тогда программа будет выглядеть так:
Здравствуйте, yumi, Вы писали:
Y>Здравствуйте, dmz, Вы писали:
dmz>>Более того, человек, который написал мега-фреймворк для сортировки ящиков, может уже не работать на момент, когда изменения понадобятся. Придет следующий человек. Получит задачу сделать так, что бы помимо ящиков, сортировались так же и бочки. Увидит фреймворк. Как думаете, он будет вникать в весь "повторно использованный код" ? Или проведет "рефакторинг" — т.е. выкинет или забьет, и напишет свое?
Y>Вы не так поняли, точнее смотрите с другой точки зрения. Только с позиции одного разработчика. Фича мега-фреймворка как раз в том, что какую-то часть, например, сортировку ящиков может делать один человек, а другой может писать сортировку бочек. Причем им нужен только интерфейс ISort.
Тема сортировки пока никем не поднималась, но в рамках предметной области допущение, что она понадобится — вполне резонное. ISort — это, кстати, у кого будет такой интерфейс? В рамках предложенной декомпозиции? Ась?
Но смотрю я не с точки зрения разработчика. Смотрю я, допустим, с точки зрения заказчика или аутсорс-менеджера. И вижу, что вместо задачи построения дискового индекса, которую я заказывал, мне впаривают фреймворк для (цитирую)
[quote]
Дано: источник данных, критерий разбиения данных на группы
Надо: данные разбить на группы, обработать данные в группах.
[/quote]
Таких задач не бывает, но да ладно. Для увеличения вероятности того, что нам такая задача понадобится — расширим ее аудиторию с рамок данного проекта до всего мира. Выложим в сеть. Как будете искать ее решение в гугле? Ладно, допустим, мы нашли.
Что мы видим? Для того, что бы данным решением воспользоваться — нужно пользоваться контейнерным (по сути) классом Group (если у нас данные ходят в каком-нибудь обычном List — придется написать адаптер, какой — нибудь свой FromListProcessor, разобраться, чем отличаются Group от Processor с одинаковым интерфейсом (две разные сущности с внешне одинаковым поведением, тесно сцепленные), а потом еще вытащить свои данные из Group.
И это вместо того, что бы тупо в лоб воспользоваться фундаментальными примитивами group, map, filter — которые будут работать с любыми списками (не знаю, как в джаве, но в питоне есть group, filter, map прямо вот в таком виде) — на которые данная задача естественно декомпозируется.
Здравствуйте, NotGonnaGetUs, Вы писали:
NGG>Гхм. Тут какое-то расхождение во взглядах на то, что такое монолитность NGG>Мне как раз твоё решение видится монолитным кусоком кода, а моё комбинируется из нескольких классов для полученя нужного результата и каждый из этих классов может жить счастливой самостоятельной жизнью.
Так как в функциональных языках функция первоклассная сущность, твое высказывание перепишется так:
а моё комбинируется из нескольких функций для полученя нужного результата и каждая из этих функций может жить счастливой самостоятельной жизнью.
Здравствуйте, NotGonnaGetUs, Вы писали:
NGG>Хитрожопую группу, которую простым фильтром не получить Н-р, нужно помнить состояние, а это меняет интерфейс группировалки...
NGG>Понятно, что "хорошее" решение, к которому я не смог бы придраться существует. Интересен принцип по которым оно строилось бы с полпинка.
На самом деле непонятно. Потому что появляются такие усложнения, которые скорее говорят о кривом решении некой другой задачи, раз появилась такая, где для группировки скоро придётся в базу данных обращаться, причём внутри самой группировалки.
Т.е. если вот приспичило цепочку собрать, так можно её и собрать, написав элементарную функцию, а не писать обобщённую группировалку, которая бы умела всё.
type Group a b = [a] -> ([([a], [a] -> b)], [a])
passFirst g s = g s
passAll g s = (fst $ g s, s)
makeGroup :: (Eq a) => ([a] -> [a]) -> ([a] -> b) -> Group a b
makeGroup f p l = ([(m, p)], l \\ m) where m = f l
composeGroup p f n [] = ([], [])
composeGroup p f n l = (fg ++ ng, ntail) where
(fg, ftail) = p f l
(ng, ntail) = p n ftail
seqGroup :: (Eq a) => Group a b -> Group a b -> Group a b
seqGroup = composeGroup passFirst
unionGroup :: (Eq a) => Group a b -> Group a b -> Group a b
unionGroup = composeGroup passAll
groupAndProcess input grouping = mapM_ (\x -> (snd x) (fst x)) $ fst $ grouping input
-- Остальное ниже - семечки, к делу не относящиеся
groupCmp cmp [] = []
groupCmp cmp l@(s:_) = filter (cmp s) l
groupByWith cmp x = seqGroup (makeGroup (groupCmp cmp) x) (groupByWith cmp x)
consoleOutput prefix input = putStrLn prefix >> mapM_ (putStrLn . ("\t" ++)) input
byFirstLetter :: String -> String -> Bool
byFirstLetter _ [] = False
byFirstLetter [] _ = False
byFirstLetter (l:_) (r:_) = l == r
groupStated f i l = map fst $ filter snd $ zip l $ fst $ runState (mapM f l) i
statedFilter :: String -> State String Bool -- группировалка со стейтом
statedFilter s = do
lastStr <- get
if ((null lastStr) || (null s) || ((last lastStr) == head s))
then do
put s
return True
else return False
input = ["abc", "cde", "efg", "aaa", "ghi", "sxdf", "zadedf", "sfsfg", "atrhyh", "43f5", "sdcsby", "Unuufd"]
main = groupAndProcess input $ unionGroup -- union, т.е. элементы попадут в обе группы
(makeGroup (groupStated statedFilter "") (\xs@(x:_) -> consoleOutput [head x] xs)) -- составляем цепочку слов
(groupByWith byFirstLetter (\xs@(x:_) -> consoleOutput [head x] xs)) -- группируем по первому символу
Смотря на всё это, делаю 3 вывода: 1. Основной код всё равно невелик, 15 строк
2. Либо всё это пишется проще на порядок (хотелось бы тогда от гуру увидеть подтверждение)
3. И проще решать частные задачи по 2 строки на каждую, чем делать такое обобщение, которым и пользоваться не будет никто
Собственно, то же самое, но в частном случае:
byFirstLetter :: String -> String -> Bool
byFirstLetter _ [] = False
byFirstLetter [] _ = False
byFirstLetter (l:_) (r:_) = l == r
makeChain strs = reverse $ makeChain' strs "" [] where
makeChain' [] cur acc = acc
makeChain' (c:cs) cur acc
| isPrefixOf cur c = makeChain' cs [last c] (c:acc)
| otherwise = makeChain' cs cur acc
main = consoleOutput "chain" chain >> mapM_ (\xs@(x:_) -> consoleOutput [head x] xs) groups where
(chain, groups) = (makeChain &&& (groupBy byFirstLetter . sort)) input
BZ>>несколько методов передать можно точно так же. насчёт контрактов я не понял — дай пример
и чем тебя не устраивает твоё решение?
BZ>>а почему моё решение комбинирует несколько функций для получения нужного результата, а твоё — монолитно? я думаю, причина в том, что в C* описание класса или даже функции — достаточно многословно, поэтому есть тенденция складывать в них больше функциональности, нежели в хаскеле
NGG>Гхм. Тут какое-то расхождение во взглядах на то, что такое монолитность NGG>Мне как раз твоё решение видится монолитным кусоком кода, а моё комбинируется из нескольких классов для полученя нужного результата и каждый из этих классов может жить счастливой самостоятельной жизнью.
NGG>Само-то решение вот: NGG>Где тут монолитность?
виноват, я в твоём решении просто не разбирался. имхо, оно ничем не отличается от моего, только я ес-но использую функции, а не классы. если к примеру тебе потребуется разбивать на классы 0..9 вместо a..z, то точно также придётся менять процитированный тобой код, как и в моём решении
Здравствуйте, dmz, Вы писали:
NGG>>вставив внутрь строчки для органиции потока данных по этой цепочке, я тоже разом решу все возможные проблемы? dmz>Все возможные проблемы решить вообще невозможно. Эту задачу — да, вполне можно решить и так.
Ну так если затем расписать все перечисленные в аргуметах интерфейсы классы, получится тоже самое количество кода что в обрисованном мной вараинте.
dmz>А можно применить шаблон template method, например, а конкретные реализации параметризовать. Получится по смыслу почти то-же, что и в ФП примере.
Так оно влюбом варианте получится тоже самое по смыслу...
dmz>Очевидно, что у нас есть повторно используемые компоненты — источник (input) — который генерирует последовательность сущностей, filter, группирующая функция (считает некий ключ для этих сущностей), и консьюмер, да и сам алгоритм, в общем. Который в силу полиморфизма можно использовать для других объектов, для которых определены соответствующие компоненты.
+ NGG>>Если расписать всё это, получатся теже яйца, что и в оо варианте вид сбоку
IFilter — filter
IGroup#add — группирующая функция (не один к одному, т.к. есть разница между группами заданными из вне и группа создаваемыми в ходе работы алгоритма (как в решении с (take 3)). "Знание" о таких группах находится в реализации CompositeGroup и там может и должен использовать дескриминатор строящий по данным группу)
IProcessor — консьюмер
СompositeGroup — сам алгоритм
Разве не яйца?
dmz>Очевидно, что неверно про раз и навсегда заданные задачи.
Наверное, очевидным должно быть, что не только для раз и на всегда заданных условий, а для более широго круга задач
Вот собственно поддтверждения этому я и хочу найти.
NGG>>Ну, так я и прошу озвучить в чём же этот подход заключается, ... Станет ли он сразу не эффективным и почему? dmz>Да потому, что язык не поддерживает.
А что он должен поддреживать? Только анонимные функции? Т.е. в C# уже на ура будет работать?
dmz>Честно говоря, приплетать опять грасп к этой задаче — это уже слишком.
Они приплетались не к этой задаче, а к вопросу о том с каким самоваром я лезу в фп
Куда, н-р, денешься от того, что есть точки не устойчивости в программах? Надо же как-то с этим бороться. В ООП интерфейсом отгараживаются, в ФП тоже как-то нужно бороться.
dmz> Ну вот пример — был у нас фильтр непустых строк, но, допустим, надо бы отсортировать комментарии и вообще — уметь наложить вместо одного фильтра N фильтров, но фильтры известны в компайл-тайме. Ну, в общем, вполне себе допущение, не хуже уже прочих.
dmz>Решение на ОО (оппа, группового наложения мы сразу не не предусмотрели? Ну, не беда) dmz>
dmz>class MegaFilter : Filter
dmz>{
dmz>};
dmz>
Гхм. Это вообще-то называется AndFilter и его добавление не приводит к изменниям в коде. Тот самый OCP в действии
Реализовывать его, пока он не был нужен и было бы овердизайном и заточкой под изменения, которые никогда не случатся (в отличии от декларации интерфейсов).
dmz>Решение три — рефакторим интерфейсы
Давайте без этого
NGG>>то в чём его плюсы перед имеющимся в наличии ООД? Если плюсы есть, то я стану использовать его в повседневной работе и буду рад безмерно. NGG>>Согласен полностью. Простые. Но я же смог показать на простой задаче применение ОО-дизайна. dmz>В итоге имеем овердизайн.
+1024.
Только цель предложенного дизайна была не показать как ооп крут, а фп гавно (такое ощущение, что многими, кто мне отвечал, оно воспринимается именно так). В том сообщении я задал вопрос про то, как выглядело бы решение в функциональном стиле будь это не задачка на две строчки, а "реальная" задача. ОО-код служит примером того, как я ответил бы на этот вопрос задай мне его кто-нибудь. Просто иллюстрация, чтобы было понятно о чём я спрашиваю. Похоже канал коммуникации этим приёмом настроить не удалось
dmz> из постановки очевидно, что "принять набор сущностей, отфильтровать, сгруппировать и и отдать консьюмеру" — это не есть сама задача — это решение некоей задачи.
Да как сказать... не очень очевидно
dmz> если задача решается в одну-две строки — то очевидно, если ВДРУГ, когда нибудь, в следующей жизни потребуются некоторые модификации, то две строчки проще выкинуть и написать заново, если уж на то пошло.
Опять +1024, но я уже тоже об этом раз 5 упомянул в своих ответах.
dmz> Как думаете, он будет вникать в весь "повторно использованный код" ? Или проведет "рефакторинг" — т.е. выкинет или забьет, и напишет свое?
Оффтоп:
Вот я сейчас в роли такого человека оказался. Перед глазами три "фреймоврка" для "легкого" построения гуя в одном приложение и все настолько безобразны (7+ лет приложению), что я плачу. Уже давно мечтаю всё выкинуть и написать своё, бо цена рефакторинга почти такая же, но если текущая задача стоит Х, переписать и выполнить текущую задачу "красиво" будет стоить 100*X, если не больше. Приходится закрывать глаза и получать удовльствие
Собственно эта ситуация отчасти поспособствовала тому, что я стал задавать тут глупые вопросы. Стало интересно, что было бы, пиши это приложение в течении 7 лет теже недалёкие люди, но только на функциональном языке. Больше гавна пришлось бы разбирать или меньше?
dmz>Особенно хорошо становится, когда креативных людей больше одного — все читали гамму, лармана и фаулера, там столько паттернов...
Я боюсь, что "креативных людей" в оо-мире не больше, чем было бы в ф-мире стань он мейнстримом, только читали бы не эти книги, а всяких других умных людей
dmz>Я еще раскрою тему.
Жду с нетерпением
Здравствуйте, dmz, Вы писали:
dmz>Но смотрю я не с точки зрения разработчика. Смотрю я, допустим, с точки зрения заказчика или аутсорс-менеджера. И вижу, что вместо задачи построения дискового индекса, которую я заказывал, мне впаривают фреймворк для (цитирую)
Вы передёргиваете. В данном случае, и заказчик и исполнитель я. И таких требований у меня нет.
Принять решение насколько нужно обобщать задачу без общения с заказчиком программист не должен. Это вне рамок его компетенции.
dmz>Что мы видим? Для того, что бы данным решением воспользоваться — нужно пользоваться контейнерным (по сути) классом Group (если у нас данные ходят в каком-нибудь обычном List — придется написать адаптер, какой — нибудь свой FromListProcessor, разобраться, чем отличаются Group от Processor с одинаковым интерфейсом (две разные сущности с внешне одинаковым поведением, тесно сцепленные), а потом еще вытащить свои данные из Group.
Неа, нужно будет только написать свой процессор, который будет результат представлять ввиде желаемого вам листа или кренделя с бубликом.
И никаких гвоздей.
К моменту завоевания мира эти реализации уже будет в составе фреймворка
dmz>И это вместо того, что бы тупо в лоб воспользоваться фундаментальными примитивами group, map, filter — которые будут работать с любыми списками (не знаю, как в джаве, но в питоне есть group, filter, map прямо вот в таком виде) — на которые данная задача естественно декомпозируется.
Кстати, да. В отличии от того же c# в java стандартных group,filter,map — нет. Писать самоделки не даёт отсутствие "компактного" синтаксиса для написания лямбд и понижение производительности связанное с копирование списков, что в сумме перевешивает выгоды от наличия таких методов. В 7-ой будут лямбы и, думается мне, обновятся соответствующим образом стандартные библиотеки.
Здравствуйте, BulatZiganshin, Вы писали:
NGG>>Целиком и полностью согласен и нисколько с этим не спорю. Я только повторяю заезженную истину о том, что дьявол в деталях. NGG>>Как делается настройка "и поведения, и данных"? NGG>>Как повторно использовать "труды" настройки?
BZ>передачей их в качестве параметров BZ>видимо, речь идёт о partial application?
Сарказм понятен, переформулирую вопрос.
Чтобы передать "в качестве параметров" нужно как-то создать эти парметры.
Как они будут создаваться?
Как избежать дублирования кода, если метод дергается из разных мест в коде со слегка различающимися параметрами?
Не дурак, понимаю, что общая логика должна быть вынесена методы.
Тогда почему в предлагаемых решениях они не вынесены?
Опять не дурак, опять понимаю, что на кой их выносить, если всё в одной строчке.
Ну так я же просил показать как будет выглядеть решение "боевой" задачи, как если бы это было решение, которое ждёт большее будущее и долгая история развития
У меня подозрение, что проделай вы всё это, вместо одной строчки было бы что-то похожее по количеству строчек на код VoidEх'a.
Ну раз этот поинт никому не интересен можно забить на мои вопросы.
BZ>4) нужен двухсторонний автовывод типов с автоматическим обобщением. этого тоже нет, что затрудняет разбиение алгоритмов на множество небольших [глобальных, локальных и анонимных] функций — засребёшься описывать типы всех их параметров и результатов
Кстати, да. Декларации типов с генериками могут засрать код хорошо... Даже без относительно к фп хотелось бы такое иметь в наличии
BZ>удобно ли это? на мой взгляд нет — нужно сгруппировать описание контрола, перевод данных в него и обратно. соответственно ФП-дизайн здесь состоит в создании высокоуровневых контролов, которые несут в себе не только свои данные, но и ассоциированные с ними действия. и тогда программа будет выглядеть так: BZ>
Пока гуй простецкий это работает. Пробовал на практике, для java есть возможность так писать используя Groovy и JavaFX. Но как только действия становятся сложнее, чем простое присвоение значения и когда контролы зависят друг от друга многими связями, плюсов станосится как-то заментно поменьше... mvc опять начинает рулить.
Но подход "dsl средствами языка" мне тоже нравится. Жаль, что в синтаксис java досточно убог для его широкого применения. Жду java7, где обещают быть улучшения в этом плане.
Здравствуйте, dmz, Вы писали:
dmz>Слать это в сокет очень полезно, без сомнения. А вот сделаем реалистичное допущение относительно данной задачи в рамках ее предметной области (уж какая есть) — писать в каждый файл только уникальные строки (т.к. на кой черт писать дублирующие?)
dmz>решение на условном ФП: dmz>concrete_filter = unique . filter filt dmz>[/code]
NGG>Ну так если затем расписать все перечисленные в аргуметах интерфейсы классы, получится тоже самое количество кода что в обрисованном мной вараинте.
В джаве — да. За нее я и не говорю.
NGG>>>Если расписать всё это, получатся теже яйца, что и в оо варианте вид сбоку
Что в ФП варианте можно расписать? Приводился — ранее — вполне рабочий код.
NGG>СompositeGroup — сам алгоритм
Спорная вещь — засовывания алгоритма в класс, который выглядит как контейнерный...
NGG>Разве не яйца?
И как-то очень много.
NGG>Наверное, очевидным должно быть, что не только для раз и на всегда заданных условий, а для более широго круга задач NGG>Вот собственно поддтверждения этому я и хочу найти.
Ну какие нужны подтверждения? Когда меняется ситуация, редактировать ФП код как-то проще, поскольку его обычно меньше. Общие вещи, абстракции — выделяются и выносятся. Рассуждать 'в общем' мне тяжело — лучше на конкретных примерах. Вот есть у меня компилятор, который пережил несколько смен синтаксиса и еще переживет. Там нет ничего, что можно было бы унаследовать, и создать, например, новый компилятор путем наследования и подмешивания к существующему. Плохо ли это? Нет, это только хорошо.
NGG>А что он должен поддреживать? Только анонимные функции? Т.е. в C# уже на ура будет работать?
Ну вот, композицию функций, например. Алгебраические типы. Паттерн-матчинг.
dmz>> Ну вот пример — был у нас фильтр непустых строк, но, допустим, надо бы отсортировать комментарии и вообще — уметь наложить вместо одного фильтра N фильтров, но фильтры известны в компайл-тайме. Ну, в общем, вполне себе допущение, не хуже уже прочих.
NGG>Гхм. Это вообще-то называется AndFilter и его добавление не приводит к изменниям в коде. Тот самый OCP в действии
Его написать надо, или его можно сгенерировать из имеющихся фильтров? Или есть конструкция AndFilter<FilterA, FilterB, ...> которая его породит?
NGG>Реализовывать его, пока он не был нужен и было бы овердизайном и заточкой под изменения, которые никогда не случатся (в отличии от декларации интерфейсов).
Ну так impact, который получится при таком изменении требований — он в итоге разный в ФП и ООП?
NGG>Только цель предложенного дизайна была не показать как ооп крут, а фп гавно (такое ощущение, что многими, кто мне отвечал, оно воспринимается именно так). В том сообщении я задал вопрос про то, как выглядело бы решение в функциональном стиле будь это не задачка на две строчки, а "реальная" задача.
Как можно показать решение "не на две строчки" в двухстрочной задаче?
NGG>ОО-код служит примером того, как я ответил бы на этот вопрос задай мне его кто-нибудь. Просто иллюстрация, чтобы было понятно о чём я спрашиваю. NGG>Похоже канал коммуникации этим приёмом настроить не удалось
Ну, наверное, не лучший пример. Не знаю, где взять лучший. Попробую сформулировать свою позже.
NGG>Вот я сейчас в роли такого человека оказался. Перед глазами три "фреймоврка" для "легкого" построения гуя в одном приложение и все настолько безобразны (7+ лет приложению), что я плачу. Уже давно мечтаю всё выкинуть и написать своё, бо цена рефакторинга почти такая же, но если текущая задача стоит Х, переписать и выполнить текущую задачу "красиво" будет стоить 100*X, если не больше. Приходится закрывать глаза и получать удовльствие
Объем задачи другой. Но ведь тут уже ничего не поможет — ни фп, ни ооп.
NGG>Собственно эта ситуация отчасти поспособствовала тому, что я стал задавать тут глупые вопросы. Стало интересно, что было бы, пиши это приложение в течении 7 лет теже недалёкие люди, но только на функциональном языке. Больше гавна пришлось бы разбирать или меньше?
Все также зависит от человеческого фактора. ФП — очень мощный инструмент. В правильных руках — он послужит сокращению сроков и издержек. Но не в тех руках — оно будет только во вред. Преимущество ФП в том, что в нем есть встроенная защита от дурака. Недостаток ФП в том, что дурак, обошедший эту защиту — стоит сотни обычных по разрушительным последствиям.
Инструмент нужно выбирать по задаче. Для меня в моих условиях — ФП является более выгодным инструментом. Для кого-то — вероятно, нет.
Как мне кажется — ФЯ являются более мощными и более высокоуровневыми, по сравнению с распространенными обычными языками.
dmz>>решение на условном ФП: dmz>>concrete_filter = unique . filter filt dmz>>[/code]
NGG>Тоже самое на условной java:
Не говоря о том, что здесь всего больше, мне как-то неочевидно, как это должно использоваться.
Re[5]: Мастер-класс по ФП
От:
Аноним
Дата:
04.01.09 21:00
Оценка:
Здравствуйте, dmz, Вы писали:
dmz>Не говоря о том, что здесь всего больше, мне как-то неочевидно, как это должно использоваться.
вместо new FilterImp(...) ставится new UniqueFilter(new FilterImpl()) и используется. FilterImpl это реализация фильтра, который нужно сделать уникальным...
А>вместо new FilterImp(...) ставится new UniqueFilter(new FilterImpl()) и используется. FilterImpl это реализация фильтра, который нужно сделать уникальным...
Предложенный интерфейс фильтра подразумевает, что он применяется к одному элементу:
interface IFilter<T>
{
boolean match(T t);
}
и в реализации так и происходит. Уникальные элементы таким образом не отфильтруешь.
Здравствуйте, NotGonnaGetUs, Вы писали:
NGG>Использование функции c не безопасно — н-р, можно при правке кода поменять a на a', а про b забыть... NGG>Компилятор промолчит. Может быть даже тесты пройдут успешно, т.к. разница между b и b' крылась в каком-то редком случае почему-то не покрытому при тестировании. А в итоге приложение не отработает как следует в самый ответственный момент.
Ну и что тут необычного? Это постоянно происходит в любых языках и парадигмах -- ФП, очевидно, не является серебрянной пулей.
Конкретно с этой проблемой может быть могут немного уменьшить опасность зависимые типы, когда их сделают простыми для использования. И то не на 100%...
NGG>Возможно моя боязнь блуждающих по аргументам в свободном полёте связных функций это только от недостатка опыта в их готовке... NGG>Но пока мне кажется, что разумно было бы явно декларировать зависимость между аргументами: NGG>
NGG>Из декларации сразу видно что к чему. NGG>Разве нет?
Ну Вам же никто не запрещает так делать? Нужно -- так делайте! Все возможности для этого у Вас есть...
NGG>Гхм. Тут какое-то расхождение во взглядах на то, что такое монолитность NGG>Мне как раз твоё решение видится монолитным кусоком кода, а моё комбинируется из нескольких классов для полученя нужного результата и каждый из этих классов может жить счастливой самостоятельной жизнью.
Делайте решение в ФП-стиле -- то есть кучу маленьких функций, максимально обобщённых. И тогда останется просто комбинировать их в нужном порядке -- вот и не будет этой страшной монолитности...
Здравствуйте, BulatZiganshin, Вы писали: BZ>как-то всё это сложно
Ну я это и нарисовал. Только использовал списковые дополнения вместо map-ов
Вместо mapMaybe (stripPrefix (make dir)) выписал списковое доплнение через take и drop для случая непустого имени (с монадами пока торможу). mapSnd — тоже выписал явно.
По ходу есть ещё одно препятствие в изучении ФП, но оно довольно общее для любых языков — пока не очень свободно знаешь язык и его стандартные библиотеки, очень трудно распознать алгоритм в чужом коде.
И тем более предсказать трудоёмкость.
Например, решение через take и drop скорее всего проигрывает по сравнению с mapMaybe (stripPrefix (make dir)). По крайней мере в С/С++ я мог бы это отразить. Но как это в haskell-е я пока не в курсе.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>вот пример. представим классическую gui-библиотеку. реализация диалога настроек на ней может выглядеть так: BZ>1) создаём все необходимые controls BZ>2) заполняем их исходными данными BZ>3) отображаем диалог BZ>4) после нажатия Ok обновляем переменные
BZ>удобно ли это? на мой взгляд нет — нужно сгруппировать описание контрола, перевод данных в него и обратно. соответственно ФП-дизайн здесь состоит в создании высокоуровневых контролов, которые несут в себе не только свои данные, но и ассоциированные с ними действия. и тогда программа будет выглядеть так: BZ>
Кстати, вот животрепещущая тема (для меня), можете посоветовать что-нить в этом плане? Имею в виду сами принципы построения такого фреймворка применительно к Хаскеллу. Всякие там Model-View-Controller в функциональном стиле...
Здравствуйте, Tonal-, Вы писали:
T>По ходу есть ещё одно препятствие в изучении ФП, но оно довольно общее для любых языков — пока не очень свободно знаешь язык и его стандартные библиотеки, очень трудно распознать алгоритм в чужом коде.
С ФП с этим полегче по моему. Вот при изучении Smalltalk у человека знающего майнстримный ООП приключается когнитивный диссонанс
Для того, чтобы код был аналогичен, нужно однако чуть добавить:
сlass TaskNumberOne {
template <class Source, class Filter, class Group, class Consumer>
void process(Source inp, Filter filt, Group group_by, Consumer consume) {...}
Тогда мы можем воспользоваться "трудами" фильтра в группировке, только они должны имеь согласованный интерфейс.
При этом возникает ещё 2 типа — то что получилось после фильтрации и то, что получилось после группировки. Но если попытаться их здесь явно выписать, то получаются уже шаблоны шаблонов и сигнатура получается монстрообразная, а на Java или C# просто невыразимая...
Здравствуйте, NotGonnaGetUs, Вы писали:
NGG>Ну так я же просил показать как будет выглядеть решение "боевой" задачи, как если бы это было решение, которое ждёт большее будущее и долгая история развития NGG>У меня подозрение, что проделай вы всё это, вместо одной строчки было бы что-то похожее по количеству строчек на код VoidEх'a.
В таких проектах объём документации должен быть на порядок больше объёма кода, иначе проблемы будут всегда. И комментарии в коде должны быть обширными. И вапще Literate Programming тут уже напрашивается.
В итоге подходим к тому, что программа должны быть исполняемым руководством...