LINUX.ORG.RU

Функциональноое программирование для ООПешников

 ,


1

3

Посоветуйте пожалуйста книгу или ресурс где для ООП программистов описывается как нужно программировать в функциональном стиле.

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

Ответ на: комментарий от anonymous

На самом деле — это мало кто понимает даже тут, на лоре — разница между ФП и ООП это всего лишь разница в компоновке кода/данных и месте хранения состояний.

Возможно, только никто не пишет в «чисто объектно-ориентированном» стиле без переопределения значения переменных и I/O в каждой строчке.

anonymous
()
Ответ на: комментарий от elf80lvl

ооп — нашлёпка сверху хоть над императивным, хоть над функциональным стилем

anonymous
()
Ответ на: комментарий от elf80lvl

Что ФП предлагает взамен наследованию, инкапсуляции, полиморфизму?

Зачем заменять? Там это просто реализовано по другому. Посмотри, как сделано ООП в Haskell. Там есть наследование, инкапсуляция и полиморфизм, но тебя удивит то, как они реализованы.

Aswed ★★★★★
()

Поиграйся с scala или f#.

anonymous
()
Ответ на: комментарий от fmdw

В коде просто синтаксическая ошибка.

-module(test).
-export([counter/0]).

counter() ->
  receive
    {cnt, N} -> self() ! {cnt, N+1}, N 
  after 0 -> self() ! {cnt, 1}, 0
  end. 

> lists:foreach(fun (A) -> {A, test:counter()} end, [a, b, c]).
> flush().
Shell got {cnt,3}
ok
> lists:map(fun (A) -> {A, test:counter()} end, [a, b, c]).
[{a,0},{b,1},{c,2}]
> flush().
> lists:foreach(fun (A) -> io:format("~p~n", [{A, test:counter()}]) end, [a, b, c]).
{a,0}
{b,1}
{c,2}
ok
NegatiV
()
Ответ на: комментарий от elf80lvl

Т.е. писать на функциональном языке в ООП стиле или смешанном с ним это нормально?

ООП не противоречит ФП. Еще раз предлагаю посмотреть на OCaml как на яркий тому пример - идеальное, имхо, сочетание ООП и ФП.

Соответствия между функциональными и императивными программами,

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

NegatiV
()
Ответ на: комментарий от NegatiV

В коде просто синтаксическая ошибка.

Ну тогда три пункта. Я просто набирал в браузере в уставшем виде.

Запустил код один раз — вроде работает. Всё правильно!

Да, так на эрланге и проектируют.

Даю подсказку: в ночь пятницы 13го этот код вдруг начинает генерировать такую последовательность:

...n, n+1, 0, n+2, 1, n+3, 2, ...

fmdw
()
Ответ на: комментарий от NegatiV

Предлагаешь посмотреть на язык, в котором все профессиональные разработчики (все 4) не используют ООП?

anonymous
()
Ответ на: комментарий от fmdw

Даю подсказку: в ночь пятницы 13го этот код вдруг начинает генерировать такую последовательность:

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

NegatiV
()
Ответ на: комментарий от NegatiV

Ты уверен что он генерирует эту последовательность при работе в одном потоке

Что за вопрос, разве thread safety — не фича Эрланга? Ок, один случай ты как бы нашёл. Теперь допустим, что потоков на ноде может быть много, но никакой rogue process в этот тред сообщения вида {counter, 0} не шлёт. Эта ситуация возникнет и в таких условиях.

и в том что код ну точно такой же?

Суть, во всяком случае, передана.

fmdw
()
Ответ на: комментарий от stevejobs

Даже пых уже стал. Привыкай.

anonymous
()
Ответ на: комментарий от fmdw

let it crash = bullshit

сам ты булшит, это главная фича

Typical Erlang code

ах ты толстячок! аж верстка разлезлась!

stevejobs ★★★★☆
()
Ответ на: комментарий от fmdw

Ах да, забыл сказать, что модель акторов в целом = зло

приведи пример зла

stevejobs ★★★★☆
()
Ответ на: комментарий от fmdw

Что за вопрос, разве thread safety — не фича Эрланга? Ок, один случай ты как бы нашёл.

Я и имел в виду что никакой процесс (в том числе self()) не отправляет себе сообщение вида {counter, _}.

NegatiV
()
Ответ на: комментарий от fmdw

Суть, во всяком случае, передана.

В общем, на R17 в рамках одного процесса (ни сам себе с помощью !, ни любой другой процесс ему сообщение {counter, _} не шлет) подобное поведение получить не удалось. Так что либо какая-то экзотическая ситуация у вас в коде происходила, либо, как говорится, дьявол кроется в деталях.

Код функции:

-module(test).
-export([counter/0]).

counter() ->
  receive
    {counter, N} -> self() ! {counter, N+1}, N
  after 0 -> self() ! {counter, 0}, counter()
  end.

NegatiV
()
Ответ на: комментарий от NegatiV

подобное поведение получить не удалось

Я как бы намекнул, что ошибка возникает спонтанно, это должно было навести на мысль, что надо немного подумать, а не тупо вбивать код в REPL. Впрочем, может у квалифицированных эрланг-программистов, к которым я не отношусь, это не принято. BTW, ты исказил изначальный код, не было там counter() после elf() ! {counter, 0}.

fmdw
()
Ответ на: комментарий от fmdw

. BTW, ты исказил изначальный код, не было там counter() после elf() ! {counter, 0}.

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

NegatiV
()
Последнее исправление: NegatiV (всего исправлений: 1)
Ответ на: комментарий от anonymous

Еще один неосилятор, который решил, что он все понял.

Aswed ★★★★★
()
Ответ на: комментарий от stevejobs

Я бы такой прием не использовал хотя бы потому что скорость извлечения значения counter'а напрямую зависит от количества сообщений в ящике - чем их там больше, тем тормознее работает counter(). К тому же в OTP-модуль такое поведение не встроить - начнет срабатывать handle_info/3, да и сам факт того что любой процесс может отправить сообщение {counter, _} может прибавить гемора на ровном месте. Я бы использовал переменную состояния где бы хранился счетчик.

NegatiV
()
Ответ на: комментарий от NegatiV

Лень. Твой код тоже может привести к той же ошибке, так что можешь пользоваться им. Ещё одна подсказка: согласно законам природы все сообщения во всех сетях приходят мгновенно. Пинг всегда и везде 0.

fmdw
()
Ответ на: комментарий от stevejobs

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

nanoolinux ★★★★
()
Ответ на: комментарий от NegatiV

как именно ты бы реализовал глобальную переменную состояния, в которой хранится счетчик?

мне просто по работе нужно иногда пейсать на эрланге, пассивно изучаю его, от того и вопросы

stevejobs ★★★★☆
()
Ответ на: комментарий от fmdw

То что сообщения сразу (условно) попадают в mailbox я знаю, знаю даже что следом за after 0 идет решедулинг текущего процесса. Тем не менее я не вижу возможности текущему процессу во время решедулинга отправить себе сообщение.

NegatiV
()
Ответ на: комментарий от stevejobs

как именно ты бы реализовал глобальную переменную состояния, в которой хранится счетчик?

Здравствуйте, это канал про функциональное программирование? Как мне реализовать глобальную переменную?

fmdw
()
Ответ на: комментарий от fmdw

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

stevejobs ★★★★☆
()
Ответ на: комментарий от stevejobs

Два раза говорил, что это не мой код. Почему лорчане такие тугие?

fmdw
()
Ответ на: комментарий от stevejobs

Процесс-сервер, вестимо. gen_server возможно будет оверкиллом, но что-то вроде (псевдокод):

-module(counter).

create() ->
    Ref = make_ref(),
    Pid = spawn(?MODULE, loop, [{Ref, 0}]),
    {Ref, Pid}.

destroy({Ref, Pid}) ->
    Pid ! {destroy, Ref}.

inc({Ref, Pid}) ->
    Pid ! {inc, Ref}.

get({Ref, Pid}) ->
    Pid ! {get, Ref, self()},
    receive 
       X -> X
    end.

loop({X, Ref}) ->
    receive
        {destroy, Ref} -> ok;
        {inc, Ref} -> loop({X + 1, Ref});
        {get, Ref, Pid} -> Pid ! X, loop({X, Ref});
        _ -> loop({X, Ref})
    end.

NegatiV
()
Ответ на: комментарий от stevejobs

Чтобы сделать прям глобально-глобально регистрируешь Pid процесса-сервера, убираешь Ref и просто шлешь сообщения по имени процесса.

NegatiV
()
Ответ на: комментарий от NegatiV

То что сообщения сразу (условно) попадают в mailbox я знаю

Вообще-то в моём сообщении содержался сарказм. Они не сразу туда попадают, ибо у процесса есть два мэйлбокса: один из них он блочит сам при receive, а другой блочится другим процессом при !. Порядок этих локов + скедулинг самих процессов не детерминированы (или доказывай обратное).

Т.е. если дёргать counter() очень быстро и тред в это время получает другие сообщения от других тредов, возможна ситуация, когда {counter, N} не успевает приходить между двумя вызовами counter().

fmdw
()
Ответ на: комментарий от fmdw

Вообще-то в моём сообщении содержался сарказм. Они не сразу туда попадают, ибо у процесса есть два мэйлбокса: один из них он блочит сам при receive, а другой блочится другим процессом при !. Порядок этих локов + скедулинг самих процессов не детерминированы (или доказывай обратное).

Емнип, self-send оптимизирован как раз на мгновенную доставку в свой ящик.

UPD. понял все это может произойти после решедулинга в after 0.

NegatiV
()
Последнее исправление: NegatiV (всего исправлений: 2)
Ответ на: комментарий от stevejobs

Здравствуйте, доктор. Я закоренелый ФП'шник, но сейчас решил втянуться в ООП. Нравится инкапсуляция и четкое структурирование кода. Но в ООП больше время выполнения и дольше разработка проекта (если сравнивать разработку проекта с нуля на ФП и ООП без CMS/CMF). Можно быстро наговнокодить нормально работающий проект на ФП, а за это же время на ООП будет написано только ядро. Сейчас не знаю, нужен мне вообще ООП? Это как-нибудь лечится?))

zevilz ★★★
()
Ответ на: комментарий от stevejobs

А что это вы там в Axmor на эрланге пишете? У вас же суровый Java бодишоп. Клепаете круды на Java EE, верно?

anonymous
()
Ответ на: комментарий от anonymous

я сто лет не в Axmor. И работал не в бодишопе а в стартапе, пишущем компилятор. Так что не совсем понимаю, о чем ты =)

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от zevilz

поциент, что из ФП вы хотите иметь? Возможно, вам подойдет Scala? Возможно, никаких особо сильных противоречий и не образуется.

stevejobs ★★★★☆
()
Ответ на: комментарий от NegatiV

Прекрасно, с куском говнокода разобрались. Переход «давсёработает глобально и надёжно» в «ну да, вот если в вм есть такая-то оптимизация...» — это именно то, чего я и ждал.

А теперь я утверждаю, что надёжность и предсказуемость любого, абсолютно любого кода на эрланге, хоть трижды обёрнутого в behavior'ы равна надёжности этого образчика.

fmdw
()
Ответ на: комментарий от nanoolinux

Ну и что можно сказать о говнокоде кроме того, что это говнокод?

Я вроде писал, что этот код призван продемонстрировать некое общее свойство. Выходит, назвав его «говнокодом», ты заклеймил любую программу на эрланге. Беда!

fmdw
()
Ответ на: комментарий от fmdw

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

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.