Написал в учебных целях утилиту для разбора build-output'а (Visual Studio/Incredibuild). Код тут.
Классно, что в Эрланге гарантируется очередность отправки/получения сообщений, то есть при определенных условиях можно гарантировать, что порядок вызова "методов" и порядок их обработки совпадут. Такой подход обеспечивает все плюсы модели Actor'ов (или MPI, как угодно) на уровне взаимодействия процессов, и плюсов функционального стиля на уровне реализации процессов.
Нужно также заметить (я сразу скептически отнесся к "еще одному динамически-типизированному языку"), что Эрланг намного статически типизирован (или менее динамически типизирован) чем, например, Python: он на этапе компиляции точно "знает", какие функции (наверное кроме анонимных) определены в компилируемом модуле, а это есть одно из необходимых условий оптимизации хвостовой рекурсии (далеко не во всех динамически-типизированных языках это возможно); также он делает проверку структуры (я бы не называл это проверкой типов), например компиляция кода:
...
A = atata,
ololo = A,
...
выдаст "Warning: no clause will ever match". То есть, Эрланг пробует унифицировать все, о чем есть информация на этапе компиляции. Правда делает он это только на уровне функции (но и это уже не мало). Такой код, например, компилируется без ошибки, хотя вызов f() будет с ошибкой:
...
f() -> g(ololo).
g(atata) -> void.
...
...
A = atata,
ololo = A,
...
выдаст "Warning: no clause will ever match". То есть, Эрланг пробует унифицировать все, о чем есть информация на этапе компиляции. Правда делает он это только на уровне функции (но и это уже не мало). Такой код, например, компилируется без ошибки, хотя вызов f() будет с ошибкой:
...
f() -> g(ololo).
g(atata) -> void.
...
Кроме этого Эрланг проверяет определена ли используемая переменная, а также используется ли ранее определеная переменная. То есть код:
...
f() -> A = B.
...
во время компиляции выдаст:
Error: variable 'B' is unbound
Warning: variable 'A' is unused
...
f() -> A = B.
...
во время компиляции выдаст:
Error: variable 'B' is unbound
Warning: variable 'A' is unused
Ну и конечно же ООП
Значит придумалось мне снабжать процесс функцией, которая "подготавливает" для него каждое сообщение, в частности как отправлять (синхронно/асинхронно) и отправлять ли вообще (оборачиваем функцией wrap_pid/2; пример create_base/0). В результате мой объект понимает "методы" status (синхронно), exit (асинхронно) и строковые константы (тоже асинхронно). Пример работы функция test/0.
Была также интересная у меня проблема, когда процессу отправлялись два сообщения одно за другим, причем первое это exit, а второе какое-то синхронное. В таком случае процесс-отправитель может заблокироваться, так как он будет ожидать ответ на второе сообщение. Решить это помог receive из timeout'ом (функция receive_alive/1).
«он "знает" о всех функциях модуля, что позволяет оптимизировать хвостовую рекурсию» — чтобы оптимизировать хвостовую рекурсию, эрлангу достаточно посмотреть, что результат функции сразу возвращается вверх, что над ним не производится вычислений.
ВідповістиВидалитиЭто понятно, но все таки в динамически типизированных языках нужно еще и "знать" о функциях. В питоне например хвостовая рекурсия не оптимизируется, потому что нет гарантий, что вызываемая функция, это именно та, что нужно.
ВидалитиВы пишите странные вещи. То, что вы перечислили, конечно, соответствует истине и удобно, но, увы, никак не связано со статической типизацией.
ВідповістиВидалити>> он "знает" о всех функциях модуля
Попробуйте:
external_module:no_such_function_bebebe(A,B,C)
"намного статически типизирован чем" не значит статически типизирован. Можете читать это как "менее динамически типизирован". А насчет "знает", я имел ввиду о функциях данного (который компилируется) модуля. Это наверное совсем незаметное требование для оптимизации хвостовой рекурсии: определять и вызывать функцию рекурсивно в ТОМ ЖЕ МОДУЛЕ, для того чтобы хвостовая рекурсия оптимизировалась.
ВидалитиКак вы можете компилируя свой модуль добиться оптимизации хвостовой рекурсии этой внешней "external_module:no_such_function_bebebe(A,B,C)" функции?