1. Pattern matching / Соответствие шаблонам.
соответствие шаблонам - это сравнение одной структуры данных (шаблона) с другой (конкретной) структурой данных, и, в случае их соответствия заполнение "шаблонных" переменных данными, располагающимися в структуре данных.
мне оччень понравилось, как оно сделано на эрланге:
{cmd, CMD_NAME, [params,[FIRST_PARAM|OTHER_PARAMS]], cmd_end} = {cmd, "MY SUPER COMMAND", [params,[1, 2,3]], cmd_end}.
cmd, cmd_end - это символы эрланга. просто символы, то же самое, для чего в scheme использовалась бы нотация 'cmd и 'cmd_endCMD_NAME, FIRST_PARAM, OTHER_PARAMS - это "переменные", в которые произойдёт подстановка при совпадении с шаблоном. переменные в erlang'е начинаюся с большой буквы (как понимаю, нужно, дабы отличить от символов).
После приведённой выше программы, "переменные" CMD_NAME, FIRST_PARAM, OTHER_PARAMS будут равны "MY SUPER COMMAND", 1 и [2,3] соответственно.
но и scheme оказывается может нас порадовать паттерн-матчингом (но не как языковой конструкцией, а как отдельной библиотекой).
Так, предыдущее выражение, написанное на scheme выглядело бы так:
(match
(list 'cmd "MY SUPER COMMAND" (list 'params (list 1 2 3)) 'cmd_end)
(
(list 'cmd cmd_name (list 'params (cons first_param other_params)) 'cmd_end); <-- шаблон
(list cmd_name first_param other_params) ; <-- функция-обработчик успешного результата
)
)
c одним небольшим нюансом: sheme необходимо указывать функцию, которая бы сразу обработала эти параметры (при совпадении). Что особенно порадовало, так это наличие регулярных выражений в сравнении, т.е. такая конструкция работает:
(match
(list 'cmd "MY SUPER COMMAND" (list 'params (list 1 2 3)) 'cmd_end)
(
(list 'cmd (regexp "SUPER(.*)" cmd_name) (list 'params (cons first_param other_params)) 'cmd_end); <--шаблон
(list (cadr cmd_name) first_param other_params) ; <-- функция-обработчик успешного результата
)
)
2. Легковесные процессы, отправка сообщений
это тоже приятная (и одна из основных) фишек erlang. так просто выглядит создание процесса на этом языке:
test_proc()->io:format("hello, world!~n").
Pid = spawn(fun test_proc/0).
отправка сообщений выглядит потрясающе: Pid ! message
например, Pid ! {hello, self()}
приём сообщений делается внутри порождаемой процедуры:
test_proc()->
some_before_commands(),
receive
{Message, Pid}->io:format("received message ~s from ~w", [Message, Pid])
end,
some_after_commands(),
test_proc().
При чём, как я понял, этот процесс встречая команду receive, ждёт сообщений (т. е. если бы после receive-ного end-а у нас стояли комманды, они бы не выполнились до того, как принято и обработано сообщение. Внутри блока receive идёт pattern matching сообщений, и если сообщение совпадает с шаблоном, то оно обрабатывается и управление передаётся за блок receive. Если же сообщение не попадает под шаблон, то, как я понял, ждём следующего сообщения, не передавая никуда управления.
в scheme создание потока тоже не отличается особой громоздкостью:
(define (test) (display "hello, world!") (newline) (test) )
(thread test)
сообщения так же поддерживаются =) называются mail-boxes
(define (test)
(display "before") (newline)
(let ((msg (thread-receive)))
(display msg)
(newline)
)
(display "after") (newline) (test)
)
(define t (thread test))
(thread-send t (list 'message 'main))
единственное, что не происходит pattern-matching для сообщения, но если необходимо, то можно просто добавить его вручную
НО. у erlanga очень хорошо обыграна связь между сообщениями. так, если процесс завершается, то он может послать связанным процессам сообщение о завершении, которые они обязаны будут обработать (иначе завершатся)
И ещё erlanga есть супервизоры, которые только и следят за жизнью процессов и (если необходимо) перезапускают их, но об этом в другой раз
test_proc()->io:format("hello, world!~n").
Pid = spawn(fun test_proc/0).
отправка сообщений выглядит потрясающе: Pid ! message
например, Pid ! {hello, self()}
приём сообщений делается внутри порождаемой процедуры:
test_proc()->
some_before_commands(),
receive
{Message, Pid}->io:format("received message ~s from ~w", [Message, Pid])
end,
some_after_commands(),
test_proc().
При чём, как я понял, этот процесс встречая команду receive, ждёт сообщений (т. е. если бы после receive-ного end-а у нас стояли комманды, они бы не выполнились до того, как принято и обработано сообщение. Внутри блока receive идёт pattern matching сообщений, и если сообщение совпадает с шаблоном, то оно обрабатывается и управление передаётся за блок receive. Если же сообщение не попадает под шаблон, то, как я понял, ждём следующего сообщения, не передавая никуда управления.
в scheme создание потока тоже не отличается особой громоздкостью:
(define (test) (display "hello, world!") (newline) (test) )
(thread test)
сообщения так же поддерживаются =) называются mail-boxes
(define (test)
(display "before") (newline)
(let ((msg (thread-receive)))
(display msg)
(newline)
)
(display "after") (newline) (test)
)
(define t (thread test))
(thread-send t (list 'message 'main))
единственное, что не происходит pattern-matching для сообщения, но если необходимо, то можно просто добавить его вручную
НО. у erlanga очень хорошо обыграна связь между сообщениями. так, если процесс завершается, то он может послать связанным процессам сообщение о завершении, которые они обязаны будут обработать (иначе завершатся)
И ещё erlanga есть супервизоры, которые только и следят за жизнью процессов и (если необходимо) перезапускают их, но об этом в другой раз
Комментариев нет:
Отправить комментарий