Evening, Andrei. Andrei Sosnin <[EMAIL PROTECTED]> 22:29 13/1/2003 wrote:
>> Да. Проблемы начинаются тогда, когда поведение addvaluesbyone для MyClass и >> ConcreteSuperclassOfMyClass - различно (такое очень часто пишут >> горе-програмисты при наследовании, т.е. реализуют в вирт. методе поведение, >> нарушающее семантику, заложенную в предка). Что приводит к трудноловимым >> ошибкам и костылям. AS> Если следовать нормальной логике, то ничего такого не будет. AS> Сомневаюсь, что программисты ФП намного сильнее защищены от таких AS> "дураков", бишь от глупых вещей. Здесь не спасет строгая типизация или AS> что-либо еще. В конце концов, тот же горе-программист может вместо А вот поди ж ты - спасает :) AS> направления строки на стандартный поток вывода (в С++ - cout) сделать AS> вывод на стандартный поток ошибок и потом долго чесать голову, почему AS> же у него не происходит кеширования вывода и в результате программа AS> работает в два раза медленнее, чем должна... Я говорю об ошибках менее тривиальных, возникающих, как правило, при доработке/переработке существующего кода, расширении ф-сти существующих (библиотечных) классов. Причем чаще всего такие ошибки делаются ненамерено. То, что я пытался проиллюстрировать примером, я считаю одним из самых больших идейных "пробоев" большинства реализаций парадигмы OOP - наследники не обязаны сохранять инвариант поведения предка. Очень часто допускаемый ляп выглядит так: у тебя есть (библиотечный) класс SortedList. Ты пишешь код, который полагается на то, что список сортированый. Потом ты наследуешь от SortedList какой-нибудь MySortedList, заменяя в нем, допустим, внутреннюю струкуру хранения данных со списка на список + avl-дерево. Ты переписываешь методы работы с данными, но не все. В результате у тебя получается класс, поведение которого относительно унаследованого виртуального метода, (например, next()) отличается от поведение предка. Чаще всего такое получается по недосмотру. Тем не менее, в большинстве (во всех?) реализаций OOP ты можешь сунуть MySortedList в любое место, где уместен SortedList. Поведение наследника отличается => отличается и поведение кода, который работает с ним. И разработчик собирается в очередной поход против ветряных мельниц.... С моей точки зрения, большинство т.н. design pattern из OOP являются борьбой этой и подобными "идеологическими недоработками" (см. например http://norvig.com/design-patterns/) В качестве иллюстрации, как может быть по-другому, пример из одного из ФЯ: описывается класс типов SortedList. Указывается, что произвольный _тип_ может рассматриваться как SortedList, если для него определены следующие операции: ... Если это возможно, ты можешь указывать реализации операций в терминах других операций из списка определенных для данного класса типов. Пример (класс типов, для которых определено понятие эквивалентности): class Eq a where (==), (/=) :: a -> a -> Bool -- Minimal complete definition: (==) or (/=) x == y = not (x/=y) x /= y = not (x==y) После этого я могу указать, как именно любой user-defined тип можно отнести к определенному классу типов. Для этого я даю определение операций (возможно, не всех, если часть из них выражается друг через друга): instance Eq MyType where a `==` b = myCompare a b определени для (/=) будет построено автоматически. Таким образом я группирую произвольные типы по их поведению. Классы можно организовывать в иерархии: class (Eq a) => Ord a where compare :: a -> a -> Ordering (<), (<=), (>=), (>) :: a -> a -> Bool max, min :: a -> a -> a -- Minimal complete definition: (<=) or compare -- using compare can be more efficient for complex types compare x y | x==y = EQ | x<=y = LT | otherwise = GT x <= y = compare x y /= GT x < y = compare x y == LT x >= y = compare x y /= LT x > y = compare x y == GT max x y | x <= y = y | otherwise = x min x y | x <= y = x | otherwise = y (т.е. над произвольным _типом_ "a" можно ввести отношение частичного порядка, если есть определение понятия эквивалентности над этим типом и определена операция <= или compare -- все остальные будут выведены из этого определения). После этого я могу писать код, который работает с данными любого типа, который может быть членом класса. Откуда взялся этот тип - мне не важно. Если мне потребуется использовать чужую библиотеку/код, то все, что мне надо будет сделать - указать, каким образом мои типы "укладываются" в поведение, требуемое библиотечным кодом. Мне не надо наследовать, переопределять, рефакторить ... AS> Также, если изменение семантики работы класса-родителя нарушает работу AS> программной системы, то, видимо, этот класс-родитель был плохо AS> написан. Хорошо написанный и продуманный класс-родитель не должен AS> допускать этого. Как класс-родитель может что-то не допускать? От него пронаследуются, перекроют его методы, а его и не спросят. [skip] >> Мне нужна композиция >> функций. Есть знакомство с математическим смыслом этого понятия? AS> Нет. Я уже на это обращал внимание. :-( "Я ведь еще только учусь!.." AS> (с) Шеф :-) А где, если не секрет (можно в привате)? AS> Но мне бы интересно было бы узнать. Есть ли _доступная_ информация в AS> онлайне на русском (английском) языке? (В популярной форме, на уровень AS> выпускника средней школы) Честно говоря, не скажу... Я с трудом представляю себе, что есть уровень выпускника средней школы. Скажу только, что материала (разного уровня сложности) в сети - хоть спину мой. Было бы желание и www.google.com. AS> Я влез в спор именно для того, чтобы понять, почему именно ФП тебе AS> показался лучше. Чем больше я спорил, тем больше я понимал, что это AS> далеко не зря, тем более что тебя стал кое в чем поддерживать V. AS> Wagner и другие, которые у меня уже отмечены как местные "гуру" и AS> интеллигенция, к которым стоит прислушиваться. Когда мне упомянули про AS> функционалы и когда я не поленился посмотреть, что такое ФП на самом AS> деле, мне стало еще интереснее. Я понимал, что мои примеры, возможно, AS> реализуют не то, что требовалось, но хотел это вытянуть у тебя. Не AS> получилось.... :-) AS> Может все-таки объяснишь, что такое функционал в математике? Как можно AS> возвращать функцию функцией? Где можно и можно ли найти информацию в AS> онлайне? Я бы не хотел заменять лектора курса по теории вычислений - это займет уйму времени :) Информацию в сети наверняка найти можно, но сайт, с которого ты скачаешь конспект лекций, врядли ответит на вопросы, которые у тебя будут возникать :) >> Мне нужен инструмент, который позволяет взять функцию string -> int >> (например, с семантикой "кол-во строк в файле с указаным именем"), функцию >> int -> string (например, с семантикой "число прописью"), сделать "compose >> spell_number count_lines" и получить сущность типа "функция из string -> >> string" с семантикой "число строк в файле с указаным именем прописью". >> Напомню, что все это - иллюстрация того, что такое "first-class funcitons". AS> Знаешь, я бы тоже мог бы попросить инструмент на языке ФП, который бы AS> реализовывал сущность трехмерного персонажа мультфильма с речевыми и AS> двигательными функциями, который должен включать сущности трехмерного AS> объекта, речевого синтезатора и объекта получения команд движений AS> через манипуляторы. Стоп. Отмотай тред. -Что такого есть в ФП, чего нет, к примеру, в ООП, что характерно для ФП? -Например, помимо всего прочего, first-class функции. -Что это? -Вот краткое описание, вот пример. -Это ерунда, так можно и в С/C++, вот пример. -Нет, эти примеры не равнозначны. -Ну, знаешь ли, я тоже могу сейчас придумать такой пример, что ты будешь год затылок чесать! Улавливаешь, к чему я? Я не хочу забить собеседника в угол хитрой задачкой, или что-то в этом роде. Я показываю, что существуют механизмы, которые удобны на практике (комбинирование функций с целью получения новых с задаными свойствами) и показываю, что, будучи естественными для одного языка/стиля програмирования, они в то же время с трудом могут быть реализованы (если могут быть реализованы вообще) средствами другого языка/стиля. Не я первый начал говорить "такое есть и в C++". AS> Если еще раз вернуться к изначальному вопросу, а именно (цитирую): AS> "Просто были продемонстрированы некие принципы, которые, по моему AS> мнению, делают ФЯ более предпочтительными средствами для AS> программирования." - я могу сказать что-то подобное: AS> Как показывает практика, введение массовой компьютерной индустрии AS> вынуждает все большее количество людей заниматься программированием AS> (вплоть до написания JavaScript). Часто эти люди либо плохо знакомы, AS> либо вообще незнакомы с тонкостями современной математики, поэтому AS> чисто математические методы программирования для них неприемлемы, ибо AS> они слишком сложны для них. Та математика, которая вспоминалась - ни разу не современная :) AS> На помощь им (и в пользу для общества в целом) приходит более простой "1000000 леммингов не ошибаются" - это не аргумент. (см. http://www.infidels.org/news/atheism/logic.html) AS> в понимании объектно-ориентированный метод программирования. Понимание AS> его главной концепции должно быть достаточно понятно - все, что нас AS> окружает, может быть представлено в виде классово-объектного понятия с AS> набором внутренных свойств и различного рода методов (в смысле - AS> функций/процедур). А мне не понятно. Я утверждаю, что модель "все есть объект. свойства объекта определяются его данными/поведением. любое действие есть поведение какого-то объекта. для решения задачи надо построить правильную систему объектов" проигрывает модели "известна цель и путь ее достижения. путь выражается в операциях над сущностями. Операции требуют наличия у сущностей определенного поведения. Любая сущность с правильным поведением может быть субъектом операции. для решения задачи надо промоделировать исходные данных в сущностях и описать операции". Мне кажется более очевидными подход "все. что имеет шестигранные выступы, можно с переменным успехом пытаться крутить с помощью гаечного ключа", чем "все, что может крутится от применения гаечного ключа, имеет в дальних родственниках гайку. В качестве побочного эффекта, оно может крутиться само, и вовсе без ключа. Более того, если хорошо поискать, обязательно где-то найдется резьба или ее рудименты, даже если она не нужна" AS> Отсюда можно утверждать также, что языки ООП все-таки предпочтительнее AS> для широкого круга пользователей. Отсюда можно утверждать все, что угодно, вплоть до наличия инопланетян. У тебя как минимум два сомнительных хода в цепочке доказательства (включая этот последний). AS> Замечю только, что с языками ФП я не сталкивался лично, но, AS> познакомившись с его "каймой" из математических премудростей из 3 AS> курса физмата (это идиома), вроде функционалов, я понял, что это не AS> для средних умов. То есть, не для широкого круга, а для специалистов. Твое утверждение подразумевает то, что для использования ФЯ необходимо знакомство с программой 3-го курса физмата. Это не так. AS> По-моему, достаточно наглядно выглядит интрукция объекту типа MickeyMouse: AS> Mickey.MoveUp(); Сходи в fido7.su.softw - там народ вторую неделю не может договориться, что более интуитивно - печка.жарить(картошка), картошка.жариться(печка), повар.жаритьВ(печка,картошка),рецепт.готовить(картошка.в(печка)), ... AS> Впрочем, не спорю, Mickey = MoveUp(Mickey) может также сойти, но это AS> уже немного более громоздко - два раза указан Mickey, что обычно людям AS> не нравится. Это ты вообще к чему говоришь? :) >> Елки же ж моталки. Ну что такого сложно в выражении "получить функцию z как >> результат композиции функций f и g, где g - .... (см. выше)"? Неужели я >> настолько путано все изложил? AS> Сложно для того, кто с таким никогда не сталкивался. Я кроме AS> императивных языков больше ничего-то и не видел поэтому понятия AS> композиции функций... В чем разница с простым возвращением значения AS> вторичной функции g(x) первичной функции f(g) в качестве аргумента? AS> Нам не дан x? 8- Да. Нам не дан х. Нам дано два поведения, мы хотим их скомбинировать. Получить в результате новое поведение и потом его использовать где не попадя. -- Dmitry Astapov //ADEpt E-mail: [EMAIL PROTECTED] GPG KeyID/fprint: F5D7639D/CA36 E6C4 815D 434D 0498 2B08 7867 4860 F5D7 639D