Здравствуйте, Mink, Вы писали:
M>Здравствуйте, Gaperton, Вы писали:
G>>{ Колесо, МашинаБезКолеса } = снятьПереднееКолесо( Машина, Ключ ). G>>Так лучше?
M>Нет. Лучше: M>машина.СнятьПереднееКолесо(ключ);
Кто снимает колесо? Умная машина, так выходит? Мне ей только надо отправить сообщение — "снять переднее колесо", и приложить к нему ключ. Машины они такие, все с первого слова понимают.
Согласен, так лучше, зачем самому корячиться
А если серьезно, то абсолютно пофигу, как писать. Разница между ФЯ и не ФЯ будет только в результате операции. Если она вернет измененный объект как часть результата, не тронув предыдущий — это функциональный стиль. Вот и весь пафос.
Здравствуйте, Mink, Вы писали:
M>Во первых, такое элементарно реализуется на ИЯ. M>Во вторых, с точки зрения читабельности кода первый вариант мне больше нравится.
Кому-то нужны пошаговые инструкции, а кому-то — образ результата.
К примеру с колесом:
1.1)
Приезжает дама на сервис, и говорит мастеру: "возьми ключ 19, поставь домкрат, поочерёдно отверни 4 болта с колеса, подними машину, сними колесо, .............., получи деньги, конец".
Что сделает мастер? Спросит "За кого ты меня держишь, *****?".
1.2)
... и говорит: "Проколото левое заднее колесо. Вот деньги, вот машина, почините плиз."
2.1)
Мастер принял заказ и передаёт машину подмастерью со словами "Вот машина, вот инструменты, вот ремкомплект, вперёд".
Подмастерье спрашивает: "Как, чёрт побери?"
2.2)
со словами "возьми ключ 19, ........., а деньги я тебе в конце смены отдам, конец".
2.3)
со словами "Чтобы починить колесо, нужно его снять, диагностировать, заклеить..... Чтобы его снять, нужно отвинтить болты и поддомкратить машину....."
Здравствуйте, Mink, Вы писали:
M>Здравствуйте, Nick_, Вы писали:
N_>>Здравствуйте, Mink, Вы писали:
M>>>Здравствуйте, Gaperton, Вы писали:
G>>>>{ Колесо, МашинаБезКолеса } = снятьПереднееКолесо( Машина, Ключ ). G>>>>Так лучше?
M>>>Нет. Лучше:
M>>>машина.СнятьПереднееКолесо(ключ);
N_>>А теперь сравните:
N_>>машина.СнятьКолесо(); N_>>машина.Починить(); N_>>машина.ОдетьКолесо();
N_>>и
N_>>ОдетьКолесо(Починить(СнятьКолесо(машина)))
M>Во первых, такое элементарно реализуется на ИЯ. M>Во вторых, с точки зрения читабельности кода первый вариант мне больше нравится.
Здравствуйте, Gaperton, Вы писали:
G>А если серьезно, то абсолютно пофигу, как писать. Разница между ФЯ и не ФЯ будет только в результате операции. Если она вернет измененный объект как часть результата, не тронув предыдущий — это функциональный стиль. Вот и весь пафос.
Насчет пофиг я, пожалуй, не соглашусь
Вообще, насчет легкости восприятия языковых конструкций по момему лучше всего сказал Элджер:
«Простые и последовательные» языки никогда не пользовались особым успехом за стенками академий, а языки с блочной структурой овладели массами. Стоит ли этому удивляться? Ведь компьютерные языки приходится изучать и запоминать, а для этого используется то же серое вещество, с помощью которого мы изучаем и запоминаем естественные языки. Попробуйте-ка назвать хотя бы один естественный язык без существительных, глаголов и скобок! Я бы не рискнул. Все наши познания в лингвистике говорят о том, что эти «плохие» особенности только ускоряют изучение компьютерного языка и делают его более понятным. i++ во всех отношениях действительно понятнее, чем i:=i+1, а x=17+29 читается лучше, нежели (setq(x(+17, 29)). Речь идет не о строении компьютерного языка, а скорее о нашем собственном строении.
DG>>Как об этом узнает модуль-визуализатор?
N_>Если "ссылка" внешняя для программы, то работать с ней надо так же как с вводом-выводом. N_>Если эта "ссылка" для программы внутренняя, то один модуль просто передает обновленные данные другому по значению. И уже дело компилятора как передать его на самом деле. По ссылке или как-то по другому.
По значению данные передадуться только один раз, а необходимо чтобы данные передавались постоянно причем измененные, т.е. фактически нужна передача по ссылке, а не по значению.
Допустим у нас распределенная система — есть что-то (объект, функция — не важно)-сервер, и есть что-то клиенты.
Клиенты могут независимо менять сервер, при этом все остальные клиенты должны работать уже с измененным состоянием.
И вот не понятно, как это будет выглядить на ФЯ.
ps
На объектах это выглядит просто:
class Server
{
public int Value;
}
class Client
{
public Client(Server server) {this.server = server;}
Server server;
public void OnTick()
{
if (new Random().Next(2) == 0)
server.Value++;
Out.Write(server.Value);
}
}
void Main()
{
Server server =new Server();
Timer timer = new Timer();
timer.Interval = 10;
timer.Start();
for (int i = 0; i < 10; ++i)
{
Client client = new Client(server);
timer.Tick += server.OnTick;
}
}
Здравствуйте, DarkGray, Вы писали:
DG>По значению данные передадуться только один раз, а необходимо чтобы данные передавались постоянно причем измененные, т.е. фактически нужна передача по ссылке, а не по значению.
Фактически, передача чего-то по ссылке — это передача не данных, а функции доступа.
Говоря на C++,
void foo(int& bar)
{
x = bar; sleep();
y = bar; sleep();
z = bar; sleep();
bar = t;
}
////////////////////void foo(/*byval*/int(*get)(), /*byval*/void(*put)(int))
{
x = get(); sleep();
y = get(); sleep();
z = get(); sleep();
put(t);
}
Здравствуйте, DarkGray, Вы писали:
DG>>>Как об этом узнает модуль-визуализатор?
N_>>Если "ссылка" внешняя для программы, то работать с ней надо так же как с вводом-выводом. N_>>Если эта "ссылка" для программы внутренняя, то один модуль просто передает обновленные данные другому по значению. И уже дело компилятора как передать его на самом деле. По ссылке или как-то по другому.
DG>По значению данные передадуться только один раз, а необходимо чтобы данные передавались постоянно причем измененные, т.е. фактически нужна передача по ссылке, а не по значению.
DG>Допустим у нас распределенная система — есть что-то (объект, функция — не важно)-сервер, и есть что-то клиенты.
DG>Клиенты могут независимо менять сервер, при этом все остальные клиенты должны работать уже с измененным состоянием.
DG>И вот не понятно, как это будет выглядить на ФЯ.
По другому. Вот чисто функциональный вариант, когда все происходит одном процессе.
Главная функция — менеджер событий. Из нее вызывается сервер, и все клиенты. Elrang.
eventCycle( { Server, Clients } ) ->
receive
after 1000
eventCycle( processEvent( fun OnTick/2, Clients, Server, [] ) )
end.
processEvent( EventHandler, [ Client | Clients ], Server, UpdatedClients ) ->
{ UpdatedClient, UpdatedServer } = EventHandler( Client, Server ),
processEvent( Clients, UpdatedServer, [ UpdatedClient | UpdatedClients ] ) ];
processEvent( [], Server, UpdatedClients ) -> { Server, UpdatedClients }.
OnTick( Client, Server ) ->
%% do something, for example
{ Client, Server + 1 }.
Я надеюсь, принцип понятен — это можно обобщить до произвольных событий и реализовать подписку.
Если приложение будет распределенным, то решение на Erlang будет отчасти императивным. Мы запустим по одному процессу на сервер и каждого клиента, и они будут обмениваться сообщениями. Каждый процесс реализуется бесконечно рекурсивной функцией, содержащей обработчик сообщений. Логика внутри процессов будет сделана на чистых функциях.
Здравствуйте, Mink, Вы писали:
M>Здравствуйте, Gaperton, Вы писали:
G>>А если серьезно, то абсолютно пофигу, как писать. Разница между ФЯ и не ФЯ будет только в результате операции. Если она вернет измененный объект как часть результата, не тронув предыдущий — это функциональный стиль. Вот и весь пафос.
M>Насчет пофиг я, пожалуй, не соглашусь
Имелось в виду Obj.Method( Parm ) или Method( Obj, Parm ).
Меня смущает идентификатор "МашинаБезКолеса".
Это же получается, что также будут идентификаторы "МашинаБезДвухКолес", "МашинаБезКолесаИБампера", "МашинаСКолесамиНоБезЗапаски" и т.д., т.е. на лицо комбинаторный взрыв, причем не понятно, как этого можно будет избежать в реальном проекте.
К>>Фактически, передача чего-то по ссылке — это передача не данных, а функции доступа.
DG>Согласен. Но функция опять же откуда должна брать меняющиеся данные...
Если вы будуте хранить изменяющиеся данные в общей памяти, то ваша программа будет работать только в одном потоке.
Либо вам придется расставлять критические секции где попало. При этом не факт, что вы правильно с первого раза расставите критические секции и избежите взаимных блокировок.
Да, в функциональных языках для вас будет немного необычно написать то, что хотите. Зато компилятор сможет ее автоматически распараллелить.
G>>{ Колесо, МашинаБезКолеса } = снятьПереднееКолесо( Машина, Ключ ). G>>Так лучше?
DG>Меня смущает идентификатор "МашинаБезКолеса". DG>Это же получается, что также будут идентификаторы "МашинаБезДвухКолес", "МашинаБезКолесаИБампера", "МашинаСКолесамиНоБезЗапаски" и т.д., т.е. на лицо комбинаторный взрыв, причем не понятно, как этого можно будет избежать в реальном проекте.
Я уже писал.
новая_машина = одеть(починить(снять(машина)))
DG>>Согласен. Но функция опять же откуда должна брать меняющиеся данные...
N_>Если вы будуте хранить изменяющиеся данные в общей памяти, то ваша программа будет работать только в одном потоке.
Вы ушли от вопроса.
На данный момент мне пофигу на блокировки, синхронизацию и т.д.
Сейчас мне интересно видеть, как две независимых части программы получают меняющиеся данные.
От Вас я услышал пока только одни общие слова "ФЯ — крутая парадигма, и там таких проблем нет", и не увидел ни одного конкретного примера.
Создается ощущение, что Вы не понимаете о чем Вас спрашивают, а только повторяете заученные слова.
Здравствуйте, DarkGray, Вы писали:
DG>>>Согласен. Но функция опять же откуда должна брать меняющиеся данные...
N_>>Если вы будуте хранить изменяющиеся данные в общей памяти, то ваша программа будет работать только в одном потоке.
DG>Вы ушли от вопроса. DG>На данный момент мне пофигу на блокировки, синхронизацию и т.д. DG>Сейчас мне интересно видеть, как две независимых части программы получают меняющиеся данные. DG>От Вас я услышал пока только одни общие слова "ФЯ — крутая парадигма, и там таких проблем нет", и не увидел ни одного конкретного примера. DG>Создается ощущение, что Вы не понимаете о чем Вас спрашивают, а только повторяете заученные слова.
Чесно говоря, я не понимаю вопроса.
если есть глобальные для программы данные, которые могут меняться обоими модулями, то модули должны их передавать друг другу по очереди. Если меняет один модуль, а другой только доступается, то первый модуль вызывает второй и передает ему данные, либо второй модуль вызывает первый что бы тот вернул ему эти данные. Я не понимаю в чем тут трудность?
Если бы вы привели пример кода на каком-нибудь императивном псевдоязыке, то я бы смог привести анологичный пример на функциональном языке.
N_>Чесно говоря, я не понимаю вопроса. N_>если есть глобальные для программы данные, которые могут меняться обоими модулями, то модули должны их передавать друг другу по очереди.
Есть глобальные данные, которые меняются и читаются несколькими независимыми модулями.
ps
Независимые означает, что модули друг о друге не знают
N_>Если бы вы привели пример кода на каком-нибудь императивном псевдоязыке, то я бы смог привести анологичный пример на функциональном языке.
ЗDG>Есть глобальные данные, которые меняются и читаются несколькими независимыми модулями.
DG>ps DG>Независимые означает, что модули друг о друге не знают
Глобальных данных в функциональном программировании не существует.
Придется передавать эти данные клиенту и серверу явно.
Доступ к любым внешним данным или разделяемой памяти делается так же как и ввод-вывод, иначе компилятор не сможет отследить от каких данных зависит ваша программа. Синхронизацию операций ввода-вывода должна обеспечить среда выполнения.
Суть чистых функций как раз в том, что все побочные эффекты выражены явно. Если процедура что-то изменяет, то это что-то должно быть в нее явно переданно и потом возвращено обратно измененным. Это позволяет компилятору увидеть суть того что вы хотите сделать.
N_>>Если бы вы привели пример кода на каком-нибудь императивном псевдоязыке, то я бы смог привести анологичный пример на функциональном языке.
DG>http://www.rsdn.ru/Forum/Message.aspx?mid=793251&only=1
N_>Глобальных данных в функциональном программировании не существует.
Нет, не только глобальных данные — нет, вообще, общих данных.
N_>Придется передавать эти данные клиенту и серверу явно.
Для больших программ — это подобно смерти, т.к. получается что каждый модуль должен знать обо всех остальных модулях.
Получается, что обязательно должен быть человек, которые будет держать в голове все зависимости между всеми модулями.
т.е. фактически не получается модульного программирования
Здравствуйте, DarkGray, Вы писали:
DG>Вы ушли от вопроса. DG>На данный момент мне пофигу на блокировки, синхронизацию и т.д. DG>Сейчас мне интересно видеть, как две независимых части программы получают меняющиеся данные. DG>От Вас я услышал пока только одни общие слова "ФЯ — крутая парадигма, и там таких проблем нет", и не увидел ни одного конкретного примера. DG>Создается ощущение, что Вы не понимаете о чем Вас спрашивают, а только повторяете заученные слова.
Ну, ФЯ — крутая парадигма, и там таких проблем нет
С отходом от функционального стиля в OCaml это делается так
let my_inc_thread r iv () =
for i=1 to 10 do
r := !r + iv;
Printf.printf "(%d)" !r;
flush stdout
done in
let x = ref 3 in (* Императивная переменная, меняющая значения *)
let t1 = Thread.create (my_inc_thread x 1) () in
let t2 = Thread.create (my_inc_thread x 100) () in
Thread.join t1;
Thread.join t2
Два треда инкрементят одну переменную.
В чисто функциональном стиле это тоже делается. Даже более изящно. Как всегда, через монады. Т.е. в треде есть функция, которая принимает аргументом старое состояние, ждет сигнала, на основе его и старого состояние делает новое и вызывает (или не вызывает) саму себя уже с новым состоянием. Если интересно — могу набросать код. А лучше почитай O'Reillyвскую книжку — там все это есть.