Comments 143
Неделя извращенства на хабре ;)
0
Вместо join, наверное «более функциональным» было бы реализовать аналог reduce, а уже join можно сделать на его основе.
+4
Согласен с вами.
Просто я хотел попроще, чтобы людям не знакомым с функциональным программированием было понятнее. Ну, и место в статье ограничено.
Просто я хотел попроще, чтобы людям не знакомым с функциональным программированием было понятнее. Ну, и место в статье ограничено.
+1
А чтобы сделать его еще более функциональным, надо было вместо аналога reduce надо было реализовать аналог foldl, на котором реализовать reduce, на котором реализовать join.
+2
Pattern-matcher было бы очень интересно.
+1
Про структурный pattern-matching на Java: samolisov.blogspot.com/2010/03/java_27.html
+4
Python? Почему его причислили к функциональным языкам?
0
Списочные выражения
0
Списочные выражения к функциональному программированию относятся постольку-поскольку.
0
Для питонистов это тот уровень функциональщины, который они могут принять:)
-1
Ну я лично пишу в том числе и на питоне, однако назвать его функциональным язык не поворачивается)
0
Ну все-таки списочные выражения пришли из ML-языков, насколько я понимаю. Да и выглядят они в точности как описания множеств из учебника по алгебре.
Википедия гласит, что в Python есть следующие элементы ФП:
Википедия гласит, что в Python есть следующие элементы ФП:
функции высших порядков, развитые средства обработки списков, рекурсия, возможность организации ленивых вычисленийЭто немало:)
0
Списочные выражения были задолго до ML. Взять хотя бы Лисп. Вообще списки — базовая структура данных и в том или ином виде есть в любом высокоуровневом языке программирования.
И выкиньте свой учебник по алгебре, списки никак не тянут на определение множества хотя бы потому, что в них важен порядок элементов, а в множестве нет. Если точно, список — множество пар вида (i, e), где i — индекс (элемент множества с установленным отношением полного порядка), e — элемент множества-носителя,
list ≡ {(i, e)} | i ∈ I, e ∈ E, (a, e1) = (b, e2) & a = b => e1 = e2.
И выкиньте свой учебник по алгебре, списки никак не тянут на определение множества хотя бы потому, что в них важен порядок элементов, а в множестве нет. Если точно, список — множество пар вида (i, e), где i — индекс (элемент множества с установленным отношением полного порядка), e — элемент множества-носителя,
list ≡ {(i, e)} | i ∈ I, e ∈ E, (a, e1) = (b, e2) & a = b => e1 = e2.
+2
У меня создалось ощущение, что вы не знаете, что такое списочное выражение и чем они отличаются от списков.
0
просветите
+1
Я бы с удовольствием, но плохо объясняю. Однако вот отрывок из учебника на Хаскелю. Автор хорошо показывает, что такое списочные выражения и откуда у них ноги растут. Обратите внимание, синтаксис очень похож на питоновский.
+1
Спасибо, но я знаком с Хаскелем (языком, не с Карри). Списочные выражения, или, точнее, S-выражения — это способ записи, иногда — способ хранения данных. И списки как структура данных обычно реализуются так, чтобы можно было осуществить разделение «голова-хвост»
+4
Ваше неверное представление, видимо, возникло из-за построителей списков в Хаскеле. Так вот, списки иногда (подчеркиваю, только иногда) являются удачным способом для представления множеств. В частности, механизм построения списка основан на теореме, что множество может быть определено с помощью универсума и предиката принадлежности элемента универсума к множеству. Но любая модифицирующая операция над множествами, представленными списками, требует проверки результата на наличие повторов
+3
И, кстати, в списках-то индекс как раз и не нужен. Нам нужна только его «голова» (ну и хвост). Это позволяет осуществлять ленивые вычисления.
0
> Википедия гласит, что в Python есть следующие элементы ФП:…
Это мало. Эти концепции можно реализовать даже на обычном Си. Однако это не сделает Си функциональным языком программирования. «Функциональность» питона проистекает из-за наличия в нем лямбда-функций, все остальное — просто следствие
Это мало. Эти концепции можно реализовать даже на обычном Си. Однако это не сделает Си функциональным языком программирования. «Функциональность» питона проистекает из-за наличия в нем лямбда-функций, все остальное — просто следствие
0
Лямбды — это тупо сахар. Ничего в них мистического нет. Куда можно передать функцию, туда можно передать и лямбду, и наоборот.
+1
лямбды — это инструмент построения функций. Без них язык не может быть функциональным в принципе. И это не просто сахар, за ними стоит очень мощная теория
0
А вы не путаете лямбда-исчисление и понятие lambda в терминах питона? lambda в питоне — это просто анонимная функция. Что с ее помощью можно сделать такого, что нельзя с помощью именованной, покажите мне?
Очень мощная теория стоит за тем, что функции являются значениями первого порядка и их можно передавать. AFAIK, это-то и имеет отношение к трудам Алонзо Чёрча.
Очень мощная теория стоит за тем, что функции являются значениями первого порядка и их можно передавать. AFAIK, это-то и имеет отношение к трудам Алонзо Чёрча.
+4
Я не совсем про лямбда-исчисление Черча. Люмбда-выражения применительно к программированию — это способ построения функций «на лету». И за этим тоже стоит теория, только из области компиляции и трансляции. В питоне это действительно просто анонимная функция. Но эта функция может быть создана в процессе исполнения программы
0
Я могу сходу назвать еще два способа построения функций в рантайме в питоне, никак не вовлекающих лямбды. И что? Давайте теперь молиться на декораторы и метод __call__?
+1
__call__ и декораторы — это совсем из другой степи, не имеющей отношение к функциональному программированию, и кстати не позволяют породить новые функции
0
а лямбды-то как порождают новые функции, просветите?
0
как конкретно интерпретатор Питона это делает — не знаю. Хотя ради Вас пороюсь в исходных кодах. А вот само «порождение» функции — пожалуйста:
def multN(value) : return (lambda x : x**value)
0
class MultN(object):
def __init__ (self, power):
self.power = power
def __call__ (value):
return value ** self.power
0
А так?
def fff(value) :
if value < 10 :
return (lambda x : x*2)
else :
return (lambda x y : x*y)
0
Добавляем в класс соответствующие методы, используем apply.
Вы что, хотите доказать, что функтор не идентичен анонимной функции?
Вы что, хотите доказать, что функтор не идентичен анонимной функции?
0
Я хочу показать, что есть принципиальная разница между объектом, который ведет себя по-разному в зависимости от внутреннего состояния, и функцией высшего порядка, которая производит функцию, удовлетворяющую некоторому условию
0
Дело не в том, что нельзя получить такую же функциональность другими методами. В большинстве случаев можно. Просто само понятие lambda было введено в Питон с целью избавиться от выражений вроде приведенного Вами. И это отнюдь не синтаксический сахар. Это совершенно другой механизм выполнения тех же действий
-1
Я согласен, что пользоваться лямбдами в вашем синтетическом примере удобнее, чем моим классом, который куда более громоздок.
Но вы утверждали, что только лямбды позволяют порождать новые функции. Функтор, конечно, не совсем чтобы функция, но и лямбда не идентична выражению def.
Но вы утверждали, что только лямбды позволяют порождать новые функции. Функтор, конечно, не совсем чтобы функция, но и лямбда не идентична выражению def.
0
Я утверждал и утверждаю, что лямбды — это не синтаксический сахар. Есть огромное количество случаев, когда применение безымянных функций «естественно», в отличие от объектов (как, собственно, в синтетическом примере). И если абстрагироваться от особенностей конкретного языка, то такое использование объектов возможно только для языков интерпретируемых, в то время как лямбды вполне хорошо живут и в компилируемых
0
Эмм, тут в топике, под которым мы развили этот холивар, вообще-то написано, как в компилируемом языке делать функторы. И как раз лямбд там нету (пока).
Такое использование объектов свойственно языкам, в которых есть перегрузка оператора оператора «вызов функции».
Нет, такое использование объектов свойственно только тем языкам, в которых функции не являются гражданами первого класса.
Такое использование объектов свойственно языкам, в которых есть перегрузка оператора оператора «вызов функции».
Нет, такое использование объектов свойственно только тем языкам, в которых функции не являются гражданами первого класса.
0
Ээээ. В каком топике? Для какого языка?
0
Нажмите ctrl+home, чтобы вспомнить. Нажмите ctrl+w, чтобы забыть.
0
Может я Вам открою глаза на мир… Но Java не является компилируемым языком в том смысле, что не компилируется в машинный код
0
Теоретически может существовать железо, для которого байт-код джавы будет являться ассемблером. Ну, а пока такого железа под рукой нет, будем его виртуализировать.
0
Увы, но как-раз теоретически такого железа пока не придумано (мне теория такого железа неизвестна). Именно в перегрузке оператора вызова во время исполнения загвоздка. Можно определить N-е количество объектов с разными версиями этой функции, но нельзя получать их в процессе выполнения, это противоречит архитектуре фон Неймана. Поэтому на данный момент такая функциональность достижима только с использованием лямбда-исчисления. И именно по этой причине нет компилятора Питона. Просто нет таких технологий компиляции
-2
А как же JIT?
0
JIT (Just In Time) производит исполнение, перевод в машинные инструкции «на лету». Но прямого соответствия между JIT-кодом и машинными командами для заданной архитектуры нет. То есть это все равно процесс интерпретации, хотя и более низкого уровня
0
Хм, ну тогда и компиляция — это «процесс интерпретации, хотя и более низкого уровня». Разница между компиляцией и интерпретацией зачастую только в том, что результат компиляции сохраняется в ПЗУ в виде файла.
0
Не правда, в Java нет никакого JIT-кода. Есть исходный байт-код, а есть машинный код, в который он компилится на основе статистики.
И можно в байт-код, кстати, вручную скомпилировать вручную что угодно. Хотя функтор. И он скомпилится JIT-от.
И можно в байт-код, кстати, вручную скомпилировать вручную что угодно. Хотя функтор. И он скомпилится JIT-от.
0
JIT-кода в природе нет, тут я маху дал. Это технология. И ради Бога, компилируйте в байт-код что угодно (условно), но это все равно байт код. Я говорю о том, что нет прямого соответствия между байт-кодом Java и машинным кодом процессора.
0
А что значит нету соответствия?
Не знаю, что вы подразумеваете под соответсвием, но способ компиляции байт-кода в машинный код процессора есть.
И вообще, ну вот напишу я на java примерно следующий код:
return Functions.componse(fn1, fn2);
Этот код создаст новый функтор и вернет. Можно с помощью ветвления задавать различные способы формирования объекта.
И эта функция будет транслирована в машинный код.
Не знаю, что вы подразумеваете под соответсвием, но способ компиляции байт-кода в машинный код процессора есть.
И вообще, ну вот напишу я на java примерно следующий код:
return Functions.componse(fn1, fn2);
Этот код создаст новый функтор и вернет. Можно с помощью ветвления задавать различные способы формирования объекта.
И эта функция будет транслирована в машинный код.
0
Эта функция будет ТРАНСЛИРОВАТЬСЯ. Нет соответствия означает, что нет (опять же, мне неизвестно) способа транслировать программу на Java в набор машинных инструкций минуя байт-код. Также как такого способа нет для Питона, Руби и многих других современных языков. Процесс выполнения Java-программы — это процесс интерпретации байт-кода Java-машиной
0
>способа транслировать программу на Java в набор машинных инструкций минуя байт-ко
А что меняет наличие этого промежуточного звена?
>Процесс выполнения Java-программы — это процесс интерпретации байт-кода Java-машиной
Это не так. Процесс выполнения java-программы, это выполнение машинного кода. Интерпретация совершается на ранних стадиях работы программы пока JIT не собрал достаточно статистики для компиляции.
А что меняет наличие этого промежуточного звена?
>Процесс выполнения Java-программы — это процесс интерпретации байт-кода Java-машиной
Это не так. Процесс выполнения java-программы, это выполнение машинного кода. Интерпретация совершается на ранних стадиях работы программы пока JIT не собрал достаточно статистики для компиляции.
0
Тогда где экзешники Java-программ? Байт-код, как Вы наверное знаете, очень хорошо документирован. Существует GNU-версия компилятора Java, который компилирует в машинный код, однако полной совместимости с языком добиться так и не удалось. Потому что не все так просто. Java-машина помимо сбора статистики (которая, кстати, может помочь оптимизировать процесс интерпретации, но никак не исключить его) делает еще кучу вещей, реализация которых в машинных инструкциях привела бы к необходимости добавлять исполняющую среду в каждую скомпилированную программу. Вот по этому и производится компиляция в байт-код. Потому что дальше этого сделать что-либо весьма проблемно
0
Exe-шники в памяти.
И, конечно, AOT-компиляторы добавляют рантайм к каждому exe-нику.
>Вот по этому и производится компиляция в байт-код.
Не по этому. Вполне можно рантайм как динамическую библиотеку таскать за собой. Байт-код же для кроссплатформенности и более эффективной компиляции за счет сбора статистики.
И, конечно, AOT-компиляторы добавляют рантайм к каждому exe-нику.
>Вот по этому и производится компиляция в байт-код.
Не по этому. Вполне можно рантайм как динамическую библиотеку таскать за собой. Байт-код же для кроссплатформенности и более эффективной компиляции за счет сбора статистики.
0
Интересно. Получаем следующую картину. Байт код эквивалентен машинному в том смысле, что может быть в него преобразован. Для большинства языков есть компиляторы в байт-код Java. То есть все языки — компилируемы! Ура товарищи, все проблемы решены!
0
А кто сказал, что компиляция в машинный код решает все проблемы производительности? Скомпилироваться то оно скомпилируется, просто не эффективно. Потому как из не эффективного байт-кода получается неэффективный машинный код.
К примеру, есть компиляторы языка scheme, которые дают настолько не эффективный исполняемый код, что он проигрывает даже некоторым интерпретаторам scheme.
К примеру, есть компиляторы языка scheme, которые дают настолько не эффективный исполняемый код, что он проигрывает даже некоторым интерпретаторам scheme.
0
Про scheme история отдельная. Там компиляторы были столь ужасны, поскольку все основные механизмы ставились на костыли. И все же пример показательный. Даже для языка с таким простым синтаксисом, как scheme, не удалось создать достойный компилятор. Java — в десятки раз сложнее даже с синтаксической точки зрения. Поэтому я и говорю, что байт-код — это вынужденная мера. Компилятора Java в машинный код нет и не предвидится не потому что это никому не нужно. Желающих навалом. Только не удается это сделать
0
Извините, но вы какую-то ерунду пишете.
> Даже для языка с таким простым синтаксисом, как scheme, не удалось создать достойный компилятор. Java — в десятки раз сложнее даже с синтаксической точки зрения.
Возможность оптимизации практически никак не коррелирует с синтаксисом языка. Для scheme нету компиляторов потому же что и для питона — отсутствие декларации типов, например как в Common Lisp который, кстати, прекрасно компилируется в машинный код.
>Компилятора Java в машинный код нет и не предвидится не потому что это никому не нужно. Желающих навалом.
Вот это уже откровенный бред. Так, на вскидку: www.excelsior-usa.com/jet.html
Популярностью особо не пользуется, так как желающих не так уж и много. JIT компиляция имеет одни единственный минус — тупеж приложения сразу после старта. Приходится приделывать всякие грелки.
> Даже для языка с таким простым синтаксисом, как scheme, не удалось создать достойный компилятор. Java — в десятки раз сложнее даже с синтаксической точки зрения.
Возможность оптимизации практически никак не коррелирует с синтаксисом языка. Для scheme нету компиляторов потому же что и для питона — отсутствие декларации типов, например как в Common Lisp который, кстати, прекрасно компилируется в машинный код.
>Компилятора Java в машинный код нет и не предвидится не потому что это никому не нужно. Желающих навалом.
Вот это уже откровенный бред. Так, на вскидку: www.excelsior-usa.com/jet.html
Популярностью особо не пользуется, так как желающих не так уж и много. JIT компиляция имеет одни единственный минус — тупеж приложения сразу после старта. Приходится приделывать всякие грелки.
+1
Всего один вопрос. Что делает JVM? При запуске Java-программы один раз создается набор машинных инструкций — эквивалентная программа — и после этого JVM с чувством выполненного долга отдыхает? Потому что если нет, то речь идет об интерпретации байт-кода.
> Для scheme нету компиляторов потому же что и для питона — отсутствие декларации типов
Ох, если бы все было так просто…
> Для scheme нету компиляторов потому же что и для питона — отсутствие декларации типов
Ох, если бы все было так просто…
-1
> При запуске Java-программы один раз создается набор машинных инструкций — эквивалентная программа
Практически да. Там есть несколько оговорок, правда.
>— и после этого JVM с чувством выполненного долга отдыхает?
Не отдыхает. По крайней мере осуществляет сборку мусора.
Практически да. Там есть несколько оговорок, правда.
>— и после этого JVM с чувством выполненного долга отдыхает?
Не отдыхает. По крайней мере осуществляет сборку мусора.
0
Тогда я неправ. И все-таки рисуемая Вами картина выглядит черезчур идеалистической. Если виртуальная машина (по-сути исполняющий механизм) оказывает какое-либо управляющее воздействие в процессе исполнения программы, то эквивалента в машинных кодах нет. А если такого воздействия нет, то непонятно, почему это называют виртуальной машиной, ведь в этом случае ее функции ограничиваются JIT-компиляцией.
0
Там фишка в том, что код, который редко вызывается не трогается JIT-ом, а интерпретируется. Ну и интерпретация врубается сразу после старта приложения, пока основная часть кода не сжитится. Управляющего воздействия вроде бы нету, по крайней мере не слышал.
+2
Ну это понятно, очевидная оптимизация. Но слабо верится, что функции виртуальной машины ограничиваются вышеперечисленными. Плотнее займусь этим вопросом
0
Хотя в моем представлении куда более правдоподобной выглядит картина, кода часть программы, та часть, где это возможно, компилируется JIT-ом, а остальная, в которую входят рефлексия и описанные в топике вещи, интерпретируются в процессе исполнения. Очень сложно представить соответствующий таким штукам набор машинных команд
0
Есть принципиальная разница между интерпретатором и рантаймом, Вам не кажется? Питон тоже можно таскать собой как библиотеку с байт-кодом, это не делает его компилируемым, потому что все равно осуществляется процесс интерпретации. В отличие от Си, в котором иногда происходит обращение к функциям библиотеки времени исполнения
0
Конечно есть. Я вообще это все писал не в защиту питона, а как доказательство того, что только реализация лямда-исчисления позволяет формировать функции в рантайме.
0
Соответствия нет. Когда в программе на Java присутствует многопоточность, потоки имитируются Java-машиной, а не средствами операционной системы. Когда происходит рефлексия — идет анализ байт-кода, а не машинного. Байт-код обеспечивает кроссплатформенность — бесспорно. Более эффективную компиляцию? скорее исполнение. Но не только. Это еще и вынужденная мера, позволяющая реализовать все средства языка
-1
0
Подождите-ка. В C++ есть перегрузка оператора (). Вы же не скажете, что это не компилируется.
0
Увы, но как-раз теоретически такого железа пока не придумано (мне теория такого железа неизвестна)
То, что вам что-то неизвестно, ещё не означает, что этого не существует в природе: en.wikipedia.org/wiki/Java_processor.
Вообще, разработка процессоров специально для байт-кода высокоуровневого языка началась отнюдь не с Java. Ещё задолго до Java-машин существовали Lisp-машины и Smalltalk-машины.
0
было уже «практически»,
цитата «Компания Sun на Микропроцессорном форуме представила процессор MicroJava 701. Это первый процессор, непосредственно исполняющий байт-код Java.»
источник — www.osp.ru/cw/1997/42/25003/
(«Computerworld Россия», № 42, 1997 )
цитата «Компания Sun на Микропроцессорном форуме представила процессор MicroJava 701. Это первый процессор, непосредственно исполняющий байт-код Java.»
источник — www.osp.ru/cw/1997/42/25003/
(«Computerworld Россия», № 42, 1997 )
0
А именно это делает язык функциональным. Если основная единица — объект. То язык объектный. И можно говорить только об элементах других парадигм программирования
0
Тут ниже высказывалось мнение, что функциональные языки — это те, в которых все функции чистые. Я вот как-то с этим больше согласен.
Но я никогда и не утверждал, что питон — функциональный язык. Но функциональщины там довольно много, и это не только лямбды и списочные выражения.
Но я никогда и не утверждал, что питон — функциональный язык. Но функциональщины там довольно много, и это не только лямбды и списочные выражения.
0
Чистота функций — следствие, не причина. Списочные выражения — тоже. Парадигму составляют не какие-либо технологии, а система базовых установок, если угодно — идея. Хаскель — функциональный язык, однако писать на нем можно без использования списочных структур и с использованием изменяемых состояний. А вот лямбда-выражения — почти краеугольный камень
-1
Кстати, apply позволяет сделать каррирование, что, в общем-то, порождает новую функцию.
0
Об этой возможности не знаю, напишите пожалуйста поподробней. Хотя сути в общем-то не меняет. Каррирование просто частный случай. Например в Хаскеле оно определяется очень просто через те же лямбды:
carry f (x, y) = \x y -> f (x, y)
carry f (x, y) = \x y -> f (x, y)
0
И да, рыться не надо, спасибо:) Мне не интересна в данном случае конкретная реализация.
0
Способность строить функции на лету — это свойство рантайма. Лямбда функции — это просто один из синтаксисов, позволяющих этим свойством воспользоваться, вам тут правильно написали.
0
Пожалуйста, поясните, почему вы считаете люмбды «тупо синтаксическим сахором», а списочное выражение нет?
Вам не кажется, что любой язык высокого это синтаксический сахар над набором машинных команд? И в чем тогда по-вашему состоит важное отличие функциональных языков программирования от других?
Вам не кажется, что любой язык высокого это синтаксический сахар над набором машинных команд? И в чем тогда по-вашему состоит важное отличие функциональных языков программирования от других?
+1
Списочные выражения значительно повышают выразительность кода и привносят новую семантику. Особенно вкупе с генераторами.
Лямбды — нет.
Вам не кажется, что любой человеческий язык — это синтаксический сахар над криками и жестами?
Действительно важное отличие для меня состоит в совершенно отличной семантике. Так же часто упоминают отсутствие побочных эффектов и ленивые вычисления.
Лямбды — нет.
Вам не кажется, что любой человеческий язык — это синтаксический сахар над криками и жестами?
Действительно важное отличие для меня состоит в совершенно отличной семантике. Так же часто упоминают отсутствие побочных эффектов и ленивые вычисления.
0
По-моему, единственной важной особенностью как-раз и является отсутствие побочных эффектов, все остальное можно накалякать сверху самому. По этому когда говорят, что человек пишет в функциональном стиле на каком-то языке, имеют ввиду, что он старается минимизировать изменяемые состояния. И по этому map > for.
Питоновская лямбда в свою очередь имеет действительно другую семантику, конечно, это не честно каррированная функция, но и не просто анонимная — в ней напрямую нельзя изменять состояния (lambda: c = 5 не покатит), хотя можно изменить косвенно, по тому, что окружение не «чистое», вроде (lambda x: x.y()).
Питоновская лямбда в свою очередь имеет действительно другую семантику, конечно, это не честно каррированная функция, но и не просто анонимная — в ней напрямую нельзя изменять состояния (lambda: c = 5 не покатит), хотя можно изменить косвенно, по тому, что окружение не «чистое», вроде (lambda x: x.y()).
0
Поясню. Допустим, мы имеем только чистые функции (без побочных эффектов, чтобы было проще возьмем только от одного аргумента, имена функций и аргументов не существенны, по этому их опустим), для того, чтобы при помощи них произвести какие-то вычисления нужно определить список операций, которые мы можем над ними выполнять. Алонзо Черч показал, что минимально необходимых операций всего 3 — α-преобрзование, β-редукция, η-преобразование.
Имея только чистые функции и 3 операции можно провести любые вычисления (язык полный по Тьюрингу), такой язык называют λ-счислением. Например, построить операцию рекурсии (Y-комбинатор).
Но так как каждый раз записывать Y-комбинатор или числа в Church numerals муторно и бессмысленно, то напридумали разного синтаксического сахара, например функции от нескольких аргументов (define в лисп) и тп
Таких функций напридумывали много (map, fold, reduce и тд) и язык реализцющих их каким-то образом, но не реализующий лямда-счисления, называют языком с функциональными возможностями, которым является Python. Lisp в свое время и был реализацией лямбда-счисления, по этому он просто функциональный язык.
Имея только чистые функции и 3 операции можно провести любые вычисления (язык полный по Тьюрингу), такой язык называют λ-счислением. Например, построить операцию рекурсии (Y-комбинатор).
Но так как каждый раз записывать Y-комбинатор или числа в Church numerals муторно и бессмысленно, то напридумали разного синтаксического сахара, например функции от нескольких аргументов (define в лисп) и тп
Таких функций напридумывали много (map, fold, reduce и тд) и язык реализцющих их каким-то образом, но не реализующий лямда-счисления, называют языком с функциональными возможностями, которым является Python. Lisp в свое время и был реализацией лямбда-счисления, по этому он просто функциональный язык.
0
И все-таки — одно дело, когда сверху сам калякаешь, а другое, когда язык это поощряет. Любая реализация тех же списочных выражений в виде некоторой функции будет выглядеть более громоздко.
Видимо, я был неправ, когда говорил, что лямбды в питоне не несут никакой новой семантики. Во-первых, я не знал про «
Видимо, я был неправ, когда говорил, что лямбды в питоне не несут никакой новой семантики. Во-первых, я не знал про «
lambda: c = 5
не покатит». Во-вторых, я пишу на JS, а там нет различия меду анонимными функциями и именованными (за тем исключением, что именованные подвергаются «поднятию», но я не могу придумать красивый не синтетический пример, когда это меняет их использование).0
Или, другими словами — где та грань, где синтаксический сахар переходит в новую семантику? Как вы считаете?
0
А писать на питоне можно очень по разному:)
-1
Функциональное программирование — это в первую очередь иммутабельность данных, а уж потом все манипуляции с функциями, как со значениями.
+1
В функциональном программировании не функция является объектом, а все элементы языка могут быть интерпретированы как функции. Поэтому можно говорить только об элементах функционального программирования в Java, Python и прочив мультипарадигмальных языках
0
Функциональное программирование — это идея в головах людей(или если хотите, подход к решению), а не конкретный язык или набор фишек, впрочем стоит отметить, что определенный набор-таки позволяет сделать это проще и естественее.
А вообще да, как человек, который пишет на java и функциональных языках, могу сказать, что редко мешаю стандартные вещи из Java с идеями подчерпнутыми из функциональной среды — поэтому было бы невероятно интересно увидеть продолжение.
мое имхо, что стоить иметь хороший набор методик из разных источников и парадигм, чтобы выбрать что-то лучшее для решения задачи, но в реальной жизни иструменты довольно сильно ограничены, поэтому написанное выше отличный компромис между форсированными сверху инструментами и выбором идей для решения задач.
А вообще да, как человек, который пишет на java и функциональных языках, могу сказать, что редко мешаю стандартные вещи из Java с идеями подчерпнутыми из функциональной среды — поэтому было бы невероятно интересно увидеть продолжение.
мое имхо, что стоить иметь хороший набор методик из разных источников и парадигм, чтобы выбрать что-то лучшее для решения задачи, но в реальной жизни иструменты довольно сильно ограничены, поэтому написанное выше отличный компромис между форсированными сверху инструментами и выбором идей для решения задач.
+3
Все попытки разбавить императивный поноскод на Java какими-либо костылями приводят в ужас. Приведенный в этом посте map имеет очень печальную, неленивую реализацию как по выделению памяти, так и по выполнению. Дальше читать уже не имело смысла.
-1
Все-таки с functionaljava.org/ это будет получше чуток
0
Со всем уважениемм и благодарностью за проделаную работу.
Как Function<F, T> реализует first class function?
А если не реализует — функциональное ли это программирование?
Скажем в javascript делаем так:
Как это реализуется на Java?
Как Function<F, T> реализует first class function?
А если не реализует — функциональное ли это программирование?
Скажем в javascript делаем так:
function outer () {
var ctx="внутри";
var inner = function() {
return ctx;
};
return inner;
}
var ctx="снаружи";
var res = outer();
console.debug(res());
Как это реализуется на Java?
0
first class function означает, что функции могут быть аргументами функций и их возвращаемыми значениями. Function все это обеспечивает.
-1
это делегаты, не замыкания
есть в совсем не функциональных паскале и си, например
замыкание, иже closure или first class function, должно еще уметь таскать за собой контекст, что и делает функциональщину такой приятной и полезной на асинхронных алгоритмах
и Function<F, T> из примера, строго говоря, контекст тащит, хоть и некими ограничениями
но я не пойму почему в статье об этом ни слова
есть в совсем не функциональных паскале и си, например
замыкание, иже closure или first class function, должно еще уметь таскать за собой контекст, что и делает функциональщину такой приятной и полезной на асинхронных алгоритмах
и Function<F, T> из примера, строго говоря, контекст тащит, хоть и некими ограничениями
но я не пойму почему в статье об этом ни слова
-1
>есть в совсем не функциональных паскале и си, например
А по-вашему в не функциональных языках не может быть элементов функциональщины? Ссылка не процедуру в Си вполне себе элемент функциональщины.
А замыкание, это замыкание. Понятие ортогональное first class function. И если вам интересно, то в Java они с оговоркой есть. Можно внутри анонимного класса обращаться к final ссылкам и полям внешнего объекта.
А по-вашему в не функциональных языках не может быть элементов функциональщины? Ссылка не процедуру в Си вполне себе элемент функциональщины.
А замыкание, это замыкание. Понятие ортогональное first class function. И если вам интересно, то в Java они с оговоркой есть. Можно внутри анонимного класса обращаться к final ссылкам и полям внешнего объекта.
-1
Ссылка на процедуру в Си вовсе не есть элемент функциональщины. По этому вопросу, собственно, и все дебаты. Как было правильно замечено ранее, функциональное программирование не определяется набором возможностей языка, это образ мышления. Если функцию можно рассматривать в математическом смысле, т.е. как отображение одного множества на другое, то это — функциональный язык. Поэтому Си — не функциональный, а императивный язык программирования
0
>Если функцию можно рассматривать в математическом смысле, т.е. как отображение одного множества на другое, то это — функциональный язык.
И что же нам мешает это делать в Си, тем более вы говорите, что ФП-это идея?
> Поэтому Си — не функциональный, а императивный язык программирования
При чем здесь «поэтому»? Си процедурный язык, так как он поощряет такую парадигму. И никак не запрещает другие, например объектно-ориентированную (см. GObject), метаязыковую (привет макросам) или функциональную (опять же привет указателям на процедуры).
И что же нам мешает это делать в Си, тем более вы говорите, что ФП-это идея?
> Поэтому Си — не функциональный, а императивный язык программирования
При чем здесь «поэтому»? Си процедурный язык, так как он поощряет такую парадигму. И никак не запрещает другие, например объектно-ориентированную (см. GObject), метаязыковую (привет макросам) или функциональную (опять же привет указателям на процедуры).
0
Где в Си наследование, инкапсуляция и полиморфизм, чтобы его можно было считать объектным? Макросы там определяют процесс компиляции и только, к алгоритмике не имеют никакого отношения. И когда Вы сможете на Си сделать то же каррирование — тогда можно будет поговорить о функциональности. А так, простите, процедурный язык и только
-1
>Где в Си наследование, инкапсуляция и полиморфизм, чтобы его можно было считать объектным?
Читайте документацию по GObject.
>Макросы там определяют процесс компиляции и только, к алгоритмике не имеют никакого отношения.
А при чем здесь алгоритмика? Речь идет о кодогенерации
>И когда Вы сможете на Си сделать то же каррирование — тогда можно будет поговорить о функциональности
Извините, говорить о чем? Я вам говорю, что ссылки на процедуры — элемент функционально программирования. Маленький такой, куцый, но элемент.
>А так, простите, процедурный язык и только
А я разве доказываю обратное?
Читайте документацию по GObject.
>Макросы там определяют процесс компиляции и только, к алгоритмике не имеют никакого отношения.
А при чем здесь алгоритмика? Речь идет о кодогенерации
>И когда Вы сможете на Си сделать то же каррирование — тогда можно будет поговорить о функциональности
Извините, говорить о чем? Я вам говорю, что ссылки на процедуры — элемент функционально программирования. Маленький такой, куцый, но элемент.
>А так, простите, процедурный язык и только
А я разве доказываю обратное?
0
Я так понимаю, у нас с Вами разные исходные убеждения. Для меня неприемлемо говорить о поддержке какой-либо идеи даже элементно, если не отражены основные концепции. То, что в Си можно присваивать переменной адрес функции, не является элементом функционального программирования, потому что сама концепция присваивания функции, именно функции, чужда этому языку. Речь может идти о присваивании адреса, что можно реализовать и на ассемблере. И я не думаю, что найдется человек, всерьез утверждающий, что ассемблер поддерживает функциональную парадигму программирования
0
ta6aku, спасибо за конструктивную критику.
В моей статье действительно ничего не было сказано о замыканиях, хотя это один из ключевых элементов функционального программирования. Уверяю вас, что замыкания в Java можно использовать также как и в JavaScript. Наверное в следующий раз стоит начать статью именно с этого вопроса.
В моей статье действительно ничего не было сказано о замыканиях, хотя это один из ключевых элементов функционального программирования. Уверяю вас, что замыкания в Java можно использовать также как и в JavaScript. Наверное в следующий раз стоит начать статью именно с этого вопроса.
0
А где тут функциональное программирование?
+2
Вот тут вижу выше много споров о том функционально/не функционально. Товарищи спорщики, вы бы вначале договорились о том, что такое функциональное программирование, а потом уже спорили. Я когда разбирался с этой терминологией и пришел к выводу, что определение у термина очень размытое. Есть некий набор свойств: функции как первоклассные значения, immutable данные, рекурсия, паттерн матчинг, алгербраические типы данных и так далее. При этом никакой набор признаков нельзя назвать необходимым или достаточным.
0
eliah_lakhin, Если возможно, расскажите, в чём преимущества «функциональной» реализации по сравнению с «традиционной». Просто из примера, это не очевидно: кода стало больше + синтаксис generic'ов усложняет чтение.
-1
Одно из преимуществ, например, заключается в том, что метод main, изначально написанный в императивном стиле(«традиционном»), занимал 6 строк, а после переписывания в функциональном стиле стал занимать всего одну строку.
0
main? Насколько я понял, он состоит только из вызова joinNumbers и для мало что изменилось при переходе к функциональной реализации.
А вот кода стало больше (INT_TO_STRING + map +join > императивный joinNumbers)
И появились конструкции вроде
public static <F, T> List map(Collection from, Function<? super F,? extends T> transformer) {
А вот кода стало больше (INT_TO_STRING + map +join > императивный joinNumbers)
И появились конструкции вроде
public static <F, T> List map(Collection from, Function<? super F,? extends T> transformer) {
0
> А вот кода стало больше (INT_TO_STRING + map +join > императивный joinNumbers)
Дело в том, что это достаточно общие конструкции, то есть их можно один раз написать, вынести в какой-нибудь утилитный класс, и потом использовать для решения подобных задач.
А можно вообще ничего не писать, просто взять уже готовый Google Collections или Apache Common Collections.
Дело в том, что это достаточно общие конструкции, то есть их можно один раз написать, вынести в какой-нибудь утилитный класс, и потом использовать для решения подобных задач.
А можно вообще ничего не писать, просто взять уже готовый Google Collections или Apache Common Collections.
0
Странно, что никто не откомментировал про Clojure. Функциональное программирование без всяких извращений.
+1
А что про него комментировать? Котлеты отдельно, мухи отдельно. Являясь большим фанатом clojure, я пишу участки, требовательные к производительности, на Java. И в Андроид пока clj не засунешь (я пробовал — 7 секунд на запуск пустого приложения). Если сравнить jvm-байткод с ассемблером, то Java сейчас — это С. Есть множество более экспрессивных и concise языков (Scala/JRuby/Groovy/Clojure), но что должно работать быстро, все равно пишется на Джаве.
А вот-такие штуки для Джавы вроде Google Collections — это как С++ как С. Код выглядит как дерьмо, но зато можно сделать больше, не теряя производительности.
А вот-такие штуки для Джавы вроде Google Collections — это как С++ как С. Код выглядит как дерьмо, но зато можно сделать больше, не теряя производительности.
+1
Давно было интересно, как можно писать функционально на Java. Однако эта статья не ответила на основные мои вопросы, которые возникают сразу после объявления интерфейса Function:
1) Как реализуется композиция: λxyz.x(yz)?
2) Типы (которые всё-таки вводятся, т.к. интерфейс-то параметрический), как я понимаю, образуют категорию, допускающую экспоненцирование и умножение. Как реализовать контроль типов? Более точный вопрос: как выглядит функция каррирования, ведь для этого нужно как минимум определить произведение?
С экспоненцированием проблем таких нет, т.к. Function, будучи интерфейсом, может рассматриваться как тип аргумента/результата (что, собственно, и подчеркивается в статье)
1) Как реализуется композиция: λxyz.x(yz)?
2) Типы (которые всё-таки вводятся, т.к. интерфейс-то параметрический), как я понимаю, образуют категорию, допускающую экспоненцирование и умножение. Как реализовать контроль типов? Более точный вопрос: как выглядит функция каррирования, ведь для этого нужно как минимум определить произведение?
С экспоненцированием проблем таких нет, т.к. Function, будучи интерфейсом, может рассматриваться как тип аргумента/результата (что, собственно, и подчеркивается в статье)
0
1) В терминах Google Colletions композиция может быть реализована с помощью Functions.compose. Она принимает две функции и создает инстанс новой функции, которая при вызове осуществляет применение(Function.apply) переданных функций.
2) Каррирование можно реализовать, например, одним из двух способов:
Способ первый. Объявить порядка семи-восьми функций, принимающих разное количество аргументов, и имеющих разный тип(Function0 — от нуля аргументов, Function1 — от одного аргумента и т.п.). Для каждого типа функций объявить метод apply с меньшим числом аргументов, который будет возвращать каррированную функцию.
Способ второй. Объявить гетерогенные коллекции(кортежи, «параметрические бины»), опять таки, для разного количества аргументов. Ну и сделать методы каррирования для функций от таких аргументов.
Отмечу, что в обоих случаях можно сделать наследование между функциями и/или кортежами, то есть, например, кортеж от пяти аргументов — это частный случай коллекции от трех аргументов. Это позволит немного унифицировать работу с функциями разных типов. Также в обоих случаях мы имеем ограничение на число аргументов, правда передавать больше шести-семи аргументов тоже не очень хорошо(в Haskell, насколько я помню, гетерогенные коллекции тоже ограничены по длине).
В общем, оба способа на самом деле не универсальны, имеют свои плюсы и минусы, однако в целом позволяют решить проблему типобезопасным образом.
2) Каррирование можно реализовать, например, одним из двух способов:
Способ первый. Объявить порядка семи-восьми функций, принимающих разное количество аргументов, и имеющих разный тип(Function0 — от нуля аргументов, Function1 — от одного аргумента и т.п.). Для каждого типа функций объявить метод apply с меньшим числом аргументов, который будет возвращать каррированную функцию.
Способ второй. Объявить гетерогенные коллекции(кортежи, «параметрические бины»), опять таки, для разного количества аргументов. Ну и сделать методы каррирования для функций от таких аргументов.
Отмечу, что в обоих случаях можно сделать наследование между функциями и/или кортежами, то есть, например, кортеж от пяти аргументов — это частный случай коллекции от трех аргументов. Это позволит немного унифицировать работу с функциями разных типов. Также в обоих случаях мы имеем ограничение на число аргументов, правда передавать больше шести-семи аргументов тоже не очень хорошо(в Haskell, насколько я помню, гетерогенные коллекции тоже ограничены по длине).
В общем, оба способа на самом деле не универсальны, имеют свои плюсы и минусы, однако в целом позволяют решить проблему типобезопасным образом.
0
Вы видели Scala?
Там все проще делается, без попыток заставить императвную Java быть функциональной.
Там все проще делается, без попыток заставить императвную Java быть функциональной.
0
Конечно видел. Я на нем пишу каждый день, и не только на нем. :)
0
Тогда непонятно желание протащить это на Java. Разве что для развлечения :).
Кстати очень напомает linq в C#.
Кстати очень напомает linq в C#.
0
Статья ориентирована на Java программистов, которые хотели бы познакомиться с ФП. Мне кажется, что примеры на Java конструкций, имеющих аналог в функциональных языках, облегчит задачу перехода к функциональному программированию.
А потом, иногда бывает, что в силу обстоятельств возможности перейти с Java на что-то другое просто нету, а желание использовать функциональные конструкции есть. Конечно эти конструкции в Java получаются гораздо более громоздкими, чем, скажем, в Scala, но все-таки для решения некоторых задач могут быть полезнее и лаконичнее аналогичных решений в императивном стиле.
Ну, и да, конечно для развлечения тоже. :)
А потом, иногда бывает, что в силу обстоятельств возможности перейти с Java на что-то другое просто нету, а желание использовать функциональные конструкции есть. Конечно эти конструкции в Java получаются гораздо более громоздкими, чем, скажем, в Scala, но все-таки для решения некоторых задач могут быть полезнее и лаконичнее аналогичных решений в императивном стиле.
Ну, и да, конечно для развлечения тоже. :)
+3
Пользуюсь Google Collections как раз для этих целей. Очень удобно.
+1
Пользуюсь иногда Guava, и каждый раз когда идет порыв на использование transform, щелчок в мозгу — кода столько же, засирается PermGen, а результат один. В итоге пишу обычный цикл.
Цееность таких извратов в стандартной яве для меня сомнительна. Как когда то писали не помню кто — если хотите писать на паскале, пишите на паскале, а не делайте макросы begin и end
Цееность таких извратов в стандартной яве для меня сомнительна. Как когда то писали не помню кто — если хотите писать на паскале, пишите на паскале, а не делайте макросы begin и end
0
Иногда(не всегда, конечно) функциональный подход может оказаться лучше в плане дизайна. Например, он позволяет облегчить задачу разделения системы на отдельные компоненты для дальнейшего их переиспользования.
> кода столько же
> кода столько же
+1
ну с этим я согласен, просто в джаве это не получается так элегантно и красиво — пока что. Вот выйдет восьмерочка с лямбдами — заживем. Там тоже не так красиво как в рубях или лиспе, но код будет короче, а значит и профит тоже хоть какой то будет (с коментом ниже я тоже согласен — очень удобно, пожалуй это один из немногих случаев когда я смело использую гуаву).
0
> кода столько же
Мой опыт показывает, что в общем случае кода меньше, поскольку функции можно выносить в отдельные сущности, и повторно использовать их в разных частях кода.
Мой опыт показывает, что в общем случае кода меньше, поскольку функции можно выносить в отдельные сущности, и повторно использовать их в разных частях кода.
0
улыбнуло
то есть, если у вас дома нету интернета и нет желания учить фп — вот пожалуйста вам в наказание, горите в аду!!!
хотели бы познакомиться с функциональным программированием, но не имеет возможности/желания изучать Haskell/Scala/Lisp/Python, — эта статья специально для вас.
то есть, если у вас дома нету интернета и нет желания учить фп — вот пожалуйста вам в наказание, горите в аду!!!
0
Sign up to leave a comment.
Функциональное программирование в Java