Зачем нужно функциональное программирование?

Dasar

Для изучения Лиспа нужно иметь довольно продвинутые мозги.
ps
Как ты думаешь, почему программистов на Cobol-е и VB-е больше всего?
И даже pascal-истов больше, чем лисповцев, не говоря уже о явистах и c-ишниках.
pps
На функциональных языках, вообще, большие программы можно написать? Воообще, пишут?
кроме банального примера emacs-а.

oleg_n

> На функциональных языках, вообще, большие программы можно написать? Воообще, пишут?
> кроме банального примера emacs-а.
Пишут. И защищают дисеры.
А то убожество с filter, которое ты смог написать на С, там выглядит очень естественно и понятно.
// shurick

Dasar

ИМХО, дисер - это маленькая программа.

Dasar

Мне, например, понятно, что на ФЯ легко пишутся вычисления.
Но вот как происходит работа с "реальными объектами" (окна, файлы, события, время и т.д. совершенно не понятно.

oleg_n

ФЯ позволяют легко достичь высокого уровня абстракции,
поэтому иногда действительно достаточно написать очень мало.
Но на тот же С это за#$ёшься переписывать.
// shurick

oleg_n

Я не считаю haskell "реальным" рабочим инструментом.
Я не считаю целесообразным его использование там,
где понятно что и как надо делать (в т.ч. "вычисления").
Но, тем не менее, он очень уместен для моделирования,
построения прототипов и разработки алгоритмов некоторых
типов. А также для обучения (насчёт школьников не знаю,
но для студентов - вполне).
//shurick

sergey_m

> На функциональных языках, вообще, большие программы можно написать? Воообще, пишут?
> кроме банального примера emacs-а.
Пишут. И защищают дисеры.
О! Именно, что защищают диссеры. А теперь покажи мне программный продукт платный или бесплатный на этих самых языках. Главное что бы продукт был используемый.

Marinavo_0507

Лично я только одну программу, которой я пользуюсь, написанную на культурном языке, сходу могу назвать: mldonkey.

sergey_m

А теперь покажи мне программный продукт платный или бесплатный на этих самых языках.
Рекомендую попрактиковаться с такой командой (под FreeBSD):
find /usr/ports -name Makefile | xargs grep -il token
где token это lang/ocaml, lang/scheme48 и т.п. Порты найденные в devel не считаем - это библиотеки и инструменты к этим языкам.

Marinavo_0507

"Миллионы мух не могут ошибаться" (с)

Aleksei66

Примерами програмных продуктов пока в основном служат компиляторы/интерпретаторы этих языков. Индустрия программирования игнорирует ФЯ по понятным причинам, в них некому вложить бабки для раскрутки.

Marinavo_0507

> в них некому вложить бабки для раскрутки.
а как там M$ кстати?

sergey_m

"Миллионы мух не могут ошибаться" (с)

Я не сказал "где большие корпорации пишущие софт на Lisp или OCaml?". Я не сказал "где сотни девелоперов?". Я сказал "где продукты?", пускай они будут написаны одни человеком. Я не вижу ничего кроме диссертаций.

Marinavo_0507

Продуктов мало.
Интересуются немодными языками в основном люди с научным складом ума, им дисеры интереснее.
"Продукт" одним человеком трудно сделать, как правило в таких случаях получается что-то,
что только автор может использовать.
Для продукта нужно в команде работать - соотвественно чем немоднее язык, тем людей меньше.
В Open Source совсем плохо с этим - ведь не ты ищешь помошников, а они тебя.
На ocaml есть несколько используемых программ, по-видимому это связано с тем,
что в некоторых французских ВУЗах заставляют его учить.

Dasar

> програмных продуктов пока в основном служат компиляторы/интерпретаторы
Что значит "пока"?
ФЯ одна из самых первых парадигм, тому же Лиспу лет, наверное, больше, чем языку С, а реальных программ, кроме того же emacs-а - так и не видно.
имхо, ФЯ удобно применять для генерации программ, но не для самих программ.
Т.к. фя очень тяжело ложится на mutable-объекты, на объекты-имеющие состояния и т.д.
Всякие преобразования/трансформации данных очень легко пишутся на ФЯ, но архитектура/структура программы на ФЯ пишется отвратно. Может быть имеет смысл связка UML + фя, где на выходе у UML-я некие объекты с которыми умеет работать уже ФЯ

Marinavo_0507

> Т.к. фя очень тяжело ложится на mutable-объекты, на объекты-имеющие состояния и т.д.
Это относится только к чистым языкам, из которых здесь упоминался только Haskell.

Dasar

"Нечистые" - это какие? И что они умеют?
По хорошему, нужна следующая связка:
1. сначала описываем объекты (что они из себя представляют, какие взаимосвязи между объектами есть и т.д.) - реального языка-кандидата на такое описание сейчас нет
2. На ФЯ описываем преобразования/трансформации данных
3. С помощью императивного языка все это связываем вместе.
Обращаю внимание, что именно императивный язык является связкой, т.к на нем проще писать сложные задачи.

Aleksei66

Ну и что? ФЯ плохо ложаться на архитектуру современных компьютеров. Т.е. по сравнению с языками того времени они существенно проигрывали в скорости выполнения. К тому же, были интерпретируемыми. И основные силы, насколько я понимаю, уходили на разработку функционального процессора, а не на оптимизацию алгоритмов компиляции и развитие языков. ML, Haskell, OCaml (Caml) - все они были созданы в 80-е или позже, когда С уже всех зарулил.
Это сейчас императивные языки успешно борются за звание самых тормозных, а тогда все было иначе.
Архитектура и структура пишутся замечательно, просто думать надо по другому.

Marinavo_0507

> "Нечистые" - это какие? И что они умеют?
Lisp, Ocaml, Perl, Python - мультипарадигмальные языки:
поддерживают процедурное, функциональное программирование, ОО
Умеют соотв. всё что обычно нужно в рамках этих парадигм.
> 1. сначала описываем объекты (что они из себя представляют, какие взаимосвязи между объектами есть и т.д.)
Это относится к представлению знаний о предметной области скорее, а не к программированию.
> 2. На ФЯ описываем преобразования/трансформации данных
> 3. С помощью императивного языка все это связываем вместе.
Для бухгалтерии всякой, про которую тут в основном говорят, так и надо наверное.
Если например у нас событийно-ориентированная система, то этой обвязки будет - один event loop фактически.

Aleksei66

Нечистые - это те, которые содержат нефункциональные фичи. Т.е. переменные в понимании ИЯ (в ФЯ переменных нет вообще, строго говоря исключения, нефункциональные функции типа ввода-вывода, короче все, что может дать косвенные эффекты при выполнении.

Dasar

Возьмем стандартную задачу про чайник, который надо поставить на огонь. Как этот алгоритм будет записываться на ФЯ?

Aleksei66

Напиши его на ИЯ, чтобы я понял, что ты имеешь ввиду.

Dasar

> Lisp, Ocaml, Perl, Python - мультипарадигмальные языки:
> поддерживают процедурное, функциональное программирование, ОО
C++ тоже поддерживает функциональное программирование, но это не значит, что на нем можно эффективно писать используя ФЯ подход. Постоянно приходится обходить кучу грабель, которые разбросаны тут, и там.
Приведи, плиз, пример ОО на ФЯ, только лучше какой-нибудь красивый, чтобы в нем было проще разобраться.
> Это относится к представлению знаний о предметной области скорее, а не к программированию.
Согласен. Но ведь программа должна знать то, с чем она работает. Причем для эффективной работы должна знать как можно больше.
> Для бухгалтерии всякой, про которую тут в основном говорят, так и надо наверное.
> Если например у нас событийно-ориентированная система, то этой обвязки будет - один event loop фактически.
Чем бухгалтерия отличается от событийно-ориентированный системы?

Dasar

СделатьЧай
{
ВзятьЧайник;
НалитьВодуВЧайник;
ПоставитьЧайникНаПлиту:
ВключитьОгонь;
ДождатьсяЗакипания;
ЗасыпатьВКружкуВодуЧайиСахарПоВкусу;
}

Marinavo_0507

> Приведи, плиз, пример ОО на ФЯ, только лучше какой-нибудь красивый, чтобы в нем было проще разобраться.
Я в ОО не рюхаю, но в OCaml говорят очень хорошее объектное расширение.
Отзывы примерно такие: этими объектами реально удобно пользоваться (имеется ввиду в отличии от яв и плюсов
но типа если язык изучить получше, окажется, что не так уж они и нужны, типа с модулями и функторами проще получается.
Примера кода не могу привести.
> Чем бухгалтерия отличается от событийно-ориентированный системы?
Не отличается
Об том и речь.

Marinavo_0507

Хуйовый у тебя алгоритм, никакой обратной связи.
Представь, что он роботом управляет, он же всю комнату порушит или сожжёт

hoha32

каждую строчку записать в виде "ОноЕсть?ДелатьТо-То:Выход"

Dasar

Еще один серьезный минус, сложный код на ФЯ нечитаем, что является серьезным препятствием при исправлениях, поисках ошибки.
Т.к. есть много разбросанных правил. И понять какое из них срабатывает в какой момент почти не реально для большой системы.
Еще как-то правильно заметили, что при добавление каждого нового правила надо перетестировать поведение всей программы, т.к. нельзя гарантировать, что добавление даже самого незначительного правила не убило все системы.

Dasar

Как правильно заметил за каждой строчкой скрывается проверка предусловия и само выполнение действия.

Marinavo_0507

> Т.к. есть много разбросанных правил. И понять какое из них срабатывает в какой момент почти не реально для большой системы.
Ты уверен, что ни с чем не путаешь?
Правила - скорее в логическом программировании.

Aleksei66

>Т.к. есть много разбросанных правил. И понять какое из них срабатывает в какой момент почти не реально для большой системы.
Абсолютно неверное утверждение. Все ошибки в типизированном ФЯ носят логический характер. Если есть ошибка, значит ты где-то напутал с логикой программы. Поэтому искать их гораздо проще, чем в С++, скажем. Это я говорю из своего опыта.
Еще большое количество ошибок отлавливается за счет строгого контроля типов. + ошибки обычно генерируют исключения из-за неправильного pattern matching.
+ ФЯ, даже нечистые, очень неприветствуют side effects. Это к вопросу о "нельзя гарантировать, что добавление даже самого незначительного правила не убило все системы". Для ФЯ это неверно, поскольку подавляющее большинство функций не имеют стронних эффектов в принципе.

Dasar

> Ты уверен, что ни с чем не путаешь?
Вроде, нет.
Сначала мы описываем функции - фактически правила преобразования причем компьютер(компилятор) выбирает наиболее подходящий вариант, а также выбирает порядок выполнения
Добавление или изменение одного из базовых правил (например, по ошибке добавление стороннего эффекта) приводит к очень интересным последствиям.

Dasar

Код без сторонних эффектов - фактически, это только вычисления.
Любое же взаимодействие с внешним миром (с другими программами, компонентами, пользователем, ОС, железом и т.д.) - это уже сторонние эффекты.

Aleksei66



fun get_kettle = if kettle exists then Some kettle else None;
fun fill_kettle kettle = if water exists then Some (fill kettle) else None;
fun na_plitu kettle = if plita exists then Some (put kettle) else None;
....
val funcs = [fill_kettle, na_plitu, fire_it, wait_for_boil, do_other_shit];
fun evaluate list expr = match (expr,list) with
(Some e, h::t) => evaluate t (h e)
| (Some e, nill) => 1;
| (None, _) => 0;
fun main = let kettle = get_kettle in
if (evalute funcs kettle) then print "success" else print "zopa";


Это без исключений. С исключениями, соответственно, было проще.

Chupa

> fun evaluate list expr =
а для кого всякие fold написали?

Marinavo_0507

Такой алгоритм проще записать на императивном языке.
Даже на чисто функциональном языке программа будет императивной (как это делается, я не в курсе,
есть какая-то магия для этого).
Теперь рассмотрим более реалистичный вариант - управление роботом, с обратной связью в полный рост.
Задачу управляющей программы можно сформулировать в терминах
преобразования потока сигналов от датчиков в поток команд для манипуляторов.
Получается уже чистая функция, которую вполне нормально будет записать даже на чистом ФЯ.
Добавляешь императивный event loop - активная сущность, которая будет вытягивать из выходного потока
команды и вставлять во входной поток сигналы.
Этот цикл удобно записать на императивном языке, но на самом деле пофиг, так как он маленький.

Dasar

> Абсолютно неверное утверждение. Все ошибки в типизированном ФЯ носят логический характер. Если есть ошибка, значит ты где-то напутал с логикой программы. Поэтому искать их гораздо проще, чем в С++, скажем. Это я говорю из своего опыта.
При написании C++-шаблонов очень часто используется ФЯ. Взять тот же STL, там активно используется ФЯ-подход.
Опыт показывает, что программисты среднего уровня очень тяжело находят ошибки, даже если ФЯ использовался только в библиотеках, а им надо было только эти библиотеки поиспользовать.
Если же им надо самим что-то изобразить в этом стиле, то там, вообще, полные кранты.

Aleksei66

Сначала мы описываем функции - фактически правила преобразования причем компьютер(компилятор) выбирает наиболее подходящий вариант, а также выбирает порядок выполнения

Ты путаешь что-то. В ФЯ компилятор ничего не выбирает, все детерминировано. Ты заранее знаешь, что и в каком порядке будет выполняться.
При перемене функций поведение программы действительно может измениться, но это экзотика и происходит это только потому, что в ФЯ можно использовать имена для функций и переменных сколько угодно раз и при изменении положения функции в файле некоторые нужные ей функции и переменные могли поменять значение. Но это очень маловероятная ошибка.

Marinavo_0507

> причем компьютер(компилятор) выбирает наиболее подходящий вариант
вот про это я не понял
маза тебя кто-то обманул
соответственно, разбрасывать функции по всей программе тоже незачем,
для этого придумали например модули
порядок вычислений выбирается автоматически только в ленивых языках, опять же *ML к ним не относятся
результат чистых функций не зависит от порядка вычислений по определению, для императивных участков
есть специальные конструкции, позволяющие управлять порядком появления побочных эффектов (это уже не ко мне, я не умею)

Dasar

> управление роботом, с обратной связью в полный рост.
Управление или пониманием того, что надо сделать дальше?
Фактически - же задача состоит из двух задач: анализ ситуации, и выполнение на основе этого анализа каких-то действий.
Если анализ - это, конечно, в большей степени - ФЯ, то выполение - это уже скорее ИЯ.

Chupa

> как это делается, я не в курсе, есть какая-то магия для этого
Эта магия - монады.
Она позволяет строить композицию state transformer'ов,
которую исполнитель (интерпретатор/кусок скомпилированного кода)
может применять к соответствующему объекту (например, к файлу).

Ivan8209

> сложный код на ФЯ нечитаем
Допиши: "написаннный плохим программистом."
Это такая же сказка, как и нечитаемый код на Форте.
Я сравнивал гнутый код, на сях, и код на Форте.
Последний куда читаемее.
На ФЯ он получился бы не менее читаемым, чем на Форте.
Не рассказывай сказки.
---
...Я работаю антинаучным аферистом...

Marinavo_0507

> то выполение - это уже скорее ИЯ.
согласен
но это уже уровень драйвера устройства
за исключением маленького event loop, который пофиг на чём написан

Dasar

Как быть, если нам необходимо передать какие-то данные из первой функции в последующую?

Ivan8209

Emacs, Enlightment, GIMP, Reduce, AutoCAD.
---
...Я работаю антинаучным аферистом...

Dasar

> Допиши: "написаннный плохим программистом."
В природе, идеальные программисты не встречаются. Идеальные программисты - пишут диссертации, на симпозиумы ездят, науку толкают, но реальные продукты не пишут.
Смысл от языка, если он применим только сферическим программистом в вакууме?

ma3yp

> В природе, идеальные программисты не встречаются.
Рассмотрим сферического программиста в вакууме...

Aleksei66

Так я уже передаю данные - kettle. Можешь считать, что это что угодно.

Ivan8209

Сможешь объяснить, почему у МО С.-А. С. Ш. для встроенных СРВ есть только два стандартных языка: Ада и Лисп?
---
...Я работаю антинаучным аферистом...

Dasar

скорее всего издержки бюрократии, тем более АДА-у они сами и разрабатывали.

Dasar

Кто будет контролировать процесс "запаковки"/"распаковки" данных в/из kettle?
Сам программист?

Chupa

> При написании C++-шаблонов очень часто используется ФЯ.
Скорее так:
"Для реализации абстракций из ФП в C++ приходится использовать шаблоны."
Получается очень хреново, но другого способа, по всей видимости, нет.
В результате "программистам среднего уровня" достаётся тяжело читаемый
и понимаемый код, причём представляющий неизвестную парадигму программирования.
Хотя если бы они были знакомы с ФП (хотя бы на основе "игрушечного" языка
то использовать эти шаблоны им бы стало намного проще (обращаю внимание,
что требуется только понимание основ ФП, а не реализация проекта на ФЯ).

Ivan8209

Только через вовзрат значения.
---
...Я работаю антинаучным аферистом...

Ivan8209

Любой язык влияет на мышление.
Не слышал об этом?
У любого языка есть стилистические правила, даже правила оформления.
Можешь посмотреть по сети.
---
Real FORTRAN Programmer can program FORTRAN in _any_ language.

Ivan8209

Описание CommonLISP доступно.
Можешь пойти и почитать.
Сравни с сями.
Это не просто так, могу тебе сказать.
"Издержки бюрократии" --- это сказки.
---
...Я работаю антинаучным аферистом...

Chupa

>> Допиши: "написаннный плохим программистом."
> В природе, идеальные программисты не встречаются.
> Идеальные программисты - пишут диссертации, на симпозиумы ездят,
> науку толкают, но реальные продукты не пишут.
>
> Смысл от языка, если он применим только сферическим программистом в вакууме?
По твоему программирование - это только то, что делают плохо обученные обезьянки?
PS А так любимый этими обезьянками M$ по-прежнему вкладывает бабло в ФП.

sergey_m

Emacs
Да? А я вижу C: http://savannah.gnu.org/cgi-bin/viewcvs/emacs/emacs/src/
Enlightment
Если имеется в виду http://www.enlightenment.org, то смотрим http://cvs.sourceforge.net/viewcvs.py/enlightenment. Видим C.
GIMP
Лень ссылку искать. Он тоже написан на C/C++.
Reduce
Что это? Можно сразу привести ссылку на исходники на ФЯ.
AutoCAD
Разве про его исходники что-то известно?

Marinavo_0507

> Да? А я вижу C
Как бы некоторые считают грамотным подходом в сложных проектах использовать несколько языков.
Мол, говорят, для разных подзадач подходят разные парадигмы.

Ivan8209

Ты компиляторы и интерпретаторы выкинь, ты же не считаешь их продуктами.
То, что останется,--- это Лисп или Схема.
У Reduce код был всегда закрыт, насколько помню.
---
...Я работаю антинаучным аферистом...

Dasar

> По твоему программирование - это только то, что делают плохо обученные обезьянки?
Нет, я хочу сказать другое: язык программирование должен облегчать написание программ, а не усложнять.
Язык (подход) должен максимально легко стыковаться с MainStream-ом, чтобы можно было не изобретать велосипед.
На данный момент, я такой стыковки не вижу.
> PS А так любимый этими обезьянками M$ по-прежнему вкладывает бабло в ФП.
MS много куда сейчас вкладывает деньги, у MS довольно серьезный отдел Research-а, но при этом далеко не все разработки research-а реально используются.

Ivan8209

LISP is in Main Stream since 1961.
---
...Я работаю антинаучным аферистом...

Dasar

Свидетельств данного факта не видно.
Я еще могу согласится, что в 1961 году Lisp был MainStream-ом, т.к. многие надеялись, что Lisp поможет быстро и просто разработать экспертные базы.
Почему ты считаешь, что Lisp до сих пор является Main stream-ом?

Marinavo_0507

MainStream - это бухгалтерия?
Тогда наверное Lisp туда не относится, пожалуй.
Хотя отдельные Success Stories и в этой области есть: http://www.paulgraham.com/avg.html

Marinavo_0507

> Язык (подход) должен максимально легко стыковаться с MainStream-ом, чтобы можно было не изобретать велосипед.
Не понимаю слова "стыковаться".
Например, для системной программы самое важное от языка - насколько легко делать системные вызовы
и другие низкоуровневые операции. Вот и вся стыковка.
Если с этим всё нормально, то уже довольно легко оценить, подходит ли язык для задачи.

Dasar

В данном случае, Main Stream - это средства разработки, которые используется для решения большинства задач, и поэтому именно для этих средств разработки, можно легко найти библиотеки, модули, подходы, методологии, патерны и т.д.
Допустим я пишу программу. В любой большой программе мне скорее всего захочется:
посохранять данные между перезапусками,
поработать со стандартными форматами данных,
пообщаться с пользователем (вывести какие-то данные пользователю, ввести данные от пользователя
пообщаться с другими готовыми программами.
Может захотеться, что-то более специфичное:
серверное решение (работа с несколькими пользователями, разделение прав доступа, тонкий клиент и т.д. работа в качестве компонента для более большой системы,
возможность частичной автоматизии программы пользователем (поддержка скриптов
возможность расширения программы пользователем (плагины).
MainStream-овые средства разработки гарантирует, что все эти задачи уже худобедно решенны, и может даже доступные какие-то готовые компоненты, или хотя бы просто советы, как лучше решать все вышеперечисленные задачи.
Насколько все вышеперечисленные задачи решены в рамках того же лиспа?
За С/C++, VB, Java, Delphi, C# я могу четко сказать, что да - все вышеперечисленные задачи уже решены.

Chupa

Там хорошая цитата из Raymond'а есть:
Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot.
Как раз ответ на вопрос зачем изучать, если нет возможности применить в явном виде.

Dasar

> Например, для системной программы самое важное от языка
имхо, на данный момент стоит говорит только о прикладных задачах, т.к. с каждым днем с развитием железа все больше системных задач переходят в разряд прикладных.
Возмем банальное общение программы с какой-то внешней железкой: если раньше безусловно было необходимо писать системную программу, которая, напрямую, работала с портами и должна была укладывать в жесткие временные рамки.
Сейчас же все проще: системный уровень уже обычно давно до нас написан, а именно написан транспортный (канальный) уровень. На нашу же долю остается банальное формирование посылаемых данных, и разбор принятых данных, которые делается непосредственно на прикладном уровне.
> Не понимаю слова "стыковаться".
Это значит уметь подсоединять библиотеки, модули, готовые программы, идеи, которые разработаны в рамках mainstream-а

Marinavo_0507

> В любой большой программе мне скорее всего захочется
Маза не в любой. Похоже, ты только о своей конкретной области думаешь.
И область эта - бухгалтерия (у тебя все примеры оттуда).
И правильнее говорить не о программе, а о какой-то системе или решении.
Отличия:
- Сразу же становится ясно, что разные компоненты могут быть на разных языках
- Часть компонентов может быть уже сделаны.
Теперь моё отношение к этим вещам:
Я ни разу не профессиональный разработчик, и не собираюсь им становиться,
программирую, когда есть конкретная задача.
Если можно решить без программирования - тем лучше.
Предположим, нельзя.
Тогда нужно решить, как проще сделать то, что нужно.
Какой-нибудь опытный разработчик и с неудобным языком управится,
а я без удобного инструмента не обойдусь, не получится просто.
И получившееся скорее всего не будет продуктом - нафиг надо?

Marinavo_0507

Под словом "системные программы" я понимал более широкий класс,
нежели ядро ОС и драйвера устройств.
И вообще, какое-то у тебя странное представление об этих делах,
думаешь, сейчас драйверов, напрямую работающих с портами, уже не делают?
Вот пример, уже более близкий к бухгалтерии, роутер с учётом трафика.
В целом, система сложная, а собственно программировать надо немного.
Вот и использование готовых библиотек, идей, компонентов!
Но среди того, что нужно дописывать, есть и системные части, и прикладные.

Dasar

> MainStream - это бухгалтерия?
Если же говорить за mainStream-овские задачи, то на данный момент mainstream-ом является не бухгалтерия, а более широкий класс задач: автоматизация (вернее сопровождение) повседневных задач, стоящих перед людьми.
Возьмем произвольного человека и понаблюдаем немного за ним:
1. Человек проснулся по будильнику (О! будильник. это можно автоматизировать: автоматизировать поведение будильника от ситуации: будни, выходные, праздник, бюлетень, равно встать - встретить поезд, у членов семьи разное расписание - один встает в 9, другой в 10 и т.д.)
2. Сделал зарядку (это тоже можно автоматизировать: формирование программы упражнений, отслеживание статистики самочувствия и т.д.)
3. Едит на работу (подсказка эффективного маршрута, оповещения о пробках, ремонтах, гаишниках и т.д.)
4. Формирование дел на сегодня (это - банально)
5. Общение с заказчиками, клиентами, покупателями (ведение картотеки по данным людям, ведение картотеки по проектам)
6. Написал пару бумажек начальнику/подчиненным (документооборот)
7. Получил зарплату (наша любимая бухгалтерея)
8. Поехал в магазин за покупками (картотека продуктов, оптимизация выбора и т.д.)
9. Приготовил ужин (картотека блюд, помощь в приготовлении блюд, помощь в покупке продуктов)
10. Досуг (картотека культурных развлечений, фильмов, книг и т.д.)
Все эти задачи построены одиннаковым образом, но при этом каждая имеет свои особенности. При чем этих задач не то, что много, а очень много. По этому на обширном фоне этих задач, все остальные задачи: системые, вычислительные и т.д., выглядят, как капля в море.
Возьмем все имеющиеся ресурсы в сети:
1. lorien.local - картотека (база знаний) о файлах в сети
2. z80 - картотека (база знаний) о фильмах в сети
3. forum - картотека (база знаний) нашего общения, наших мыслей
4. vnk.local - картотека (база знаний) о сотовой связи
5. Биллинги - картотека (база знаний) о сеансах связи с инетом
и т.д.
Все эти задачи объединяет следующие: есть некие данные, эти данные хранятся, структурируются (для этого, например, на форуме модераторов даже заводят живут своей жизнью (меняются, устаревают, преобразуются по этим данным собирается статистика, формируется советы по оптимальному использованию (например, слово (new) рядом с тредом подсказывает о том, что в данный тред стоит зайти учитываются требования пользователя (банальное изменение внешнего вида) и т.д.
Во всех этих задачах, я не вижу применимость ФЯ в качестве основного средства программирования.
Да, его можно использовать по чуть-чуть, то здесь, то там, но не более.

Chupa

> Во всех этих задачах, я не вижу применимость
> ФЯ в качестве основного средства программирования.
Просто инертность мышления.
>Возьмем все имеющиеся ресурсы в сети:
> и т.д.
Новый switchmap написан на ocaml.
В нём мне удобнее работать с деревом.

Dasar

> думаешь, сейчас драйверов, напрямую работающих с портами, уже не делают?
зачем это взаимодействие делать на системном уровне, если проще сделать на прикладном? Открыл tcp/ip соединие и вперед общайся по самое не хочу.

Dasar

> Новый switchmap написан на ocaml.
Стыковка с остальными частями программы идет через файлы, или напрямую?

Marinavo_0507

> Во всех этих задачах, я не вижу применимость ФЯ в качестве основного средства программирования.
А если я вижу, в некоторых?
А применимость функционального стиля в качестве основного, при использовании
мультипарадигмальных языков - так совсем хорошо вижу.

Chupa

Что такое "остальные части программы"?

Dasar

> А если я вижу, в некоторых?
Например?
> А применимость функционального стиля в качестве основного, при использовании
мультипарадигмальных языков - так совсем хорошо вижу.
В качестве основного не получится, т.к. event loop все равно внешний

Marinavo_0507

> зачем это взаимодействие делать на системном уровне, если проще сделать на прикладном?
> Открыл tcp/ip соединие и вперед общайся по самое не хочу.
С PCI-картой ты будешь по TCP/IP общаться? LOL

Marinavo_0507

> Например?
Форум, файлоискалка, биллинг - то, про что я немного знаю.
> В качестве основного не получится, т.к. event loop все равно внешний.
Я под словом "основное средство" понимаю то, что используется для большей
части содержательного кода, не относящегося к категории готовых библиотек и компонентов.
Например, в случае форума сейчас это именно скрипты на PHP,
а вовсе не ядро Linux и не apache (хотя event-loop-ы все там)

Dasar

Последнее время почти все расширения подключают, или через USB или через FireWire.
Встроенные решения уже намного реже делают.
зы
вот, например, в ряде промышленных компьютеров, в качестве шины используют gigabit ethernet, в которую втыкаются отдельные части компьютера

Marinavo_0507

> вот, например, в ряде промышленных компьютеров, в качестве шины
> используют gigabit ethernet, в которую втыкаются отдельные части компьютера
это всё хорошо и прогрессивно в некоторых случаях
я на самом деле очень рад таким тенденциям
ссылку можешь дать?
но для гигабитных карт нужен драйвер
и для гигабитного свитча нужно firmware
и рост скорости железа ничего не решает, так как так же
растут и требования к скорости передачи
и модификации TCP/IP (как протокола, так и реализации)
нужны при росте скоростей

Dasar

> Я под словом "основное средство" понимаю то, что используется для большей
части содержательного кода, не относящегося к категории готовых библиотек и компонентов.
Тогда уж больше будет декларативного кода. Кода, который описывает данные, их взаимосвязи, ограничения и т.д.
Тот же sort, поиск и т.д. пишется только один раз.
Если немного помечтать о будущем, то в идеале будет следующее:
1. Декларативное описание данных
2. Логические правила преобразования данных
3. Немного ФЯ в качесте подсказки компьютеру для тех случаев, где он не смог сам справиться.
но, имхо, ФЯ в том виде, в котором оно сейчас почти непригодно в вышеперечисленных задачах.

Dasar

> Что такое "остальные части программы"?
Например, пользовательский интерфейс.

Marinavo_0507

> Тогда уж больше будет декларативного кода. Кода, который описывает данные, их взаимосвязи, ограничения и т.д.
не вижу в этом проблем для использования ФП
> но, имхо, ФЯ в том виде, в котором оно сейчас почти непригодно в вышеперечисленных задачах.
Как мы выяснили, у тебя весьма странные представления о функциональном программировании,
и о языках.
Может быть, пока не время столь категорично выражаться?

Chupa

Взаимодействие с graphviz для рисования картинки через файлы, разумеется.
Это самое простое решение и я пока не вижу причин здесь что-то менять.
Остальные части пользовательского интерфейса, например, статус свитча
и подключенных к нему компов или поиск пути между компами,
сделаны на ocaml целиком.

Dasar

> Как мы выяснили, у тебя весьма странные представления о функциональном программировании,
и о языках.
> Может быть, пока не время столь категорично выражаться?
У меня о ФЯ до этого треда было чуть идеализированное представление, мне казалось, что в ФЯ намного больше используется декларативный подхода, чем в ИЯ.
На практике оказалось, что в ФЯ используется только одно единственное логическое правило - это то, что рекурсию можно перевести в цикл.
но, имхо, как раз это отличие не очень важно.
Намного интереснее следующие вещи:
например:
sort(items) преобразуется в qsort(items)
sort({i}) преобразуется в {i}
sort({i, j}) преобразуется в if (i < j) return {i, j}; else return {j, i};
sort(items, desc)[0] преобразуется в max(items)
и т.д.
Декларативный подход (в частности, логическое программирование) как раз может все это обеспечить.
А ФЯ, насколько я понял, все это обеспечить не может. увы...

Ivan8209

Почему же тогда электронщики не любят TCP?
---
...Я работаю антинаучным аферистом...

Ivan8209

> 1. Человек проснулся по будильнику
Событийное программирование.
Появилось в Лиспе.
> формирование программы упражнений, отслеживание самочувствия и т.д.)
Экспертная (маленькая такая) система?
Появилось в Лиспе.
> 3. Едит на работу (подсказка эффективного маршрута,
> оповещения о пробках, ремонтах, гаишниках и т.д.)
Поиск в сетях, расписание маршрутов.
Тоже Лисп.
> 4. Формирование дел на сегодня (это - банально)
E-Lisp.
> 5. Общение с заказчиками, клиентами, покупателями
> (ведение картотеки по данным людям, ведение картотеки по проектам)
Легко.
> 6. Написал пару бумажек начальнику/подчиненным (документооборот)
Emacs
> 7. Получил зарплату (наша любимая бухгалтерея)
Это что подразумевается?
> 8. Поехал в магазин за покупками (картотека продуктов,
> оптимизация выбора и т.д.)
Планирование тоже появилось в Лиспе.
> 9. Приготовил ужин (картотека блюд, помощь в приготовлении блюд,
> помощь в покупке продуктов)
То же.
> 10. Досуг (картотека культурных развлечений, фильмов, книг и т.д.)
Базу данных сделать не вопрос.
> 5. Биллинги - картотека (база знаний) о сеансах связи с инетом
и т.д.
К Полу Грахаму.
> Во всех этих задачах, я не вижу применимость ФЯ
> в качестве основного средства программирования.
Тем не менее все эти задачи исконно решаются на Лиспе.
Учи матчасть.
---
...Я работаю антинаучным аферистом...

Chupa

> sort(items) преобразуется в qsort(items)
> sort({i}) преобразуется в {i}
> sort({i, j}) преобразуется в if (i < j) return {i, j}; else return {j, i};
В чём проблема-то?
Берёшь и декларируешь.


sort :: Ord a => [a] -> [a]
sort (i:[]) = [i]
sort (i:j:[]) = if i<j then [i,j] else [j,i]
sort a = qsort a

Ivan8209

Ты запиши это на каком-нибудь ФЯ и увидишь, что записано точно так же,
только по-аглицки или со скобками.
В некоторых ФЯ, кстати, есть ленивые вычисления сразу.
В других ФЯ их можно сделать.
---
...Я работаю антинаучным аферистом...

Dasar

Вот это уже другое дело. спасибо. ps: Значит меня все-таки сбили слова -а.
А трансляторы из ФЯ в ИЯ есть? Например, для Java-ы?

Dasar

> Берёшь и декларируешь.
> sort (i:[]) =
сложные условия декларировать можно?
например, что-то такое:
sort (items where items.Length > 1000000) сортироватьСлиянием(items)

Ivan8209

Есть компиляторы Лиспа и МЛ в Си.
Вроде, видел упоминание и о "Яве."
"Яву," вообще-то не стоит рассматривать --- ВМ нафиг ненужна.
---
...Я работаю антинаучным аферистом...

Ivan8209

Использовать if.
Это не условия, как ты думаешь, а сопоставление с образцом.
---
...Я работаю антинаучным аферистом...

Chupa

> "Яву," вообще-то не стоит рассматривать --- ВМ нафиг ненужна.
У связки фп+ява могут быть свои достаточно интересные применения.
Например, можно попытаться сгенерить эффективный генератор
компилятора произвольного языка в яву по интерпретатору этого языка,
написанному на яве, то есть, фактически, по спецификации.
Для этого нужно написать на яве самоприменимый специализатор явы
(что весьма сложно) или написать его на ФЯ и скомпилить в яву
(это тоже сложно, но всё же значительно проще а потом
дважды применить его к себе (3я проекция Футамуры-Турчина).
С лиспом и рефалом какие-то успехи в этой области уже были,
явой несколько лет назад занимались, а вот с C такое сделать не получится.
Кстати, MS вроде чем-то таким тоже интересовалась,
а может уже и использует во всю.

Ivan8209

> самоприменимый специализатор явы
Можно по-русски?
"Ява" на "Яве," что ли?
Да и причём здесь "Ява?"
Любая ВМ подойдёт, как я понимаю.
---
...Я работаю антинаучным аферистом...

Chupa

>> самоприменимый специализатор явы
> Можно по-русски?
> "Ява" на "Яве," что ли?
На входе программа на J и некоторые её входные данные,
на выходе - программа на J, уже использующая эти данные.
Причём, реализовано всё тоже на J, и эту реализацию
можно подсунуть на вход программы.
> Да и причём здесь "Ява?"
> Любая ВМ подойдёт, как я понимаю.
Любая конечно.
А ты говоришь "нафиг не нужна".

Ivan8209

То есть, "частичное применение?"
Я правильно понимаю?
У "Явы" очень плохая ВМ.
Медленная.
---
...Я работаю антинаучным аферистом...

Chupa

> То есть, "частичное применение?"
> Я правильно понимаю.
Да, только это частичное применение может быть гораздо сложнее
подстановки констант в нужные места программы, и может включать
достаточно сильную трансформацию кода или вообще генерацию его заново.
На относительно игрушечном языке (пример из дисера) мне однажды показывали,
как из функции поиска подстроки в строке методом последовательного прикладывания образца
в результате специализации по подстроке, которую ищем, получался
алгоритм КМП для её поиска.

Ivan8209

> Да, только это частичное применение может быть гораздо сложнее
Ну, это понятно.
> алгоритм КМП для её поиска.
Сокращение не понял.
---
"...Надо учиться --- не напрягаясь!.." Акад. А. А. Бучаченко.

Chupa

Алгоритм Кнута-Морриса-Пратта.

Marinavo_0507

А что тут чудесного?
То же самое на C записывается с помощью конструкции if.
Теперь ты наверное логическое программирование идеализируешь,
а там тоже нет чудес.
Все "чудесные" результаты, вроде суперкомпиляции или как там
называется то, про что рассказывает, придумываются
теоретиками, и мейнстрим узнает про это в последнюю очередь.
По определению, ведь до этого нет готовых библиотек, модулей, советов.

Marinavo_0507

> А трансляторы из ФЯ в ИЯ есть? Например, для Java-ы?
Ну бывают, конечно, только ИЯ в качестве ассемблера используются обычно -
более высокоуровневые конструкции едва ли подойдут из-за другой системы типов хотя бы.

Aleksei66

Как тут правильно заметили, изучение разных парадигм программирования полезно тем, что дает возможность иначе взглянуть на решаемые проблемы, даже если ты никогда не напишешь ни одной программы на языке отличном от C#, например. Здесь такая же ситуация, как и с естественными языками, жалкими подобиями которых являются компьютерные. Выучив другой язык ты получаешь возможность взлянуть на мир через призму другой культуры, осмыслить его в совершенно иных и необычных терминах. Твоя проблема сейчас в том, что ты не знаешь, что значит мыслить функционально, ты пытаешься сравнивать ФЯ и ИЯ с позиций ИЯ, так как ты привык решать задачи на них и требуешь от нас, чтобы мы тебе показали преимущества ФЯ на каких-то искуственных примерах. Это бессмысленный подход, как я мог бы, например, доказать человеку, который не знает английского, что он ничем не хуже русского, а просто другой? Есть только один путь, чтобы понять разницу - выучить самому один из ФЯ, благо есть книги и по ML и по OCaml и по Haskell. Я думаю, ты не пожалеешь о потраченном времени, тем более, что ФЯ синтаксически гораздо проще императивных и учатся гораздо быстрее. Взамен ты узнаешь, что есть совсем иной взгляд на то, как должны выглядеть программы, настолько другой, что в свое время для меня было сильным потрясением узнать о нем.

Dasar

> То же самое на C записывается с помощью конструкции if.
Опять ты испортил мое идеализированное представление о ФЯ
> Теперь ты наверное логическое программирование идеализируешь,
а там тоже нет чудес.
Логическое программирование пока отложим.
Меня на данный момент интересуют в первую очередь декларативные языки.
Мне казалось, что ФЯ как раз являются декларативными языками, но оказалось, что в ФЯ этой самой декларативщины лишь малая часть.
> Все "чудесные" результаты, вроде суперкомпиляции или как там
называется то, про что рассказывает, придумываются
теоретиками, и мейнстрим узнает про это в последнюю очередь.
По определению, ведь до этого нет готовых библиотек, модулей, советов.
Это понятно. И с этим я согласен.
Но одно дело, когда эти "чудесные" результаты - совершенно оторваны от MainStream-а и непонятно, что с ними тогда делать в реальной жизни.
А совсем другое дело, когда эти "чудесные" результаты после доработки напильником могут быть применены в реальных проектах (для этого и должна быть стыковка с mainStream-ом).

Dasar

> выучить самому один из ФЯ
ФЯ я знаю (по крайней мере в рамках Лиспа и могу писать программы в функциональном стиле (вышеперечисленные приведенные примеры на ФЯ, я поматерившись на синтаксис, смогу написать)
но при этом я не вижу принципиальной разницы между ИЯ и ФЯ, и там, и там мы пишем, как надо делать, а не что надо делать. Какая разница как записывать работу над списком? В виде рекурсии, или в виде цикла? Рекурсивный вариант только чуть более близок к математической записи, но не более.
Но я вижу, что вокруг ходит народ и восторгается этим самым функциональным подходом.
В результате этого противоречия (вижу/не вижу) возникает мысль, что может я что-то недопонял в ФЯ? Может нынешние функциональные языки (ML, OCaml, Haskell и т.д.) умеют больше, чем я о них думаю на примере Лиспа?
На основе данного треда, все-таки вытанцевывается мысль, что в ФЯ сильно прогрессивных идей, по сравнению с тем же C++, не несут.

Ivan8209

Доказательство соответствия программы заданию значительно проще.
И рекурсия и цикл могут быть спрятаны.
Смотри хотя бы те же map и filter.
Ленивые вычисления даже на Лиспе делать куда проще, чем на ИЯ.
В отличие от Лиспа ни у одного ИЯ нет единства программ и данных.
---
"Надо учиться --- не напрягаясь!"

Marinavo_0507

> В отличие от Лиспа ни у одного ИЯ нет единства программ и данных.
У ФЯ тоже

Ivan8209

Именно потому я и остаюсь с Лиспом.
МЛ-ы мне не так понравились.
---
"А я обучался азбуке с вывесок,
листая страницы железа и жести."

Dasar

> И рекурсия и цикл могут быть спрятаны.
> Смотри хотя бы те же map и filter.
По этому я и говорю, что разницы между ИЯ и ФЯ нет, потому что мы можем реализовать map и filter и там, и там, а далее будет код один в один.
Что понимается под "единством программы и данных"?

Marinavo_0507

> ФЯ я знаю (по крайней мере в рамках Лиспа)
Лисп - обычно не считается ФЯ, на нём можно писать в любом практически стиле.
> но при этом я не вижу принципиальной разницы между ИЯ и ФЯ, и там, и там мы пишем, как надо делать, а не что надо делать.
Я понимаю так, что это общее свойство языков программирования.
В отличии от других языков.
О декларативных языках.
Тут имхо надо разделять ситуации: одно дело, когда необходимо понимание, что происходит в интерпретаторе,
и тогда это язык программирования: фактически, человек пишет так, чтобы "за кулисами" происходило
то, что ему нужно.
И другое дело, если это понимание не требуется, тогда это не программирование, а использование программы.
ФП и ИП - это разные представления алгоритма.
Иногда удобнее одно, иногда другое.
> Но я вижу, что вокруг ходит народ и восторгается этим самым функциональным подходом.
Народу нравится функциональное представление
> В результате этого противоречия (вижу/не вижу) возникает мысль, что может я что-то недопонял в ФЯ?
Возможно, ты не видишь чистых функций, и соответственно потенциальной области применения ФП,
там, где этот народ их видит?
Такое предположение согласуется с твоими словами, что ты почему-то считаешь ФП неприменимым
там, где другие видят применения.
> На основе данного треда, все-таки вытанцевывается мысль, что в ФЯ сильно
> прогрессивных идей, по сравнению с тем же C++, не несут.
В С++ неудобно писать в функциональном стиле, а идея это или нет, уж не знаю.
Просто отсутствуют некоторые конструкции языка, и чтобы получить возможности ФЯ,
фактически нужно писать интерпретатор или самому поработать компилятором.
А Лисп - случай особый, вследствии единообразия кода и данных.
В частности, насколько я понял (точно скажу, когда книжку дочитаю
магию вроде этого yield можно реализовать штатными средствами.
И любую другую магию такого плана.
Например, ленивость, мемоизацию, или там заставить
любую программу чек-поинты периодически делать.
Но тут я не уверен - книжку не дочитал.

Ivan8209

> мы можем реализовать map и filter и там, и там
Вперёд.
map из R^5RS на "C."
> Что понимается под "единством программы и данных"?
Оно и понимается.
См. lambda.
---
...Я работаю антинаучным аферистом...

Dasar

> И другое дело, если это понимание не требуется, тогда это не программирование, а использование программы.
Эту фразу не понял.
> Возможно, ты не видишь чистых функций, и соответственно потенциальной области применения ФП,
там, где этот народ их видит?
Можно ли сказать, что в sql-е много чистых функций?
А ведь как раз большую часть кода в прикладных программ можно описать в рамках sql-я.

Ivan8209

> Лисп - обычно не считается ФЯ, на нём можно писать в любом практически стиле.
На МЛ (в т. ч. и Хаскелле) тоже можно.
Вывод.
> О декларативных языках.
> Тут, имхо, надо разделять ситуации:
> одно дело, когда необходимо понимание, что происходит в интерпретаторе,
> и тогда это язык программирования: фактически, человек пишет так,
> чтобы "за кулисами" происходило то, что ему нужно.
Верное замечание.
Порядок вычисления аргументов произволен, в общем случае.
> Возможно, ты не видишь чистых функций,
> и соответственно потенциальной области применения ФП,
> там, где этот народ их видит?
Чистые функции тоже имеют своё назначение.
Именно в смысле порядка вычислений и параллельности.
А ещё и для доказательства корректности.
> В С++ неудобно
Невозможно.
Функции неравноправны с обычными данными.
> А Лисп - случай особый, вследствии единообразия кода и данных.
> В частности, насколько я понял (точно скажу, когда книжку дочитаю
> магию вроде этого yield можно реализовать штатными средствами.
См. Лисп на Лиспе по Самому Маккарти.
Придётся сделать переключающий цикл.
> Например, ленивость,
Легко.
> мемоизацию,
Не понял, что ты имеешь в виду.
Замыкание, что ли? "function"?
> или там заставить любую программу чек-поинты периодически делать.
Тоже не понял.
---
"А я обучался азбуке с вывесок,
листая страницы железа и жести."

Dasar

> map из R^5RS на "C."
чем он отличается от Map-а на Лиспе?
> См. lambda.
см. http://boost.org/libs/lambda/doc/index.html

Dasar

> А Лисп - случай особый, вследствии единообразия кода и данных.
> В частности, насколько я понял (точно скажу, когда книжку дочитаю
магию вроде этого yield можно реализовать штатными средствами.
> И любую другую магию такого плана.
Например, ленивость, мемоизацию, или там заставить
любую программу чек-поинты периодически делать.
На SmallTalk-е эта магия тоже активно делается и используется.

Ivan8209

Ты напиши-напиши.
Сообщи, какого типа значение вовзращает твой map.
---
...Я работаю антинаучным аферистом...

Marinavo_0507

> > И другое дело, если это понимание не требуется, тогда это не программирование, а использование программы.
> Эту фразу не понял.
Возьмём например декларативный язык SQL.
Если ситуация такая, что можно написать любой запрос из эквивалентных,
не заботясь об например об эффективности, то это не программирование.
Всё уже запрограммировали авторы СУБД.
Если же нужно думать, какие создать индексы, и как потом сформировать запрос,
не дай бог с хинтами оптимизатору, вот это уже можно рассматривать
как программирования, но и декларативности поубавилось.
В чём разница?
В обоих случаях человек формулирует, какой нужно результат получить.
Но во втором случае оказывается не всё равно, как он будет получен,
и тут начинается программирование.
> А ведь как раз большую часть кода в прикладных программ можно описать в рамках sql-я.
Имхо неправда.
Самая интересная часть - это та, которая определяет, когда какие запросы
выдавать, в каком порядке, с какими параметрами, и как использовать результаты.
И на SQL это не выражается (если процедурные расширения туда не относить).
Вот там уже дофига можно найти чистых функций.
А SQL - это всего лишь элемент API.

Marinavo_0507

> > Лисп - обычно не считается ФЯ, на нём можно писать в любом практически стиле.
> На МЛ (в т. ч. и Хаскелле) тоже можно.
> Вывод.
На Лиспе - примерно одинаково удобно в любом стиле.
На ФЯ - в языке специальные конструкции для функционального стиля.
> Порядок вычисления аргументов произволен, в общем случае.
Я вообще то далеко не только про порядок, а вообще про все действия.
Декларативный язык - специфицирует только желаемый результат.
Язык программирования - описывает способ получения результата.
> > В С++ неудобно
> Невозможно.
Возможно скомпилировать функциональную программу в C++.
В том числе и вручную, примеры приводил в одном из прежних флеймов.
> > мемоизацию
запоминание результата чистой функции, чтобы потом,
если её вызовут с тем же аргументами, просто подставить
тот же результат
> > заставить любую программу чек-поинты периодически делать
ну типа есть программа
а мы из неё получаем (прозрачно для пользователя) другую,
которая периодически сохраняет состояние, для обеспечения
отказоустойчивости
мы это обсуждали как-то уже
Ещё вспомнил:
исполнение недоверенных апплетов.
Можно получить выражение (программу) и например расставить необходимые проверки
доступа в соответствии с политикой безопасности, причём по ходу доказать как можно
больше полезных свойств, которые позволят сэкономить на проверках.

Marinavo_0507

> На SmallTalk-е эта магия тоже активно делается и используется.
Да!
Это тоже язык с тем же свойством, как я понял из тонкой книжки.

Dasar

> Ты напиши-напиши.
> Сообщи, какого типа значение вовзращает твой map.
Открываем файл <algorithm> из поставки любого компилятора C++:
[c]
// TEMPLATE FUNCTION transform WITH UNARY OP
template<class _InIt,
class _OutIt,
class _Fn1> inline
_OutIt transform(_InIt _First, _InIt _Last, _OutIt _Dest, _Fn1 _Func)
{ // transform [_First, _Last) with _Func
for (; _First != _Last; ++_First, ++_Dest)
*_Dest = _Func(*_First);
return (_Dest);
}
// TEMPLATE FUNCTION transform WITH BINARY OP
template<class _InIt1,
class _InIt2,
class _OutIt,
class _Fn2> inline
_OutIt transform(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2,
_OutIt _Dest, _Fn2 _Func)
{ // transform [_First1, _Last1) and [_First2, _Last2) with _Func
for (; _First1 != _Last1; ++_First1, ++_First2, ++_Dest)
*_Dest = _Func(*_First1, *_First2);
return (_Dest);
}
[/c]
пример использования (из документации):
[c]
Example
// alg_transform.cpp
// compile with: /EHsc
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
// The function object multiplies an element by a Factor
template <class Type>
class MultValue
{
private:
Type Factor; // The value to multiply by
public:
// Constructor initializes the value to multiply by
MultValue ( const Type& _Val ) : Factor ( _Val ) {
}
// The function call for the element to be multiplied
int operator ( ) ( Type& elem ) const
{
return elem * Factor;
}
};
int main( )
{
using namespace std;
vector <int> v1, v2 ( 7 v3 ( 7 );
vector <int>::iterator Iter1, Iter2 , Iter3;
// Constructing vector v1
int i;
for ( i = -4 ; i <= 2 ; i++ )
{
v1.push_back( i );
}
cout << "Original vector v1 = ( " ;
for ( Iter1 = v1.begin( ) ; Iter1 != v1.end( ) ; Iter1++ )
cout << *Iter1 << " ";
cout << ")." << endl;
// Modifying the vector v1 in place
transform (v1.begin ( ) , v1.end ( ) , v1.begin ( ) , MultValue<int> ( 2 ) );
cout << "The elements of the vector v1 multiplied by 2 in place gives:"
<< "\n v1mod = ( " ;
for ( Iter1 = v1.begin( ) ; Iter1 != v1.end( ) ; Iter1++ )
cout << *Iter1 << " ";
cout << ")." << endl;
// Using transform to multiply each element by a factor of 5
transform ( v1.begin ( ) , v1.end ( ) , v2.begin ( ) , MultValue<int> ( 5 ) );

cout << "Multiplying the elements of the vector v1mod\n "
<< "by the factor 5 & copying to v2 gives:\n v2 = ( " ;
for ( Iter2 = v2.begin( ) ; Iter2 != v2.end( ) ; Iter2++ )
cout << *Iter2 << " ";
cout << ")." << endl;
// The second version of transform used to multiply the
// elements of the vectors v1mod & v2 pairwise
transform ( v1.begin ( ) , v1.end ( ) , v2.begin ( ) , v3.begin ( ) ,
multiplies <int> ( ) );

cout << "Multiplying elements of the vectors v1mod and v2 pairwise "
<< "gives:\n v3 = ( " ;
for ( Iter3 = v3.begin( ) ; Iter3 != v3.end( ) ; Iter3++ )
cout << *Iter3 << " ";
cout << ")." << endl;
}
Output
Original vector v1 = ( -4 -3 -2 -1 0 1 2 ).
The elements of the vector v1 multiplied by 2 in place gives:
v1mod = ( -8 -6 -4 -2 0 2 4 ).
Multiplying the elements of the vector v1mod
by the factor 5 & copying to v2 gives:
v2 = ( -40 -30 -20 -10 0 10 20 ).
Multiplying elements of the vectors v1mod and v2 pairwise gives:
v3 = ( 320 180 80 20 0 20 80 ).
[/c]

Dasar

> Это тоже язык с тем же свойством, как я понял из тонкой книжки.
Это свойство называется "closure"?

Marinavo_0507

Это свойство - наличие единого представление кода и данных,
позволяет создавать самомодифицирующийся код.
Характерно ещё для маш.кода
Пользоваться тем легче, чем проще сгенерировать код и запустить его.
В Лиспе - проще всего, наверное.

Ivan8209

А если арность оператора увеличить, придётся переписывать, так я понимаю?
Сравни объём кода:


(define (orl . l)
(if (null? l) #f
(if (car l) #t (apply orl (cdr l
(define (mapcar f l)
(if (null? l) l
(cons (f (car l (mapcar f (cdr l
(define (map f . l)
(if (apply orl (mapcar null? l '
(cons (apply f (mapcar car l
(map f (mapcar cdr l


Это определение.
Просто тупо напрямую.
f в map --- функция какой угодно арности.
Одно только использование в Си уже неудобно.
Сможешь написать так?


(map + '(1 2 3 4) '(5 6 7 8


Или тебе придётся обёртку для плюса делать?
---
...Я работаю антинаучным аферистом...

Dasar

> А если арность оператора увеличить, придётся переписывать, так я понимаю?
Сейчас сложно сказать. Так сразу я не вспомнить использование многоарных функций.
> Или тебе придётся обёртку для плюса делать?


#include <algorithm>
#include <functional>
#include <iterator>
#include <vector>
int _tmain(int argc, _TCHAR* argv[])
{
int f1[] = {1, 4, 2};
int f2[] = {3, -4, 1};
std::vector<int> result;
std::transform(&f1[0], &f1[sizeof(f1)/sizeof(int)], &f2[0],
std::back_insert_iterator<std::vector<int> >(result
std::plus<int>
return 0;
}

Ivan8209

Многоарная?
Построение кубического сплайна, например.
Выкинь две строки с присвоением значений массивов и посмотри,
насколько много тебе приходится писать лишнего.
Начиная с "#include" и заканчивая постоянным "std::" и непонятным "sizeof(int)."
Почему сделано взятие первого члена "[0]"?
Почему есть смешение понятий массива и неизвестно чего, обозначенного "std::vector?"
Почему введены переменные f1, f2?
У меня не было никаких вспомогательных имён.
Кстати, почему ты не можешь "#include" написать в одну строчку?
Наподобие такого:
(require "this" "this" "and this")
Это настолько просто сделать, что не сделать этого --- преступление.
То, что ты привёл, --- это не функциональный стиль.
Должно быть так:
(max (map + '(1 2 3 4) '(5 6 7 8
А у тебя --- фортраноподобное "call solve(in1, in2, rslt)."
---
...Я работаю антинаучным аферистом...

Dasar

> Почему сделано взятие первого члена "[0]"?
> Почему есть смешение понятий массива и неизвестно чего, обозначенного "std::vector?"
> Почему введены переменные f1, f2?
Потому что C++ - уродский язык с уродскими legacy-конструкциями для сохранения максимальной совместимости с C
> То, что ты привёл, --- это не функциональный стиль.
> Должно быть так:
> (max (map + '(1 2 3 4) '(5 6 7 8
> А у тебя --- фортраноподобное "call solve(in1, in2, rslt)."
В чем разница?

Ivan8209

Где вовзращаемое значение у твоего якобы "map?"
Ты пишешь примерно так: call map(f,x,result)
А должно быть так: result=map(f,x)
---
...Я работаю антинаучным аферистом...

Ivan8209

Это я читал.
Половина, если не больше, "причин" весьма и весьма спорны.
Некоторые вообще неверны.
Ты смотрел внутрь Glibc?
---
...Я работаю антинаучным аферистом...

Dasar

> Ты пишешь примерно так: call map(f,x,result)
> А должно быть так: result=map(f,x)
во-первых, я пишу вот так:
call map(f, x, шняга_в_которую_надо_положить_result)
во-вторых, это уже придирки к синтаксису

solteron

> В отличие от Лиспа ни у одного ИЯ нет единства программ и данных.
У ФЯ тоже
А в Python вообще все, что можно является объектами, включая переменные, функции и модули.
Чем не единство?

Dasar

> Ты смотрел внутрь Glibc?
Нет не смотрел, а стоит?

Ivan8209

Это не придирки к синтаксису.
Как ты напишешь такое?
(foldr + (map * list1 list2
---
...Я работаю антинаучным аферистом...

Ivan8209

Посмотри.
Увидишь, чего стоят все эти ИЯ с никакой расширяемостью.
Размышлять над словом "метапрограммирование."
---
...Я работаю антинаучным аферистом...

Ivan8209

Не единство.
Функции ты умеешь создавать?
Сравни: (map (list 'lambda '(x) (read 1 2 3 4)
---
...Я работаю антинаучным аферистом...

solteron

Да, функции можно создавать на лету. На самом деле, в питоне (по крайней мере в версиях 2.x) имеются lambda, map, filter и reduce. Но я его функциональными возможностями пока не пользовался на практике.

Aleksei66

По поводу статьи. Все возражения там или сопровождаются объяснением, почему на самом деле это возражение несущественно, или связаны с недостаточным финансированием (отладчики, библиотеки и т.п.) . На самом деле статья не о том, почему не нужно использовать ФЯ, а про то, почему это делать надо, но есть пока некоторое проблемы, препятствующие этому.

DiDiPi

> Для изучения Лиспа нужно иметь довольно продвинутые мозги.
Зачем так категорично? Вот смотрю, например, как инженеры-проектировщики лихо пишут в АвтоКАДе на Lisp'е свои какие-то задачи.Эти люди не программисты, к тому же большинство из них кроме АвтоКАДа компьютерами не пользуется.
ps
На мой взгляд, утверждение "для изучения ХХХ нужно иметь довольно продвинутые мозги" лишено смысла. В общем виде в абстрактной теории все может казаться сложным и задвинутым, но если есть конкретные задачи, которые однозначно делаются на ХХХ, любой здравомыслящий вменяемый человек способен освоить.

freezer

я б написал так:


#include <algorithm>
#include <functional>
#include <iterator>
#include <vector>
using namespace std;
int main
{
int f1[] = {1, 4, 2}, f2[] = {3, -4, 1};
vector<int> result;
transform(f1, f1+sizeof(f1)/sizeof(int f2, back_inserter(result plus<int>
return 0;
}


симпатичнее смотрится
а еще у меня есть самопальная либа в которой это все можно было бы сделать так:


#include "vectop.h"
using namespace cmpml;
void main
{
array1d<int> a, b, c;
a=1, 4, 2; b=3, -4, 1;
c=a, b;
}


интересно, Контру это устроит?..

Dasar

> using namespace std;
В больших приложения за такое убивают. Потому, что очень много идет пересечений по идентификаторам (vector, string, min, max и т.д.)
> int f1[] = {1, 4, 2}, f2[] = {3, -4, 1};
Опять же не рекомендуется при разработке в команде, т.к. читабельность падает. запятую лучше, вообще, стараться не использовать, потому что она приводит к довольно трудновидимым глюкам.
например:


double pi = 3,1415;


Ошибку в этом коде можно искать очень долго.
> a=1, 4, 2; b=3, -4, 1;
в команде, я бы с запятой не баловался бы. тем более данной кусок изменяет семантику оператора запятая

Darion

В последнее время, время перемен, время движения и изменения всего, что только можно менять, время новых возможностей и новых технологий, когда одна — молниеносно сменяет другую, стоит уделить особое внимание возможности сохранения накопленных знаний, знаний, над которыми корпели наши отцы, знаний, которые прошли самую надежную проверку — проверку времени. Новая технология, новый язык... основной минус в том, что миллионы строк надежного кода, написанного на «устаревшем» языке могут потеряться. Поэтому до сих пор в некоторых местах востребованы программисты на клиппере, не для разработки, но для поддержки.
Наша эпоха — это не только эпоха технологических метамарфоз. Наша эпоха — это эпоха систем миграции. Ведь это чудо, когда старый, уже никому не нужный код, но давно отлаженный и проверенный годами, сможет эволюционировать и породить таким образом новый, готовый к интеграции с самыми последними технологическими достижениями.
На смену двухуровневой технологии больших информационных систем пришла трёхуровневая, не буду вдаваться в природу и преимущества настоящего скачка, но отмечу и, может быть, повторюсь, что миллионы строк отлаженного кода, например, написанного на языке PL/SQL могут кануть в лету. Только грамотная система миграции может спасти золото наших отцов. По сути, система миграции — это компилятор, не в узком смысле, когда имеется в виду превращение текста на языке программирования в машинно-зависимый бинарный файл, но в истинном смысле, означающим преобразование текста одного языка в текст другого языка, будь то реальный язык программирования или машинные коды. Формальный язык или нет (в последнем случае — это уже задачи AI для реализации этого процесса нужно сосредоточиться именно на сути проблемы, но не на системных задачах подобных «проблемам» расположения кнопочек на форме, ползущей надписи, выделения памяти, ручной сборки мусора, в конце концов, сворачивания языка в трубочку и других ухищрения, что по сути вызывает глубинные мутации, в том числе и у воспринимающего субъекта — того програмиста, который вместо того, чтобы изливать свою душу на красивом языке постоянно ругается словами йоб твайу, пидарасы, гандоны, твердит о четвертовании била гейтса и ритуальном сожжении ОС Windows вместе со своими распрекрасными VC, COM, GDI, ADO, IUnknown, .NET, и другими высокотехнологичными словами, а потом с пола устало собирает остатки клавиатуры, искоса поглядывая в монитор на ящик сообщения, гласящий "Access violation", он, монитор, может быть, тоже не будет обделён...
Ява — это хороший раскрученный язык, но, товарищи, истинная сила в pattern matching, по крайней мере, в насущной задачи миграции. Я не буду объяснять, что это такое для тех, кто не знает, для этого есть очень много соответствующей литературы, но, товарищи драйверописатели, бухгалтеры и другие, в частности, все любители проектов «с нуля», не доказывайте со слюнями, что ваш язык круче. Дискуссия, как обычно, превратится в мерянье письками.
ML — вот пример языка, отлично подходящего для вышеназванной задачи. Как пример готового проекта, дам ссылку:
http://www.fdc.ru/portal/page?pageid=60,54746&_dad=portal&_schema=PORTAL
это адрес страницы, на которой описывается проект миграции из PL/SQL в современные Java технологии. Компилятор полностью написан на функциональном языке SML. Касательно процесса разработки — если программа откомпилировалась и у программиста нет ошибки в ДНК, то, скорее всего, все заработает правильно. Исключением могут быть лишь те случаи, когда программист не до конца понимает поставленной перед ним задачи. Касательно непопулярности языков ФП скажу лишь, что почти все знакомые мне программисты банально не понимают и не умеют пользоваться рекурсией. А заявления, подобные «что это за язык такой, без циклов, без настоящих переменных, без гуи, и не поддерживающий COM» — это те же самые заявления, что и о плоской Земле. Вскормленные на хелловордных книгах, люди не в состоянии вполне оценить прелесть функционального программирования. Это лишь наблюдение… Я ни в коем случае не пропагандирую ФП, я лишь отмечаю, что красота должна быть выразима и не должна иметь предела. Выбирайте сами язык, на котором вы лучше всего признаетесь в любви вычислительной технике, и, конечно же, себе самому как высококвалифицированному специалисту.

Dasar

Я не понимаю, как этот самый pattern matching поможет в больших проектах, если он работает только со списками.
Сначала пара вопросов:
что такое тип в понятие ML-я?
можно ли на нем описать тип натуральное число? как это будет выглядить? Что это нам даст?
можно ли описать, например, тип C-идентификатор - это строка, с рядом ограничений
можно ли описать, например, тип идентификатор - это нечто, которое можно между собой сравнивать.
тип круг - это штука, у которой есть поля радиус и центр, и которая поддерживает операции изменитьПоложение, ВернутьОсиСимметрии и т.д.
тип невырожденный эллипс - это штука, с полями большой, малый радиус, центр, с операциями ВернутьФокусы, изменитьБольшойРадиус и т.д.

Marinavo_0507

Новый язык - новый способ мышления.
Чтобы понять язык, нужно научиться на нём думать, а не переводить с него на родной и обратно.
Вот ты английские термины часто используешь, почему не переводишь на русский?
Твои вопросы означают: а можно ли программу на C++ перевести в SML?
Да, конечно можно, но смысла не прибавится, наоборот, станет длиннее и менее понятно.
Как если бы слова co-routines, mainstream, closure и т.д. переводить на русский.
Если ты хочешь писать ОО, возьми ОО-язык, который специально для этого придуман.

Marinavo_0507

Сцылка не работает:
Error: ORA-06502: PL/SQL: numeric or value error: character to number conversion error
Наверное, при переводе на Java что-то сломалось

Chupa

> Это я читал.
> Половина, если не больше, "причин" весьма и весьма спорны.
> Некоторые вообще неверны.
И кому народ поверит: благородному дону или Контре?

Chupa

Wadler всё правильно написал. И даже Куна не зря вспомнил.
Только твоих взглядов на ФП он совсем не разделяет:
Функциональное программирование прекрасно, оно - радость созерцания. Как только кто-то поймет функциональное программирование, он немедленно перейдет к нему. Массы, которые застряли в устаревшем императивном и объектно-ориентированном программировании, делают это из слепого предубеждения. Они просто не понимают.

Papazyan

Как пример готового проекта, дам ссылку:
http://www.fdc.ru/portal/page?pageid=60,54746&_dad=portal&_schema=PORTAL
это адрес страницы, на которой описывается проект миграции из PL/SQL в современные Java технологии.

Ну надо же, неужели все-таки написали.

Papazyan

Я не понимаю, как этот самый pattern matching поможет в больших проектах, если он работает только со списками.
Сначала пара вопросов:
что такое тип в понятие ML-я?
можно ли на нем описать тип натуральное число? как это будет выглядить? Что это нам даст?
можно ли описать, например, тип C-идентификатор - это строка, с рядом ограничений
можно ли описать, например, тип идентификатор - это нечто, которое можно между собой сравнивать.

Тип в понятии ML - это обычный тип. Ограничения на типы можно накладывать в Haskell.
Выглядит это примерно так: берем и говорим, что всякий, кто претендует на звание целого числа, должен поддерживать операции + и -. После чего, ты создаешь свой тип и реализуешь для него эти операции и дальше твой тип можно передавать в функции, где требуются целые типы. Т.е. если есть полиморфная функция, которая складывает свои аргументы, то в нее можно передать значения любого типа, если они поддерживают понятие целое. На самом деле в Haskell'e можно делать даже больше, но я не помню уже что именно.

Dasar

> Новый язык - новый способ мышления.
> Чтобы понять язык, нужно научиться на нём думать, а не переводить с него на родной и обратно.
Не вижу я этого нового мышления, не вижу. Самое главное не вижу, что мне это новое мышление дает.
Вот с чем я, как архитектор, буду работать в ФЯ? со списками?
Рассмотрим, как человек, в реале взаимодействует с окружающим миром.
В реале, можно взять любой предмет, даже незнакомый, и по этому предмету определить, что он умеет. Подошли к окну, посмотрели на него, потрогали, попинали и поняли, что он состоит из рамы, стекла; умеет показывать, что находится за ним; быстро портится, если по нему пинать и т.д.
В ОО-программе, все тоже самое, я беру незнакомый объект, и прямо по объекту понимаю, что он из себя представляет, что с ним можно делать и т.д.
Для большого проекта - это очень важный принцип, т.к. все держать в голове не получается, особенно, если в разработке участвуют другие люди.
В ФЯ я всего этого не вижу, а так же не вижу какие-то другие подходы, которые позволяют мне также легко работать с большой программой, незнакомой программой.
А также не вижу, что мешает, например, для списка "круг" применить функцию "посмотреть сквозь него", поэтому опять же не понимаю фразу о том, что "если программа на ML скомпилировалась, то в ней нет ошибок".
> Вот ты английские термины часто используешь, почему не переводишь на русский?
Вот скажу я "сборщик" - а каждый поймет, что-то свое (linker, assembler, compilator, builder). Зачем мне это надо?

Papazyan

В OCamle похожего эффекта можно добиться с помощью объектов. В функции там можно передавать любые объекты, если у них есть нужный набор функций с правильными сигнатурами. Т.е. это что-то вроде интерфейсов в C#, только лучше.

Dasar

> В OCamle похожего эффекта можно добиться с помощью объектов.
Объекты mutable-ные, или нет? Тип объектов можно менять?
> Т.е. это что-то вроде интерфейсов в C#, только лучше.
Чем лучше?

Dasar

> Если ты хочешь писать ОО, возьми ОО-язык, который специально для этого придуман.
Приведи примеры программ, для которых ОО лишний, и не дает ничего полезного.
ps
Замечу, что список, атом, число, строка, функция - это все тоже объекты, каждый из которых поддерживает свой набор операций над ним.
т.е. получается, что в программе на ФЯ у нас есть только объекты зашитые в язык, но нет возможности описать свои объекты.

Dasar

> (map + '(1 2 3 4) '(5 6 7 8
а это будет работать если вместо чисел будут комплексные числа?
при чем самих комплексных чисел на уровне языка нет.
и как это для случая комплексных чисел запишется?

sergey_m

Приведи примеры программ, для которых ОО лишний, и не дает ничего полезного.
Посмотри в исходники Linux или FreeBSD.
Замечу, что список, атом, число, строка, функция - это все тоже объекты, каждый из которых поддерживает свой набор операций над ним.
т.е. получается, что в программе на ФЯ у нас есть только объекты зашитые в язык, но нет возможности описать свои объекты.

Да, любую задачу можно свести к объектам. Но это вовсе не означает, что именно так и надо делать.

Papazyan

>Объекты mutable-ные, или нет? Тип объектов можно менять?
Что ты имеешь ввиду? Объекты могут содержать mutable поля, чтобы не копироваться при каждом присваивании и могут быть целиком объявлены, как mutable, как и любая другая переменная. Тип менять естественно нельзя, и на что его собственно менять?
>Чем лучше?
Лучше тем, что все делается неявно самим компилятором. Кроме того, все это полиморфно.

Marinavo_0507

> Посмотри в исходники Linux или FreeBSD.
Там полно ОО
Так что пример плохой.

Dasar

> Тип менять естественно нельзя, и на что его собственно менять?
Допустим сначала был тип круг, а мы к нему применили операцию изменить радиус по осиX, в результате тип должен измениться на тип эллипс.

Marinavo_0507

> Не вижу я этого нового мышления, не вижу.
Естественно.
Вот ты видишь людей, у них, как у тебя, одна голова и две руки.
Но вот их поступков ты не понимаешь, сам признаёшься.
Потому что думают они по-другому.
> Самое главное не вижу, что мне это новое мышление дает.
Это можно понять, только научившись ему.

Darion

тип в понятиях ML — это такая штука, которая позволяет избежать многих ошибок на этапе компиляции. ML, в отличии от С и С++ — язык со строгой типизацией. Это значит, грубо говоря, что тип значения не может быть изменен во время исполнения программы. Иначе мы забываем о том, зачем вообще были придуманы типы. В ML есть еще такое понятие как tyvar — это значит, что тип значения в данном контексте _не_важен_ и, в принципе, может быть любым.
Пример 1:
fun exchange (a: int, b: int) = (b, a)
эта функция получает пару целых чисел и возвращает понятно чего.
Пример 2:
fun exchange (a: int, b: 'a) = (b, a)
эта функция получает пару, состоящую из целого числа на первом месте и абсолютно чего угодно, хоть целую программу туда запихни, на втором месте. Обозначение tyvar как 'a в данном случае значения не играет, потому что оно встречается только один раз. По-другому то же самое можно записать так: fun exchange (a: int, b) = (b, a)
Пример 3:
fun exchange (a: 'a, b: 'a) = (b, a)
это значит, что функция принимает пару значений одного и того же типа.
Пример 4:
fun exchange (a: 'x, b: 'y) = (b, a или просто fun exchange (a, b) = (b, a)
принимает значения произвольных типов.
Тут я продемонстрировал некоторые примеры параметрического полиморфизма, что в С++ достигается использованием неуклюжих шаблонов.
ML поддерживает несколько встроенных типов, а именно: char, string, int, real, unit (аналок void в С, единственное его значение - это ).
Свои типы данных, в понятиях С++, инстанциированные шаблоны, могут быть такими: int list, int * string, (int * string list) list list и другие, которые создаются на основе чего-то типа декартова произведения типов ( тип1 * тип 2 * ... * типН ) или на основе того же самого инстанциирования, для этого нужно, чтобы тип был соответствующим образом определен.
Пример реализации "Натуральное число":


structure Nat :> sig
(* это что-то типа интерфейса *)
type nat
val make_nat : int -> nat
val to_int : nat -> int
val plus : nat -> nat -> nat
val minus: nat -> nat -> nat
(* тут идут другие декларации *)
end = struct
datatype nat =
Nat of int
| NotNat
fun make_nat n = if n > 0 then Nat n else NotNat
fun to_int (Nat n) = n
| to_int _ = 0
fun plus (Nat n1) (Nat n2) = Nat (n1 + n2)
| plus _ _ = NotNat
fun minus (Nat n1) (Nat n2) = if n1 > n2 then Nat (n1 - n2) else NotNat
| minus _ _ = NotNat
(* тут идут другие функции *)
end


Для окружности:


structure Circle :> sig
type circle
val make_circle: real * real * real -> circle
val relocate : (real * real) -> circle -> circle
val to_graphics : circle -> Graphics.graphics
end = struct
datatype circle =
Circle of real * real * real (* коорд. х, коорд. у, радиус *)
| NotCircle
fun make_circle (x, y, r: real) = if r > 0 then Circle (x, y, r) else NotCircle
fun relocate (x', y') (Circle (x, y, r = Circle (x', y', r)
| relocate _ _ = NotCircle
fun to_graphics (c as (Circle _ = let
fun to_graphics' (c as (Circle (x, y, r graphics alpha = let
val x1 = (x + r * (Math.cos alpha
val y1 = (y + r * (Math.sin alpha
val alpha = alpha + 1;
val x2 = (x + r * (Math.cos alpha
val y2 = (y + r * (Math.sin alpha
val graphics = Graphics.DrawLine x1, y1 (x2, y2 graphics
in
if alpha < 360 then
to_graphics' c graphics alpha
else
graphics
end
| to_graphics' _ g _ = g
in
to_graphics' c Graphics.empty 0
end
| to_graphics _ = Graphics.empty
end


Если что-то непонятно, могу разъяснить.

Dasar

> Посмотри в исходники Linux или FreeBSD.
Там есть Handle-ы плюс функции, которые оперируют с этими handle-ами.
Фактически это тот же ОО, только без syntactic sugar.

Dasar

> Потому что думают они по-другому.
Но, почему, я могу обяснить (по крайней мере пытаюсь что дает ООП, а ты не можешь объяснить, что дает ФЯ?
Это тоже "думать по другому"?

Dasar

Спасибо, посмотрю, но уже позже.
Пока стандартный вопрос на засыпку, что возвращает (какой тип) функция "растянуть по оси-x", если ее применить к кругу или эллипсу?
какой тип будет в результате, если к кругу применить последовательно операции: растянуть по осиX в два раза, сжать по осиX в два раза?

Papazyan

>Допустим сначала был тип круг, а мы к нему применили операцию изменить радиус по осиX, в результате тип должен измениться на тип эллипс.
А как это выглядит на C# или там С++?

sergey_m

> Посмотри в исходники Linux или FreeBSD.
Там полно ОО
Так что пример плохой.
Ну и отлично. Там же не только ОО. Требовались примеры, где ОО лишнее - вот примеры.

Dasar

> Ну и отлично. Там же не только ОО. Требовались примеры, где ОО лишнее - вот примеры.
Тогда говори точнее. Иначе получается "иди туда не знаю куда, но там где-то точно есть места, где ОО нет".

sergey_m

> Ну и отлично. Там же не только ОО. Требовались примеры, где ОО лишнее - вот примеры.
Тогда говори точнее. Иначе получается "иди туда не знаю куда, но там где-то точно есть места, где ОО нет".
Такие места там сильно преобладают.

Dasar

> А как это выглядит на C# или там С++?
Средствами языка тоже никак. Потому что C# и C++, напрямую, тоже поддерживают только те операции, которые не выводят тип из поля.
Но на smalltalk-е ("правильный" ОО-язык) это решается, через динамическую типизацию, и изменение типа объекта
вот цитата на эту тему
Рассмотрим класс "эллипс". Этот класс может обозначать две разные сущности:
1. Элиппс, не являющейся кругом. Или другими словами - это эллипс без вырожденных случаев.
2. Эллипс с учетом всех вырожденных случаев. Фактически такой эллипс должен содержать поведение и для таких вырожденных случаев, как круг, точка и может быть такие вырожденные случаи, как "плоскость"(эллипс бесконечного радиуса "отрезок" (эллипс нулевой длины и какой-то ширины "прямая" (эллипс нулевой длины и бесконечного радиуса
"полоса" (эллипс какой-то ширины и бесконечной длины).
Теперь поговорим об интерфейсах для данного случая.
Интерфейсы получаются следующие:
Не вырожденный эллипс ( 0 < ширина < бесконечность, 0 < высота < бесконечность, ширина != высота)
Круг
"Точка"
"Плоскость"
"Полоса"
"Отрезок"
Обобщенный эллипс
Рассмотрим интерфейс "круг". Здесь тоже возможны два разных интерфейса, которые скрываются под одним словом "круг".
С одной стороны - это интерфейс, который поддерживает все операции доступные над кругом, в том числе и растяжение по одной из оси, с другой стороны - возможен интерфейс, который допускает только те операции, результат которых остается в поле "круг" (т.е. в результате после операции круг остается кругом).
рассмотрим интерфейс "обобщенный эллипс".
Например, метод "Дай оси симметрии". такой метод в отличии от такого же метода для невырожденного эллипса, должен возвращать не только пару осей, как для невырожденного эллипса, но и должен уметь возвращать множество из бесконечного числа осей симметрии, т.к. у частного случая "круг" именно такой набор осей симметрии.
Или возьмем метод "Дай больший радиус", если для невырожденного эллипса такой метод имел смысл, то для обобщенного эллипса - этот метод уже может заканчиваться ошибкой, т.к. большего радиуса у вырожденных случаев (круг/точка) просто нет.
Получается, что когда мы говорим про интерфейс "обобщенный эллипс" мы также подразумеваем два разных интерфейса: один интерфейс - это операции, которые доступны над каждым вариантом эллипса, второй интерфейс - это набор операций, которые доступны хотя бы над одним вариантом эллипса.
Компоненты не имеют право, напрямую, ссылаться на типы-реализации (иначе получаем нарушение инкапсуляции и нарушение полиморфизма). Компоненты имеют право только пользоваться вышеприведенными интерфейсами.
Теперь вернемся к наследованию, как я уже вышеупомянул, термин "наследование" в первую очередь означает наследование реализации.
Рассмотрим класс-реализацию "обобщенный эллипс".
Этот класс должен реализовывать все вышеуказанные интерфейсы, а их у нас получилось, как минимум 12 штук.
Т.е. получается, что класс-реализация "обобщенный эллипс" содержит реализации интерфейсов "круг", "точка", "невырожденный эллипс" и т.д.
Рассмотрим класс-реализацию "круг".
Этот класс содержит 3 реализации интерфейсов: класс-реализация "точка", класс-реализация "круг с операциями из поля круг", класс-реализация "круг с операциями, выводящие из поля круг".
Теперь рассмотрим наследование реализаций.
Наследовать мы можем, как класс-реализацию "круг" от класс-реализации "обобщенный эллипс", так и "обобщенный эллипс" от "круга".
-- наследование класса-реализации "обобщенный эллипс" от класса-реализации "круг" --
Здесь все просто. Обобщенный эллипс добавляет реализацию тех методов, которые не были реализованы в круге.
-- Наследование класса-реализации "круг" от класса-реализации "обобщенный эллипс". --
Вот мы и добрались до самого интересного.
В данном случае такое наследование тоже может быть. Класс-реализация "круг" после наследования от класса-реализации "обощенный эллипс" отключает ненужные ему реализации, оставляя только необходимые.
В данном случае, нет нарушений правил Лисковой, потому что внешние компоненты не имеют права ссылаться на класс-реализации, они имеют право только ссылаться на интерфейсы.
А для всех внешних компонентов, данный класс-реализация выглядит как правильная класс-реализация "круг"-а.
И для внешних компонентов такое наследование совершенно прозрачно.
Поговорим чуть-чуть о динамической типизации.
Как мы уже выше убедились, у нас есть интерфейсы, которые оставляют класс в том же поле, что и до операции, но есть также и операции, которые переводят класс из одного поля в другое.
Если программе достаточно интерфейсов первого рода, то можно обойтись статической типизацией, а также тем, что объект не меняет набор поддерживаемых интерфейсов по ходу работы.
Если же нам нужны и интерфейсы второго рода и не достаточно интерфейсов первого рода, то необходимы также и динамической типизации, а также изменение набора поддерживаемых интерфейсов у объекта по ходу работы.
Все текущие индустриальные языки (C++, Java, C#) довольствуются интерфейсами только первого рода, и не поддерживают, напрямую, интерфейсы второго рода.

Papazyan

Да, кстати. Ты упираешь на ООП, но это только один, причем не самый лучший, из способов описывать мир. Т.е. берем мяч и говорим - у него есть радиус, его можно накачать, он из кожи и т.п. Но можно смотреть на это совсем с другой точки зрения - воспринимать мир, как совокупность связей между объектами. Т.е. не воспринимать мяч, как некую отдельную сущность, а воспринимать его только по отношению к себе - т.е. не мяч желтый, а мяч меня желтит, не мяч круглый, а мяч меня круглит, не мяч можно накачать, а я накачиваю мяч и т.п.
ФЯ - основываются на теории категорий, которая как раз и предлагает такой взгляд на мир. Теория категорий концентрируется не на объектах-множествах (как теория множеств а на функциональных связях между ними, сущность объектов не играет никакой роли. Это дает новый уровень абстракции.

Dasar

> Такие места там сильно преобладают.
Приведи законченный пример.
ps
иначе у нас неравноценные позиции, тебе нужно доказать, что в Linux-е есть хоть один кусок куда без ООП, а мне надо доказать, что в Linux-е все(большинство) куски кода использует ООП.
насколько я помню математику, доказать второе в реальный условиях почти невозможно.

sergey_m

Приведи законченный пример.
IP и TCP/IP стэк src/sys/netinet в любой BSD. Нет намеков на ОО. Можно посмотреть через CVSweb на www.freebsd.org или www.openbsd.org

Chupa

Кстати, прикольный подход есть к описанию всяких
лингвистических конструкций в функциональном стиле:
applicative universal grammar.
Там элементы языка типизированы наподобии ФЯ,
например, существительное имеет тип T,
предложение - S, прилагательное - (T->T
глагол (T->S а всякие вспомогательные конструкции
ещё более сложные абстрактные типы.
В результате "белая кошка" это "белый(кошка)", а не "кошка.setColor(белый)".
Таким образом, наделить объект дополнительным свойством можно не
внося изменений в сам объект, что больше соответствует реальному миру,
где объекты остаются одими и теми же, а свойствами их наделяют люди
по мере того, как начинают их различать и придавать им значение.

Dasar

> ФЯ - основываются на теории категорий
где это в ФЯ проявляется?
Допустим у меня мяч относится к категории физический предмет (доступно состояние: положение в пространстве, размер; операции: передвинуть, изменить размер и т.д. а также относится к категории товар (у него есть цена, его можно продать и т.д.)
Как это будет записываться на ФЯ?
> Это дает новый уровень абстракции.
Пока это не увидел. В некотором смысле, это те же грани одного объекта, если в терминах ООП.
Приведи, плиз, какой-нибудь пример.

Darion

Пока стандартный вопрос на засыпку, что возвращает (какой тип) функция "растянуть по оси-x", если ее применить к кругу или эллипсу?
какой тип будет в результате, если к кругу применить последовательно операции: растянуть по осиX в два раза, сжать по осиX в два раза?
В ML, как и в С (огромный ему за это пинок под его сишный зад) параметры в функции передаются только по значению. В паскале есть такое ключевое слово var, которое означает, что параметр передается не по значению, а по имени (по-моему, это называется так, хотя я могу и ошибаться). В идеале, в функциональном языке ссылок быть не должно, поэтому получать результат через парамерты, и, тем более, но это уже в силу передачи по значению, менять их значения — нельзя. Вообще, __изменить__ в функциональных языках ничего нельзя! (Знатокам ML и ocaml — типы ссылки ('a ref которые все могут очень сильно испортить, по моему мнению просто позволяют схитрить и выйграть время ценой красоты кода. Это мусор в ML, так же, как и исключения. Все это для любителей императива, которые готовы брать МЛ только за его паттерн-мэтчинг).
В идеале, от которого ML на самом деле совсем недалеко, результат функция должен возвращаться как значение. Соответственно, функция, которая растягивает или сжимает эллипс должна вернуть новый эллипс, на котором все преобразования проделаны. ML для этого оптимизирован, так что никаких накладок по поводу нерационального использования памяти не возникнет. Более того, это и есть парадигма ФП. Огромнейший плюс ФП как раз в том, что у функции нет никаких сторонних эффектов, то есть, например, в ML, если не использовать фичи императивного подхода, а они там, к сожалению, есть, как я уже говорил выше, можно быть уверенным, что функция ничего не сделает лишнего, только вернет результат. Да даже в случае с использованием МЛ-ных имперетивных референсов, можно быть уверенным за нереференсные переменные, значение которых можно "изменить", только переопределив их в их области видимости или во вложенной.
Функции ввода-вывода реализованы на очень низком уровне и являются скорее не частью библиотеки, а частью языка. На самом деле, это, как посмотреть, но смотреть именно так очень выгодно. Как результат своей работы, они возвращают unit. Можно, конечно, написать функцию вычисления факториала, которая попутно бы срала мегабайтами на диск ЦЭ или меняла бы файлы в system32, но это будет не ошибка программиста, а банальное хулиганство. Язык от хулиганов страховать не должен. Это задача ОС. В остальном, криворукие программисты просто не смогут скомпилировать код до тех пор, пока не поймут суть проблемы.
------
вот еще одна ссылка, должно быть, рабочая:
http://www.fors.biz/fors/docs/english/p-j_engl.html?view=default_english

Papazyan

>Как это будет записываться на ФЯ?
Никак. Поскольку совершенно неважно какими свойствами обладает объект сам по себе. Нам интересно, как он взаимодействует с другими объектами. Мяч, например, можно пнуть. Получаем два объекта - нога и мяч. К какому из них должно относиться действие "пнуть"? К обоим - нельзя, лишняя функциональность, а если выбрать только один, то возникает вопрос, а почему не другой? Кроме того, мяч можно не только пнуть, но и кинуть, покатить и т.п. А ногой можно не только пинать, но и шагать, прыгать. И как здесь применить ООП?
В ФЯ мы бы не мучались, а определили бы полиморфную функцию пинать с двумя аргументами.

freezer

запятую лучше, вообще, стараться не использовать, потому что она приводит к довольно трудновидимым глюкам

тогда надо так:


int f1[3];
int f2[3];
f1[0]=1;
f1[1]=4;
f[2]=2;
f2[0]=3;
f2[1]= -4;
f2[2]=1;



ни одной запятой
В больших приложения за такое убивают.

а если везде std:: писать, то в больших проектах от этого сами помирают
если боишься пересечений - пиши using внутри функции.
тем более данной кусок изменяет семантику оператора запятая

угу, есть такой недостаток. Но как я понял, ты этим оператором и так не пользуешься.

Dasar

Статически полиморфную можно написать и на C++:


void Пнуть (Мяч, НогаВБутце){}
void Пнуть (Шкаф, ГолаяНога){}


Но вот что делать с динамическими типами?
объяснение, откуда берутся динамические типы, я уже приводил вверху.

Chupa

> Вообще, __изменить__ в функциональных языках ничего нельзя!
И тем не менее, на них можно делать императивщину,
причём иногда достаточно эффективно.
"Imperative Functional Programming", Wadler, Jones, 1993
http://www.research.microsoft.com/Users/simonpj/Papers/imperative.ps.Z

Papazyan

> В некотором смысле, это те же грани одного объекта, если в терминах ООП.
Приведи, плиз, какой-нибудь пример.
Я могу сказать только, что при использовании теории категорий существенно упрощается описание свойств алгебраических объектов. Там как раз неважно, что за группа, кольцо, модуль конкретно изучаются, важны некоторые общие свойства присущие некоторому классу объектов.

Papazyan

>Но вот что делать с динамическими типами?
>объяснение, откуда берутся динамические типы, я уже приводил вверху.
ХЗ, что с ними делать. Нужен конкретный пример.
Например, когда я писал компилятор, то в результате парсинга получалось дерево с различными видами вершин. Реализовывать каждый вид вершины отдельной структурой - нерационально, поскольку структура дерева будет повторена аж 3 раза - в парсере, в иерархии структур для вершин и функциях обходящих дерево, в то время, как достаточно одного парсера. В случае изменения дерева изменения пришлось бы вносить в 3 местах. Поскольку в SML строгая типизация и нет никаких динамических типов, то единственный вариант был их сымитировать, т.е. в каждой вершине хранить список подвершин с идентификаторами типов. В результате функция, которая обрабатывала дерево занимала несколько строчек, я ей передавал аргументы-функции, которые реагировали только на нужные вершины. Было довольно удобно.

Darion

можно даже написать "универсальное дерево", что-то типа XML-дерева, и пихать туда все что угодно. Продолжая таким образом, можно остановиться только на "правильном" заполнении дерева при имеющихся универсальных функциях его обхода. Но в этом случае сам процесс "правильного" заполнения может стать гораздо сложнее программирования обхода или изменения каких-то небольших участков кода. Золотая середина? Нет золотой середины. Это коммерческая уловка. Но мозги есть всегда. Написать с первого раза правильное дерево настолько же важно, как и придумать схему данных в СУБД. А можно и блобами, как написано в соседнем треде. Прелесть МЛя и в том, что при любой сложности очень легко вносить изменения в проект. Только бы не было императивщины.

Papazyan

Ты прав. У меня и было "универсальное" дерево с однотипными вершинами. Проблема с ним в том, что трудно обеспечить правильный порядок подвершин в списке и сам доступ к ним затруднен, поскольку нужно перебирать все подвершины, чтобы найти нужную. Но, я считаю, что такие неудобства полностью компенсировались простотой обхода дерева. К тому же, эти неудобства можно было бы уменьшить, а то и вообще скрыть автоматической генерацией кода по псевдоязыку проверки и модификации дерева. К сожалению, когда мне пришла в голову эта идея, я уже уволился с этого проекта.

shlyumper

еще туда же:
openjade

Chupa

Добавлю, что AUG очень сильно изменило мои представления
об устройстве естественных языков и возможности их обработки.
Знание ООП мне в этом плане практически ничего не дало,
разные мелочи возможной реализации нижнего уровня
просто не позволяли увидеть, как всё красиво и естественно
может получиться сверху. Причём в первую очередь,
именно из-за запихивания свойств внутрь объектов,
как предписывает ОО подход.
Интересно, как в ABBYY с ЕЯ работают?

yaantonio

Интересно, как в ABBYY с ЕЯ работают?
Будь осторожнее, а то за могут и покарать.

Aleksei66

А почему интересно программисты АББИИ поставлены в ФАКе на один уровень с Биллом Гейтсом?

borneo5

Т-система -- среда программирования с поддержкой автоматического динамического распараллеливания программ.
Для реализации концепции автоматического динамического распараллеливания программ в Т-системе предложена новая модель организации вычислительного процесса, основанная на следующих базовых принципах:
В качестве основной парадигмы рассматривается функциональное программирование. Программа представляет собой набор чистых (без побочных эффектов) функций. Каждая функция может иметь несколько аргументов и несколько результатов. В то же время тела функций могут быть описаны в императивном стиле (на языках типа FORTRAN, C и т.п.) Важно только, чтобы:
Всю информацию извне функция получала только через свои аргументы;
Вся информация из функции передавалась только через явно описанные результаты.
По этой ссылке подробнее о том что наверху:
http://www.ctc.msiu.ru/program/t-system/first/node15.html
По этой коммерческое применение:
http://skif.pereslavl.ru/skif/
Ксати люди принимающие участие в разработке этой системы работают и преподают на мехмате.

Dasar

> В ФЯ мы бы не мучались, а определили бы полиморфную функцию пинать с двумя аргументами.
Тут есть вот такая проблема: как быть, если компилятор обнаруживает, что у него есть несколько путей преобразования?
Возьмем те же коллекции.
Допустим у нас есть коллекция с индексным доступом (например, коллекция, которая находится в памяти и коллекция с последовательным доступом (например, коллекция, которая находится на диске).
Для коллекция с индексным доступом также доступен последовательный доступ.
Далее мы можем написать преобразование, которое обеспечивает индексный доступ к последовательной коллекции
Так же у нас есть две сортировки: одна для последовательного доступа, другая - для индексного доступа.
Внимание, вопрос:
Какую сортировку и почему должен выбрать компилятор, если в функцию сортировки передается коллекция, которая поддерживает и индексный доступ, и последовательный доступ?

Dasar

> IP и TCP/IP стэк src/sys/netinet в любой BSD. Нет намеков на ОО.
А вот это что?
int in_broadcast(struct in_addr, struct ifnet *);
int in_canforward(struct in_addr);
int in_cksum(struct mbuf *, int);
int in4_cksum(struct mbuf *, u_int8_t, int, int);
void in_delayed_cksum(struct mbuf *);
int in_localaddr(struct in_addr);
void in_socktrim(struct sockaddr_in *);
char *inet_ntoa(struct in_addr);
Все тоже самое. Есть структура, и есть операции над этой структурой - фактически опять же объявляем объект.

sergey_m

Извини, если Сшные структуры считать объектами, то не OO языком останутся наверное только BASIC и asm.
P.S. Особенно мне прет считать struct in_addr объектом

Dasar

И чем этот In_Addr Отличается от вот такого класса: ?


public class IPAddress
{
private static IPAddress;
public IPAddress(byte[] address);
public IPAddress(byte[] address, long scopeid);
internal IPAddress(int newAddress);
public IPAddress(long newAddress);
public override bool Equals(object comparand);
public byte[] GetAddressBytes;
public override int GetHashCode;
public static short HostToNetworkOrder(short host);
public static int HostToNetworkOrder(int host);
public static long HostToNetworkOrder(long host);
internal bool IsIPv4Compatible;
internal bool IsIPv4Mapped;
internal bool IsIPv6LinkLocal;
internal bool IsIPv6Multicast;
internal bool IsIPv6MulticastGlobal;
internal bool IsIPv6MulticastLinkLocal;
internal bool IsIPv6MulticastNodeLocal;
internal bool IsIPv6MulticastOrgLocal;
internal bool IsIPv6MulticastSiteLocal;
internal bool IsIPv6SiteLocal;
public static bool IsLoopback(IPAddress address);
public static short NetworkToHostOrder(short network);
public static int NetworkToHostOrder(int network);
public static long NetworkToHostOrder(long network);
public static IPAddress Parse(string ipString);
public override string ToString;
public long Address { get; set; }
public AddressFamily AddressFamily { get; }
internal bool IsBroadcast { get; }
public long ScopeId { get; set; }
public static readonly IPAddress Any;
public static readonly IPAddress Broadcast;
internal const string InaddrNoneString = "255.255.255.255";
internal const string InaddrNoneStringHex = "0xff.0xff.0xff.0xff";
internal const string InaddrNoneStringOct = "0377.0377.0377.0377";
public static readonly IPAddress IPv6Any;
public static readonly IPAddress IPv6Loopback;
public static readonly IPAddress IPv6None;
public static readonly IPAddress Loopback;
internal const long LoopbackMask = 127;
internal long m_Address;
private AddressFamily m_Family;
private int m_HashCode;
private ushort[] m_Numbers;
private long m_ScopeId;
public static readonly IPAddress None;
internal const int NumberOfLabels = 8;
private static bool s_Initialized;

}



Отличия только в синтаксисе вызовов.

Dasar

> то не OO языком останутся наверное только BASIC и asm
http://www.wasm.ru/srclist.php?list=8

sergey_m

не надо притворяться, что ты не видишь разницы между структурой и объектом.
И чем этот In_Addr Отличается от вот такого класса: ?
Сделай diff:


struct in_addr {
in_addr_t s_addr;
};

Dasar

ООП есть в любых программах на любых языках.
но явное объявление объектов дает нам полезный Syntactic shugar, который очень удобен при разработке больших программ, т.к. позволяет сразу определить какие операции и свойства доступны для данного объекта в данный момент.

Dasar

Чем отличается


struct in_addr
{
in_addr_t s_addr;
};
char *inet_ntoa(struct in_addr);


от


class in_addr
{
public:
in_addr_t s_addr;
char *inet_ntoa;
};


?
Вызовы
inet_ntoa(in_addr);
и
in_addr.inet_ntoa;
даже один и тот же asm-код генерируют.

Chupa

> ООП есть в любых программах на любых языках.
Да. Нужно просто уметь это видеть.
То же самое относится и к чистым функциям.
Суслик есть.
> но явное объявление объектов дает нам полезный Syntactic shugar,
> который очень удобен при разработке больших программ,
> т.к. позволяет сразу определить какие операции и свойства
> доступны для данного объекта в данный момент.
"Удобство" - это не более чем согласованность
со стереотипами и прочими окаменелостями в мозгах.
Удобство ограничивает возможности, а не расширяет их.
"Полезность" для "больших" проектов весьма спорна.
Ты прочитал lisp success story? Почему там так получилось?

Dasar

> Да. Нужно просто уметь это видеть.
Согласен.
> То же самое относится и к чистым функциям.
Тоже согласен.
Архитектура (каркас приложения) - это в первую очередь объекты/сущности. Попробуйте описать хоть что-нибудь не используя ни одного существительного, а ведь в речи, как раз существительное указывает на наличие явного или не явного объекта.
Поэтому я и говорю, что объекты именно в большом проекте полезны, потому что позволяют видеть архитектуру приложения явно в коде.
Функции - это преобразование данных/объектов.
> "Удобство" - это не более чем согласованность
> со стереотипами и прочими окаменелостями в мозгах.
> Удобство ограничивает возможности, а не расширяет их.
Совсем не согласен.
Удобство позволяет сосредоточится на главном, держать в памяти действительно важные вещи, позволяет уменьшить время разработки, уменьшить кол-во ошибок, в конце концов, уменьшить стоимость разработки.

Marinavo_0507

> Архитектура (каркас приложения) - это в первую очередь объекты/сущности.
Только если ты так захочешь.
> Попробуйте описать хоть что-нибудь не используя ни одного существительного, а ведь в речи,
> как раз существительное указывает на наличие явного или не явного объекта.
В языке процесс может выражаться как глаголом, так и существительным (номинализация).
В ФП функции являются данными, что позволяет рассматривать их не только как процессы,
но и как сущности. Процедурное программирование и ООП стараются игнорировать эту особенность.
> Функции - это преобразование данных/объектов.
... и кроме того, сами могут являться данными.
Свойства, принадлежащие якобы объектам, отражают лишь наше восприятие этих объектов.
Всё, что мы знаем про объекты, является результатом нашего взаимодействия с ними,
т.е. наблюдений. Приписывать это самим объектам - лишь один из способов мышления,
очень часто к тому же приводящий к парадоксам.
Теперь - о мутабельности.
Это тоже отражает наше восприятие времени, которое, как известно из физики, относительно.
Всё, что мы знаем об объектах - результаты наблюдений, т.е. данные.
Причём они в некотором смысле, вечны - мы можем про них забыть (как GC в ФЯ
но можем и хранить столько, сколько захотим.
Данные, полученные "только что", принципиально ничем не хуже данных, полученных "давно".
Объявление какого-то из возможных наборов данных "текущим состоянием" объекта, как это
нужно делать в ООП, субъективно.
Даже SQL-базы, приводимые в качестве образца императивности, поддерживают конкурентные
транзакции, в каждой из которых наблюдаемое состояние - своё.
> Удобство позволяет сосредоточится на главном, держать в памяти действительно важные вещи,
> позволяет уменьшить время разработки, уменьшить кол-во ошибок, в конце концов, уменьшить стоимость разработки.
Инвалиду костыль позволяет быстрее и надёжнее ходить, и является для него удобством.
Но вот здоровому человеку он только мешает при ходьбе.

Chupa

> Архитектура (каркас приложения) - это в первую очередь объекты/сущности.
Архитектура - это не объекты, а взаимосвязи между ними (Аристотель vs Гегель ).
Собственно, в этом и состоит основное отличие
ООП ("всё является объектом") от ФП ("всё является функцией").
> Попробуйте описать хоть что-нибудь не используя ни одного существительного,
> а ведь в речи, как раз существительное указывает на наличие явного или не явного объекта.
Именно на наличие. А все "свойства" у такого объекта снаружи и не имеют значения,
пока явно где-нибудь не понадобятся.
> Поэтому я и говорю, что объекты именно в большом проекте полезны,
> потому что позволяют видеть архитектуру приложения явно в коде.
Взаимосвязи между объектами видеть тяжело.
> Функции - это преобразование данных/объектов.
Функция - это в первую очередь не пребразование,
а некоторое отношение между сущностями.
Причём до некоторого момента может не иметь значения,
как именно это отношение и сами сущности должны
быть устроены внутри.
>> "Удобство" - это не более чем согласованность
>> со стереотипами и прочими окаменелостями в мозгах.
>> Удобство ограничивает возможности, а не расширяет их.
>
> Совсем не согласен.
> Удобство позволяет сосредоточится на главном,
> держать в памяти действительно важные вещи,
> позволяет уменьшить время разработки, уменьшить
> кол-во ошибок, в конце концов, уменьшить стоимость
> разработки.
Я не вижу здесь противоречия.
Если инструмент и подход выбраны правильно, то так оно и есть.
Только вот далеко не всегда так бывает, и "действительно важных
вещей" может только прибавиться из-за того, что удобство есть
совсем не там, где надо.

Dasar

> В ФП функции являются данными, что позволяет рассматривать их не только как процессы,
но и как сущности. Процедурное программирование и ООП стараются игнорировать эту особенность.
Что в том же C-и нельзя сделать такого с функцией, что можно сделать с обычными данными?
ps
Хотя да, у C-и есть недостаток - функция не может быть объявлена внутри другой функции.
Но возьмем тот же SmallTalk - самый объектный язык, там то чего нет?
> Инвалиду костыль позволяет быстрее и надёжнее ходить, и является для него удобством.
> Но вот здоровому человеку он только мешает при ходьбе.
Почему ты взял именно костыль? Почему ты не взял для примера: велосипед, машину и т.д.?

Marinavo_0507

> Но возьмем тот же SmallTalk - самый объектный язык, там то чего нет?
Несмотря на то, что он "самый объектный", в вашем мейнстриме он не котируется, так?
Вряд ли потому, что там чего-то нет (про это я ничего сказать не могу, почти ничего не знаю о нём).
В моём понимании, он довольно похож на лисп, только структуры данных и синтаксис менее регулярные.
> Почему ты взял именно костыль? Почему ты не взял для примера: велосипед, машину и т.д.?
Кому нужен костыль, велосипед не поможет, и машина ему подойдёт только специальная.
Мышление же более пластично, ограничение сознания можно преодолеть,
гораздо легче, чем ампутацию ноги, например.

Dasar

> Именно на наличие. А все "свойства" у такого объекта снаружи и не имеют значения,
пока явно где-нибудь не понадобятся.
Состояние таких наружных свойств где хранится?

Dasar

> Несмотря на то, что он "самый объектный", в вашем мейнстриме он не котируется, так?
Да, в "нашем" mainstream-е не котируется. В целом, опять же по тем же причинам: тяжело стыковать с этим самым MainStream-ом.
Но есть мнение, что Smalltalk рулит как раз в написании сложных системах с большим кол-вом часто меняющихся требований.
"Ноги" многих методик и подходов растут именно из smalltalk-а
> Вряд ли потому, что там чего-то нет (про это я ничего сказать не могу, почти ничего не знаю о нём).
В Smalltalk-е нет статической типизации. Причем совсем нет - это мешает выжимать соки из производительности, т.к. даже критические к производительности части кода сложно оптимизировать на нативном уровне.
> В моём понимании, он довольно похож на лисп, только структуры данных и синтаксис менее регулярные.
имхо, в Smalltalk-е только два основных понятия - это объект и сообщение.

sergey_m

Вызовы
inet_ntoa(in_addr);
и
in_addr.inet_ntoa;
даже один и тот же asm-код генерируют.
Ну и что? Это ж не доказывает, что структура обладает всеми св-вами объекта.

Marinavo_0507

Именно так принято отображать ОО на Си, если ты не знал

Ivan8209

Нет, не устроит.
Какое значение вернула transform (где, кстати, оно?)?
А должна вернуть vector.
Именно вот так:


let vec_res = map (+) vec1 vec2; (* SML *)
(set! vec-res (map + vec1 vec2 ;; Scheme


и никак иначе.
То есть, вектор должен быть вовзращён _значением_,
а не побочным эффектом.
Все ваши хвалёные transform --- это Фортран, только вид с другой стороны.
Опять же, как ты напишешь (fold + 0 (map * x y?
(Примечание: определение fold по SRFI-1.)
---
...Я работаю антинаучным аферистом...

Ivan8209

Точно так же.
Плюс можно переопределить.
Пущай сразу пары чисел складывает.


(define old-+ +)
(define (+ a b)
(cond number? a) (+ (cons a 0) b
number? b) (+ a (cons b 0
(else (cons (old-+ (car a) (car b (old-+ (cdr acdr b


---
...Я работаю антинаучным аферистом...

Ivan8209

CLOS --- одна из лучших в мире ОО систем.
Ты будешь работать с тем, что хочешь видеть.
Знаком с понятием "фрейм?"
Это появилось давно.
Так что и ООП можно считать лисповским изобретением.
Само ООП очень ограничено по определению, поскольку невозможно работать уже с двумя _равноправными_ объектами.
А если их три?
Или четыре?
Число Ингве, всё-таки, не равно одному.
Собственно, и "compiler," и "linker," и "assembler" представляют собой одно и тоже --- сборщик.
Только эти сборщики работают на разных уровнях.
---
...Я работаю антинаучным аферистом...

Ivan8209

> ФП ("всё является функцией").
Радикальный подход.
Обычно под ФП понимают более мягкое "аппликативное" программирование.
Комбинаторные замашки навроде Хаскелла --- более новая ветка.
---
...Я работаю антинаучным аферистом...

Ivan8209

> Попробуйте описать хоть что-нибудь не используя ни одного существительного,
> а ведь в речи, как раз существительное указывает на наличие явного или не явного объекта.
А глаголы появились в речи раньше существительных.
Ты этого не знал, верно?
Трудность ОО подхода заключается в том, что делается попытка описать действия почти исключительно с помощью простых предложений с жёстко выделенным единственным подлежащим.
Что делать, когда подлежащих должно быть два или три, не говорится.
Как будто и не бывает такого.
И оттого имеем суровое ограничение на мощность выражений.
---
...Я работаю антинаучным аферистом...

Ivan8209

Создать функцию.
---
...Я работаю антинаучным аферистом...

Dasar

> А глаголы появились в речи раньше существительных.
> Ты этого не знал, верно?
AFAIK, ты ошибаешься. Глаголы являются более высокой абстракцией, чем существительные.
У детей, например, сначала появляются существительные, и только потом глаголы.
> Трудность ОО подхода заключается в том, что делается попытка описать действия почти исключительно с помощью простых предложений с жёстко выделенным единственным подлежащим.
Приведи пример таких трудностей.

Dasar

Что значит "нельзя создать функцию"?
Напрямую ты функцию и на лиспе не создашь, ты ее сможешь только собрать из кусочков.
Но из кусочков можно собрать функцию и в C++.

Dasar

> Само ООП очень ограничено по определению, поскольку невозможно работать уже с двумя _равноправными_ объектами.
Пример, плиз.

Dasar

fold:


template<typename Function, typename Result, typename Source>
Result fold(Function function, Result initialValue, list<Source> items)
{
Result res = initialValue;
foreach (Source item in items)
{
res = function(res, item);
}
return res;
}


Соответственно, например, transform через fold:


template<typename Result, typename Function, typename Source>
list<Result> transform(Function function, std::list<Source> items)
{
return fold(delegate(list<Result> items, Source item) {items.add(function(item;},
new list<Result> items);
}

Ivan8209

>> А глаголы появились в речи раньше существительных.
>> Ты этого не знал, верно?
> AFAIK
Плохо знаешь.
Самые первые, самые древние слова --- глаголы повелительного наклонения.
> У детей, например, сначала появляются существительные,
> и только потом глаголы.
Угу. Хорошее такое существительное --- "дай!"
> Приведи пример таких трудностей.
Любое действие наподобие сложения, сцепления.
Тот же "+" для комплексных чисел, умножение для разных там матриц, сцепление и слияние списков и проч.
---
...Я работаю антинаучным аферистом...

Dasar

Еще раз повторю свою основную мысль:
у ФП мощность языковых средств не выше, чем у нормального объектно-ориентированного императивного языка, т.к. единственная разница - это замена цикла хвостовой рекурсией.
Единственный плюс ФП - это возможность за пять копеек написать простой транслятор (интерпретатор, компилятор) для функционального языка. Этот плюс достигается за счет принудительного убеднения синтаксиса языка.

Dasar

> Плохо знаешь.
> Самые первые, самые древние слова --- глаголы повелительного наклонения.
До этого появляются местоимения. Такое местоимение может заменяться тыканьем пальца. Если пальцев нет, то местоимение звучит в явном виде.

Dasar

> Любое действие наподобие сложения, сцепления.
> Тот же "+" для комплексных чисел, умножение для разных там матриц, сцепление и слияние списков и проч.
см. понятие functor.

Ivan8209

Нет ни одной операции, вовзращающей значение типа "функция."
Ты не можешь объявить функцию литералом.
Ты даже не можешь написать (fold + чего-то-там).
Потому что "+" --- это якобы не функция.
Тебе придётся делать затычку наподобие "int plus(int a, int b) {return a+b;}"
В Лиспе функция --- это список.
В Схеме функция --- это то, что получается от вычисления списка для лиспа.
В Сях "функция" --- это указатель.
Только ты не сможешь разместить в памяти ничего полезного,
если не поработаешь компилятором.
---
...Я работаю антинаучным аферистом...

Dasar

продолжение основной мысли:
т.к. мощность языковых средств у ФП не выше, чем у ОО ИП, то значит ФП никакого рывка не может дать в принципе по сравнению с ИЯ.
Замечу, что у декларативных языков, как раз такой потенциал есть, есть надежда, что при накоплении определенной базы декларативный подход позволит резко прыгнуть в разработке ПО.

Ivan8209

> у ФП мощность языковых средств не выше,
> чем у нормального объектно-ориентированного императивного языка,
> т.к. единственная разница - это замена цикла хвостовой рекурсией.
ОО можно убрать без всяких ограничений.
> Единственный плюс ФП - это возможность за пять копеек написать
> простой транслятор (интерпретатор, компилятор)
> для функционального языка.
> Этот плюс достигается за счет принудительного убеднения синтаксиса языка.
Это ты только про Лисп или про все?
Тебе уже указали вещи, которые на порядок сложнее для ИЯ, чем для ФЯ: доказательство корректности, распараллеливание, оптимизация.
---
...Я работаю антинаучным аферистом...

Ivan8209

Мне лень искать ссылки.
Но относительно глаголов повелительного наклонения я прав.
Можешь исследовать этот вопрос.
---
...Я работаю антинаучным аферистом...

Ivan8209

> т.к. мощность языковых средств у ФП не выше, чем у ОО ИП,
> то значит ФП никакого рывка не может дать в принципе по сравнению с ИЯ.
Есть такие слова "семантический разрыв."
Мышление куда более привязано к глаголу, как это ни странно, чем к предметам.
Любой человек пытает машину словом "дай" и "делай,"
то есть описывает _действие_.
Одно только это показывает, что ОО --- это переворачивание с ног на голову.
Если ещё не обратил внимания, то посмотри,
что "сложить произведения пар", через "(fold 0 (map + x y" описывается куда более естественно, чем через

for(i=0,a=0; i<чего-то-там; i++) a+=x[i]*y[i];


> Замечу, что у декларативных языков, как раз такой потенциал есть,
> есть надежда, что при накоплении определенной базы
> декларативный подход позволит резко прыгнуть в разработке ПО.
Декларативные --- это какие?
ФЯ тоже некоторыми относятся к декларативным.
---
...Я работаю антинаучным аферистом...

Dasar

> Ты даже не можешь написать (fold + чего-то-там).
Это синтаксис. Можно сделать, например, простой препроцессор, который все плюсы будет заменять на создание объекта plus.
в ФЯ тоже нельзя многое записать на уровне синтаксиса: взять те же самые структуры.
> Тебе придётся делать затычку наподобие "int plus(int a, int b) {return a+b;}"
ну, написал я один раз


template<class Left, class Right, class Result>
class plus
{
Result operator (Left left, Right right) {return Left + Right;}
}


вынес это в H-файл, и далее это код везде использую
и где обещанное тобой сильное ограничение?
> В Сях "функция" --- это указатель.
> Только ты не сможешь разместить в памяти ничего полезного,
> если не поработаешь компилятором.
Про функторы уже прочитал?
Покажи мне где в определении функтора встречается хоть раз слово "указатель".

Dasar

> Декларативные --- это какие?
Это те языки, в которых говорится, что надо сделать, а не как.
SQL - можно считать (с оговорками) за пример такого языка.
> ФЯ тоже некоторыми относятся к декларативным.
Я уже в рамках данного треда говорил каким боком ФЯ относится к декларативным языкам.

Dasar

> ОО можно убрать без всяких ограничений.
Нельзя, потому что в ИЯ нет понятия "список".
И данное понятие можно ввести в язык только при помощи объектов.

Ivan8209

Под ФЯ ты понимаешь Лисп или все ФЯ?
Что ты понимаешь под "структурами?"
Синтаксис, кстати, не такая уж маловажная вещь.
Он тоже немало влияет.
Именно потому, кстати, в Схеме отказались от имён вроде "quotient" в пользу более привычного "/".
Под функторами мы, видимо, понимаем разные вещи.
Что ты имеешь в виду?
В Сях, например, ты не сможешь сделать простой и понятной любому "шептателю" вещи: считать выражение с консоли (с диска и т.п.) и сделать функцию.
---
...Я работаю антинаучным аферистом...

Ivan8209

Если взять язык Бекуса, то он будет столь же декларативен, в твоём смысле, как SQL.
То есть, можно и Лисп урезать до такой степени.
---
...Я работаю антинаучным аферистом...

Ivan8209

Ссылочный тип отменили?
А обобщённый, абстрактный?
---
...Я работаю антинаучным аферистом...

Aleksei66

Блин, , если ты изучал только Лисп, то, говоря о ФЯ, мы говорим о совершенно разных вещах. Lisp и то, что обычно называют ФЯ, не имеют практически ничего общего. Прочитай руководство по Haskell'ю или OCaml'у, это не займет много времени, иначе спор становится бессмысленным после твоих слов
>в ФЯ тоже нельзя многое записать на уровне синтаксиса: взять те же самые структуры.
Ибо в ФЯ есть структуры. В OCamle есть все типы данных (если не считать различные типы целых чисел и т.п. муру что есть в С++.

Aleksei66

Еще раз повторю свою основную мысль:
у ФП мощность языковых средств не выше, чем у нормального объектно-ориентированного императивного языка, т.к. единственная разница - это замена цикла хвостовой рекурсией.
Единственный плюс ФП - это возможность за пять копеек написать простой транслятор (интерпретатор, компилятор) для функционального языка. Этот плюс достигается за счет принудительного убеднения синтаксиса языка.

Ну это совсем что-то странное. Рекурсия лишь одно из видимых невооруженным взглядом отличий в подходах, а вовсе не единственная разница. Никакого убеднения синтаксиса в принципе нет, ибо изначально для самого простого ФЯ требуется меньше ключевых слов и конструкций, чем для самого простого императивного. Потом языки усложняются и становятся все более монструозными, но их монструозность вовсе не означает качество. Взять, например, С++ и C# или Java.

sergey_m

Мне лень искать ссылки.
Но относительно глаголов повелительного наклонения я прав.
Можешь исследовать этот вопрос.

Извини, если ты настаиваешь на весьма спорном утверждении, то приводить ссылки твоё дело, а не оппонента. Иначе Ваш славный спор превратится в флейм.

Dasar

> Рекурсия лишь одно из видимых невооруженным взглядом отличий в подходах, а вовсе не единственная разница.
Голословное утверждение.
Факты или примеры будут?
> но их монструозность вовсе не означает качество
Опять голословное утверждение.
Где обоснование данного утверждения?

Aleksei66

Я не вижу смысла приводить факты и примеры, пока ты не познакомился хотя бы с одним из языков, о которых идет речь - ML, OCaml, Haskell. По всем есть книги (и)или мануалы.

Ivan8209

Основа --- получение выражения, а не осуществление действия.
Даже так ---- получение значения.
В частности, разница отразилась в требовании вовзращения значения функцией map.
И в названии "map," а не "transform."
Для того, чтобы понять независимость от рекурсии,
достаточно взглянуть на комбинаторное представление и на FP от Бекуса.
Замечание по поводу лингвистики (больше Глебу, чем тебе, но всё же).
Вопрос о глаголах повелительного наклонения прямого отношения к программированию не имеет, хотя любопытен сам по себе.
Достаточно того, что к машине обращаются именно "сделай" или "дай,"
что получило отражение в ранних ЯП именно императивного направления.
---
...Я работаю антинаучным аферистом...

rosali

Извиняюсь, что не осилил все 220 постов и прочитал лишь несколько десятков последних...
Господа, о чем спор ? И С++ и Haskell - алгоритмически полные языки. Когда встает вопрос о том, что в некоторых случаях один из языков _выразительнее_ другого, бессмысленно объяснять, как можно добиться того же на другом. И на С++ можно написать интерпретатор Haskell-я и наоборот, это само собой разумеется. Просто надо понимать, что для языка естественно, а что нет.
* В Haskell-е, например, очень удобно частичное применение (partial application то есть (<5) - это одноместный предикат, а (2-) - одноместная функция. Их можно передать параметром в какую нибудь функцию высшего порядка, filter, map, ...
* В Haskell-е есть понятие class (ничего общего с ООП с помощью которого пишутся, например, мультиметоды (функции, полиморфные по нескольким параметрам которых в ООП до сих пор нет.
* В Haskell-е очень мощная система типов. Помимо математической красоты она еще позволяет практически избежать отладки. Это большая редкость, когда правильно стипизированная программа на Haskell-е неправильно работает.
@ В Haskell-е _ужасно_ неудобно выражать понятие состояния. Монады и прочие безумства, Монадный ввод/вывод.
@ В Haskell-е весь полиморфизм статический. Точный тип любой переменной известен на момент компиляции.
...
В общем, надеюсь что вопрос "что лучше" исчерпан.
Более правильно по моему ставить вопрос так: должен ли ООП программист вообще знать о существовании ФП и сопутствующих идей (lambda-исчисление, curring, монады, ленивые вычисления, функции высшего порядка, унификация, ...) Я думаю, что _программист_ (не _кодер_) должен, иначе он просто будет изобретать велосипед.
Всем спасибо за внимание

rosali

В идеале, в функциональном языке ссылок быть не должно, поэтому получать результат через парамерты, и, тем более, но это уже в силу передачи по значению, менять их значения — нельзя. Вообще, __изменить__ в функциональных языках ничего нельзя!

Что-то это ты погорячился. В функциональных языках , действительно, ничего нельзя изменить, но это как раз означает, что параметры _всегда_ передаются по ссылке (в том числе в конструкторы). Так дешевле, а волноваться, что кто-то что-то испортит, не надо. Хотя в принципе, что всего лишь вопрос терминологии...
PS. Ну вот я и добрался до середины треда, скоро до начала дочитаю

freezer

мультиметоды (функции, полиморфные по нескольким параметрам

@ В Haskell-е весь полиморфизм статический. Точный тип любой переменной известен на момент компиляции.

тогда этот "полиморфизм" - то же самое, что перегрузка в C++. И не понятно, почему тогда
в ООП до сих пор нет

Marinavo_0507

маза, если хоть немного изучить вопрос, прежде чем комментировать,
такой чуши гораздо меньше будет

freezer

ты б хоть пояснил, кто чушь написал?.. Я или

Marinavo_0507

Тот, кто не изучил вопрос

Smaug

тогда этот "полиморфизм" - то же самое, что перегрузка в C++.

Очень даже справедливо! Но есть одно НО. Ты подсознательно имеешь в виду заодно и C++-ные шаблоны.


double f(double x, double y){ return(x+y); }
int f(int x, int y){ return(x-y); }
double f(double x, int y){ return(x*y); }
template<class T, class S>
T g(T t, S s){ return(f(f(t,ss; }
g(5, 6);
g(5.5, 6.6);


А в ООП, как таковом, шаблоны пока не очень-то распространены (Java, .NET, ...). Ну, когда-то наверное, дождемся
Да и вообще, Haskell-ный class - это очень глубокая вещь, а мультиметоды так, для примера...

rosali

Какой в баню Ленчик! Я это, ессессенно...

rosali

Тот кто не изучил вопрос

Так кто не изучил и какой вопрос?

Ivan8209

И нормальные алгорифмы и машины Тьюринга, вроде, тоже полны.
Ты хочешь сказать, что существуют прикладные задачи,
для решения которых, удобно использовать что-то из этих двух?
---
...Я работаю антинаучным аферистом...

1234554321

О да! Машины Тьюринга в чистом виде используются в шифровании. То есть, если мне нужно скрыть некое "ноу-хау", то сначала пишу нормальную версию, а потом секретную часть переписываю в виде машины Тьюринга

Ivan8209

Ты на http://ioccc.org/ ещё ничего не посылал?
---
...Я работаю антинаучным аферистом...

rosali

code:
let vec_res = map (+) vec1 vec2; (* SML *)



map :: (a->b) -> [a] -> [b]


или как там на SML

map : ('a->'b) -> 'a list -> 'b list


так что ли...
Короче, ею нельзя два массива сложить...
То что тебе надо на Haskell-е называется zipWith, а на SML не знаю как.

rosali

"сложить произведения пар", через "(fold 0 (map + x y" описывается куда более естественно, чем через ...

а произведение пар складывать надо вот так

foldl (+) 0 (zipWith (*) x y)


PS Чего вы его вообще слушаете, он про SML неделю назад узнал и теперь брызжит слюной направо налево, машину Тьюринга еще вспомнил...

Ivan8209

А мне всё-таки больше нравится так:


(map + x y z) ;; для сложения векторов
(apply + (map * x y ;; для сложения попарных произведений


В общем, МЛы мне не понравились.
Я скобки люблю.
---
"...но и без чтения мы разбирались в том,
в каком идти, в каком сражаться стане."

rosali

(map + x y z) ;; для сложения векторов
(apply + (map * x y ;; для сложения попарных произведений

Ты на каком языке пишешь-то?

Ivan8209

Это Схема.
---
...Я работаю антинаучным аферистом...

rosali

Ааа... , ну, извини. На Схеме умеешь программировать! Все работает

Ivan8209

Да, лямбды красивые.
Честно говоря, я не понимаю приверженцев "общего шёпота."
Но вот, когда на свет появится это, я, возможно, поползу туда.
#f и #t писать неудобно.
Так же, как и lambda.
Либо дело дойдёт до грязного хака с вовзращением T и NIL.
---
...Я работаю антинаучным аферистом...

rosali

Я принципиально против Lisp-ов из-за того, что они нетипизированные. А в остальном они может и хорошие...

Chupa

> Я принципиально против Lisp-ов из-за того, что они нетипизированные.
"Any lisp hacker will tell you there is only one type: a list." (c) Alan Cox

Marinavo_0507

Как думаешь, распределённая система масштабов Интернет может быть строго типизированной?
А весь мир "является" ли строго типизированным?

rosali

А весь мир "является" ли строго типизированным?

То, что в Lisp-е нет типизации, не означает, что программисты ее не соблюдают. Просто вынуждены держать это в голове, вместо того, чтобы возложить на компилятор.
"Any lisp hacker will tell you there is only one type: a list." (c) Alan Cox

Вот это он молодец, но, если даже забыть про числа и прочие примитивы, то в любом случае еще есть функции, и функции, чьими параметрами являются функции и т.д...

Ivan8209

Функция --- это тоже список.
---
...Я работаю антинаучным аферистом...

Ivan8209

Кстати, ты знаком с понятием "динамическая типизация?"
То, что ты называешь типизацией,--- это только один из её видов,
строгая статическая типизация.
---
...Я работаю антинаучным аферистом...

Marinavo_0507

Ты уже представил, как Бог (а в этом случае он может быть только один) компилирует мир?

Chupa

make world

Elina74

А зачем нужна динамическая типизация?
О великий гуру!

Chupa

> А весь мир "является" ли строго типизированным?
Типизация возможна только в мире, состоящем из объектов.
Так ли это "на самом деле"?

Marinavo_0507

с отрицанием возможности апгрейда по частям, как и положено в монотеизме и в *BSD
да, что-то загнался я

rosali

Кстати, ты знаком с понятием "динамическая типизация?"

А зачем нужна динамическая типизация?

Ну, вроде как без нее никуда, нельзя же складывать функции или те же списки... Так что либо в статике выясняется, что этот плюс будет складывать числа, либо в динамике.
Я вот как раз за статику. SML компиляторы, например, на основе информации полученной из типизации программы проводят неплохую оптимизацию, хвостовую рекурсию в циклы сворачивают, например. Хотя не знаю, связано это как нибудь с типизацией вообще ...
Основной тезис такой. Типизация программы, это одновременно формулировка и доказательство некоторого утверждения о программе, которое компилятору самому вывести трудновато. Этим утверждением можно пользоваться при оптимизации, справедливость доказательства можно автоматически проверять - и то и другое есть хорошо. Возьмем какую-нибудь Java программу и объявим все переменные Object, а там где методы надо вызывать или к полям доступ, там dynamic_cast-ов навворачиваем. Затормозит неподетски (как пишется-то? не-по-детски? непо-детски? не по-детски, что ли?..). Это не потому, что в Java-е плохой JIT поставили, а просто трудно это...
Да и вообще функциональные языки сложно отлаживать (кто-нибудь видел debugger? без типизации подавно.

rosali

А весь мир "является" ли строго типизированным?

Я склоняюсь к тому, что миром правят не свойства, а отношения. Так что язык программирования, подходящий под мою философию, пока вообще не изобрели
Если не совсем понятно, я пару примеров приведу: смотрим в .NET, читаем


virtual Object Clone;
virtual bool Equals(Object o);


В обеих строчках написано одно, а подразымевается другое! Clone пораждает не Object, а нечто, того же типа, что и this, это как бы Haskell-ное "::a->a" а пишут "::a->b", потому что это на языке ООП типизации невыразимо. Все от того, что надо записать некоторое утверждение о паре объектов (= отношение).

rosali

make world clean !

Ivan8209

> SML компиляторы,
...
> хвостовую рекурсию в циклы сворачивают, например.
"Scheme is... properly tail-recursive..."
> Да и вообще функциональные языки сложно отлаживать
Писать надо правильно, тогда и отлаживать не придётся.
> (кто-нибудь видел debugger?
Много раз.
Но не пользуюсь.
Отладка в лиспах проводится очень просто.
И без употребления отладчика.
---
...Я работаю антинаучным аферистом...

Ivan8209

> Я склоняюсь к тому, что миром правят не свойства, а отношения.
> Так что язык программирования, подходящий под мою философию,
> пока вообще не изобрели.
Пролог изобрели тоже где-то в начале 70-х.
---
...Я работаю антинаучным аферистом...

Aleksei66

Вообще-то, то, что SML'и и прочие OCaml'ы требуют заранее объявить все типы, это скорее особенность, чем необходимость. Вполне можно было бы добавить динамическое добавление новых функций и типов из программы (как в .NET) ценой потери производительности.

Marinavo_0507

Это где-нибудь уже сделано (с нормальной системой типов, так что всякие джавы и дотнеты не предлагать)?
А можно сделать так, чтобы один и тот же код мог производить сериализацию/десериализацию
данных любых (ну пусть хоть только алгебраических) типов?
То есть функции типа read : string -> 'a и print : 'a -> string ?

sergey_m

с отрицанием возможности апгрейда по частям, как и положено в монотеизме и в *BSD
Нет такого отрицания. Если ты воин - пожалуйста, апгрейди по частям. Я так иногда делаю.

Marinavo_0507

> Нет такого отрицания.
Это потому что идея строгой статической типизации не доведена до завершения,
так что я преувеличил, конечно.
Остаются операции приведения типов во время выполнения:
- запуск процессов, как правило, осуществляется из скрипта не шелле - нетипизированном языке
- программы преобразуют параметры командной строки и конфиги в свои внутренние структуры,
и на этом этапе может проявиться несовпадение типов (которые в этом случае называются форматами)
- всякие другие штуки, типа загрузки библиотек - тоже типы практически не проверяют
Идеально статически типизированная система включала бы в себя шелл с проверкой типов,
запрещающий передавать программам аргументы, которые они не поймут.
Так же нужно какое-то средство, чтобы нельзя было написать конфиг в неверном формате.
Сборка такой системы завершалась бы глобальной проверкой типов, и апгрейд был бы возможен только
полный, с потерей всех данных.

rosali

Сборка такой системы завершалась бы глобальной проверкой типов, и апгрейд был бы возможен только полный

Как это вообще связано? В SML есть раздельная компиляция...

rosali

Пролог изобрели тоже где-то в начале 70-х.

Да Пролог тоже не типизированный, я не про то. Я говорю, что само понятие типизации предполагает, что во главу всего ставится понятие свойства. Потому, что "Переменная x имеет тип X" <=> "То, что хранится в переменной x обладает свойством X". А отношения между переменными в современных системах типов не выразимы.

Chupa

> Я говорю, что само понятие типизации предполагает, что во главу всего ставится понятие свойства.


map :: (a->b) -> [a] -> [b]


Какие свойства объектов (и каких объектов) участвуют
в данном объявлении и в реализации такой конструкции?

rosali

То есть функции типа read : string -> 'a и print : 'a -> string ?

Hugs98/Lib/Exts/Haskell2Xml.hs ? Еще есть Hugs98/Lib/Exts/dynamic.lhs , на этом тоже вроде можно написать... Мне не хватило здоровья разбираться в этом Exts, там чего только нет!

Marinavo_0507

> В SML есть раздельная компиляция...
Не очень-то она раздельная, как я помню.
Нужны ведь сигнатуры всех используемых модулей, и в них содержится
вся необходимая информация о типах.
Ты наверное не понимаешь, про что я говорю.
Вот пример.
Рассмотрим почти любой сетевой протокол - например HTTP.
В нём сразу были предусмотрены возможности расширения, благодаря чему
сейчас параллельно используются несколько версий - 1.0, 1.1,
совместимость с 0.9 сохраняется обычно, всякие промежуточные варианты
и нестандартные расширения.
Это возможно лишь благодаря тому, что такие протоколы в корне противоречат
идее строгой статической типизации - ведь соответствие протоколу проверяется в динамике.
Но ведь можно было определить протокол с помощью алгебраических типов и сигнатур,
тогда динамические проверки не были бы необходимы, если все участники коммуникации
прошли статическую проверку типов.
Всякие поля неизвестных заранее форматов, зарезервированные для будущих расширений,
не могли бы существовать, так как тип данных, передаваемых в этих полях,
не был бы известен во время компиляции.
Протокол определялся бы некоторой сигнатурой, описывающей формат всех сообщений.
При модификации протокола было бы необходимо перекомпилировать все программы,
его использующие, и если две программы были бы скомпилированы относительно разных сигнатур,
они не смогли бы взаимодействовать -- требовалась бы одновременная перекомпиляция и замена
всех программ.
Естественно, такой подход не масштабируется на достаточно сложные системы --
представь себе одновременный апгрейд всех web-серверов и всех браузеров в Интернет --
поэтому возможны только лишь отдельные "островки" со статической типизацией,
и динамическая проверка типов на их границах.
В случае Интернет эти границы есть модули, реализующие стандартные протоколы.
В случае ОС - модули, работающие с форматами файлов, параметрами командной строки,
и с теми же протоколами.
То есть спор, какая типизация круче, статическая или динамическая, не имеет смысла,
так как есть потребность и в том, и в другом.

rosali

map :: (a->b) -> [a] -> [ b]

Ну, это намного ближе, к тому, что я хочу, чем вышеописанный Clone. Наверное ко мне придет счастье вместе с Generics.NET Кстати ими заведует некто Andrew Kennedy, фанат функционального программирования, создатель SML.NET
PS Блин, а как заэкранировать [ b]?

rosali

То есть спор, какая типизация круче, статическая или динамическая, не имеет смысла,
так как есть потребность и в том, и в другом.

Пять баллов! Полностью согласен. Ну дык в Lisp-е же одной из них как раз и нет!..

Marinavo_0507

> Ну дык в Lisp-е же одной из них как раз и нет!..
Я с этим не разобрался ещё, но как я понял, подход такой:
можно по сути сделать расширение языка с любыми свойствами,
и компилятор для этих расширений с помощью макросов.
В том числе и статическую типизацию можно сделать таким образом,
и вроде как и сделано даже.
Причём проверка типов может быть и во время выполнения, например
при загрузке плагина, и всё это без магии, штатными средствами.

rosali

...производить сериализацию/десериализацию...

Во!
Тебя с Kennedy одни и те же вопросы интересуют Хотя мне не понравилось, потому, что у него получилось в итоге не так как ты хотел...

Ivan8209

Вопрос: в котором Лиспе?
Выдайте кто-нибудь список свойств атома proclaim.
Или их уже отменили?
---
...Я работаю антинаучным аферистом...

Ivan8209

> Пролог тоже не типизированный
Что неверно.
По меньшей мере, существуют числа, строки и атомы.
> А отношения между переменными в современных системах
> типов не выразимы.
Переменные --- это имена.
Какие могут быть соотношения между именами?
В большинстве языков имена недоступны изнутри.
---
...Я работаю антинаучным аферистом...

Ivan8209

Если ты имеешь доступ к транслятору, многое из этого (если не всё) не имеет значения.
> - запуск процессов, как правило, осуществляется из скрипта не шелле
Замени sh на SML, что от этого изменится?
> - программы преобразуют параметры командной строки
> и конфиги в свои внутренние структуры,
Кто мешает проверить это при вводе команды?
> - всякие другие штуки, типа загрузки библиотек - тоже типы практически не проверяют
Что мешает им проверить?
> Так же нужно какое-то средство, чтобы нельзя было написать
> конфиг в неверном формате.
Мысли Чака Мура живут и процветают.
http://www.colorforth.com/cf.html
> Сборка такой системы завершалась бы глобальной проверкой типов,
> и апгрейд был бы возможен только полный, с потерей всех данных.
Связывание может быть отложенным.
---
...Я работаю антинаучным аферистом...

Ivan8209

Можно подробнее?
Как это можно сделать неявно?
---
...Я работаю антинаучным аферистом...

rosali

Ты только спорить попусту можешь? На твои посты даже ответить нечего
Переменные --- это имена.

А когда у переменной есть тип, то это нормально? Как у имени может быть тип? И вообще, имя чего? Переменной? Переменная - это имя переменной, а дальше рекурсия - переменная это имя имени переменной и т.д. Вобщем, как я уже сказал
На твои посты даже ответить нечего
один только флуд

rosali

можно по сути сделать расширение языка с любыми свойствами,
и компилятор для этих расширений с помощью макросов.
В том числе и статическую типизацию можно сделать таким образом

Что-то в этом есть! Учитывая, что в Lisp-е, вообще, грань между компиляцией и исполнением крайне размытая. Как я понял, там на стадии компиляции можно сделать сколь угодно сложные действия, не то что позорный C препроцессор...

Marinavo_0507

> на стадии компиляции
camlp4
и что-то подобное в хаскеле
а в лиспе то, про что я читал - это именно на стадии выполнения
но это не страшно - так как представление кода и данных одинаково, то всё,
что можно сделать во время выполнения, можно и во время компиляции, если
входные аргументы (программа на расширенном языке) уже известны

rosali

а в лиспе то, про что я читал - это именно на стадии выполнения

Я то в Lisp-е вообще ни бумбум разве что Схему из-за КОНТРы поставил, чтобы (apply...(map ... запускать Так что я все плету по воспоминаниям с курса ФП (с) Роганов (знаешь его наверное? )
PS Чего отвечаешь так быстро? Спать пора!

Marinavo_0507

> разве что Схему
в данном контесте схема - не то
там нет макросов

Ivan8209



(define-syntax fn
(syntax-rules (lambda) fn . l) (lambda . l
...
(map (fn (x) (* x x lst


---
...Я работаю антинаучным аферистом...

Ivan8209

> А когда у переменной есть тип, то это нормально?
Нет.
Тип есть только у значения переменной.
> Как у имени может быть тип?
Только когда именем обозначаются значения единственного рода.
> И вообще, имя чего?
<<Заглавие этой песни называется "Пуговки для сюртуков.">>
---
...Я работаю антинаучным аферистом...

rosali

Тип есть только у значения переменной.

Ты всего лишь споришь с общепринятым способом употребления термина. Что, может пойти в gоogle и найти тебе миллион словосочетаний "тип переменной"? Только тебе одному приходит в голову, что человек, использующий это словосочетание, на самом деле не понимает его смысла... Тебя это обстоятельство не смущает?

Ivan8209

То есть Пратт, Хантер, Девис и кто-там-ещё, написавшие классические учебники по языкам и компиляторам, используют необщепринятый смысл.
Про "тип переменной" могу сказать просто: мир, в основном, жил и живёт с ранним связыванием.
---
...Я работаю антинаучным аферистом...

Papazyan

Если речь идет о ФЯ, то вообще нет смысла спорить о том, есть у переменных тип или нет. В ФЯ нет переменных как таковых и этот факт не сразу доходит до императивщиков. Переменные - это имена, алиасы для упрощения программирования, их невозможно оторвать от значений, на которые они ссылаются, поэтому у них не может быть никакого типа.

Marinavo_0507

Маза это как раз значению тип не нужен, так как есть уже само значение.
Значения появляются лишь во время выполнения, а проверка типов проходит раньше -
следовательно, типы проверяются не у значений.
А именно, у "переменных", т.е. типы присваиваются именам, определённым в каком-то контексте.
В математике так же: в записи $f(x) = x^2$ x называется переменной, хотя разве он меняется?

Papazyan

Нет, самого значения недостаточно. Оно может быть потенциально сразу нескольких типов. И тип 'переменной' и значения вообще может быть разный, если на то пошло.
И все-таки типа у переменной нет, есть тип у выражения, на которое она ссылается, или константы. Не вижу причин приписывать дополнительные свойства обычной ссылке на другой объект, который на самом деле обладает этими свойствами.

Marinavo_0507

> И все-таки типа у переменной нет, есть тип у выражения, на которое она ссылается, или константы.
Согласен, так точнее.

rosali

И тип 'переменной' и значения вообще может быть разный

Это факт! Тип переменной общее, чем тип объекта, на который она ссылается.
Не вижу причин приписывать дополнительные свойства обычной ссылке на другой объект

Ты хочешь сказать, что в Java не стоит указывать типы переменных только потому, что в ней есть RTTI?
И все-таки типа у переменной нет, есть тип у выражения, на которое она ссылается
В ООП это заведомо не так, еще раз повторяю, тип переменной всегда более общий чем тип значения переменной, но эти типы вполне могут и не совпадать. В ФП в некотором смысле возможна противоположная ситуация, программист может наcильно сузить тип переменной


intMap :: (Int->Int) ->[Int] -> [Int]
intMap = map


Тип переменной intMap -- (Int->Int) ->[Int] -> [Int], а тип ее значения -- (a->b)->[a]->[ b].
PS Пажаалуйста! Не отправляя меня в FAQ научите написать [ b ] без пробелов

Papazyan

Чувак, я говорил о функциональных языках (чистых а не Явах и т.п. И типа у переменных в ФЯ нет, потому что нет переменных, поскольку по своей сути они просто ссылки на константы или выражения.

Marinavo_0507

> я говорил о функциональных языках (чистых)
однако верно и для *ML тоже
если не называть переменной ссылки ('a ref)

rosali

В ФП в некотором смысле возможна противоположная ситуация, программист может наcильно сузить тип переменной
code:--------------------------------------------------------------------------------
intMap :: (Int->Int) ->[Int] -> [Int]
intMap = map
--------------------------------------------------------------------------------
Тип переменной intMap -- (Int->Int) ->[Int] -> [Int], а тип ее значения -- (a->b)->[a]->[ b].

Чего неправильно то сказал?

rosali

Продолжаем разговор (С)
А теперь покажи мне программный продукт платный или бесплатный на этих самых языках.

FFTW (The Fastest Fourier Transform in the West). Код на C естественно (может даже Fortran? но он был не написан руками, а сгенерирован программой, написаной на OCaml. Вот.

rosali

ФЯ плохо ложаться на архитектуру современных компьютеров.

А императивные языки плохо ложатся на архитектуру будущих компьютеров. Все уже заманались Fortran распараллеливать!.. Приходится всякие извращения изобретать, OpenMP тот же, векторные операции, встроенные редукции...

rosali

Еще один серьезный минус, сложный код на ФЯ нечитаем, что является серьезным препятствием при исправлениях, поисках ошибки.

Зачастую программа на ФЯ состоит из трех строк, над которыми надо минутку подумать, а аналогичная программа на С занимает три экрана. Каждую строчку последней понимаешь сразу при прочтении, но разве это значит, что она проще? К тому же понять каждую строчку программы не означает понять саму программу, нужно понять их все.

Ivan8209

Хотите посмотреть на повторное использование кода в Сях?
gsl-1.4/fit/linear.c
GNU SL можно взять, например, из БСД.
Я уменьшил размер более, чем в полтора раза, переведя всё то же на Схему.
---
...Я работаю...

xz_post

круто !

Ivan8209

Кстати, у них там ещё и какой-то бред насчёт матрицы covNN в случае взвешеной подгонометрии.
---
...Я работаю...

Ivan8209

Короче, мне сейчас стало лень заниматься этим.
Так что всё откладывается.
Кому любопытно, смотрят в контрафактах.
---
...Я работаю антинаучным аферистом...

Ivan8209

Чуть не забыл.
Потом для скорости перепишу на массивы,
а сейчас пусть будут списки.
---
...Я работаю...
Оставить комментарий
Имя или ник:
Комментарий: