я не хочу холиваров на хабре и вообще хочу конструктивного диалога :)
то что в начальном тексте у меня ошибка это ясно, глупо клонировать функцию вот так
when "[object Function]" then some.bind({})
а потом пытаться сравнивать вот так
when "[object Function]" then a.toString() == b.toString()
Но вот я поковырялся с интерпретатором, и в итоге прикрепляю скриншот того что получилось. Я вижу что функции тут — клонируемые по значению абстракции, и это парадоксально но похоже что сравниваются они тоже по значению. Прикрепляю скриншот чтобы ты не подумал что я жульничаю и набираю это всё в текстовом редакторе :)
Похоже всё работает как надо, но конечно если придерживаться определённых правил.
1) Однородность данных: сервер кидает клиенту через вебсокет сообщения которые содержат какие-то данные. Сервер написан на эрланге. Там нет никаких объектов — есть binaries, integers, floats, lists, maps. Именно в таком виде данные приходят клиенту. Если мы продолжим работать с этими данными именно как с данными а не как с объектами — это здорово снизит накладные расходы на написание всяческого рода классов, конструкторов, и прочих адаптеров erlang_data <=> js_data.
То же самое правило я кстати использую и по отношению в взаимодействию сервер <=> бд. То есть называю поля в эрланговских структурах в точности именами столбцов бд. Это реально здорово снижает накладные расходы, количество кода, увеличивает читаемость и прозрачность.
2) Мне гораздо проще читать / писать код, если он написан в парадигме моего основного языка.
Кстати насчёт == || === и прочего — в coffeescript многие подобные скользкие моменты решены, например == всегда разворачивается в ===, слова return нет — всегда возвращается результат последнего выражения в функции итп
Насчёт работы с реальным продакшном у меня сложилась поределённая схема, вот пример:
1) Вот html-страничка, нас интересует вот этот блок который собственно будет отрисовываться в jreact, там будет происходить весь экшн
4) А дальше уже всё в абсолютно свободном плавании — коллбэки висящие на кнопках, что-то летящее с сервера в вебсокет — всё это отправляет сообщения актору
Дело в том что я в своём коде не использую какие-то сложные, неоднозначные и уж тем более ООП стороны js.
а вы точно хотите на +0 == -0 получать true?
да :)
В моём понимании [head, tail...] — это просто список, а не объект и я никогда не переопределю для него поле length, в моём понимании length тут вообще не поле а метод (хотя судя по тому как он «вызывается» — это не так)
{key: value} — для меня не объект а просто map, хэш-таблица с парами key — value где key и value — любые js-данные, и поэтому я никогда не буду что-то там делать с прототипами
Насчёт when "[object Function]" then a.toString() == b.toString() — реально очень скользкий момент, но я увы так и не смог придумать как ещё можно сравнить две функции по значению. Разыменовывания указателя в js я так и не нашёл, это решило бы все подобные проблемы :(
a == b для примитивов у меня написано просто для красоты и однородности :) Да и мало ли что, просто изучать детально и глубоко реализацию всех типов данных в js не было ни времени ни сил ни желания
Не знаю)
Название я позаимствовал у одноимённого аналогичного макроса из библиотеки для ЯП Elixir которой пользуюсь. А вообще, возможно такое понятие как «монада» близко pipe_matching. «Возможно» — потому что Haskell я почти не знаю, так что за этот факт не могу ручаться.
При разработке на erlang / otp всегда есть 3 уровня абстракции — application, supervisor, gen_server. Application собственно — это дерево с корневым supervisor к которому привязаны другие supervisors, а gen_server в дереве — соответственно листья. И всё это динамическое — то есть может порождаться, прикрепляясь к какому-либо supervisor или умирать. В одном реальном приложении естественно может работать несколько otp-applications
Огромное спасибо за ценное замечание насчёт # — я реально проглядел так как ещё пока newbie в таких вещах, в репозитории исправлю обязательно перед использованием в продакшне)
Насчёт «читать внутреннее устройство макросов» — а зачем в этом случае это делать? Просто задаются некоторые правила ( в данном случае требуется паттерн первым аргументом и n-ное количество выражений ) и макрос гарантированно предоставляет определённую управляющую логику для этих выражений — в данном случае pipe matching с заданным pattern-ом (ну если конечно убрать этот баг с «res»))).
Какую логику тут использовать в качестве управляющей — сугубо дело вкуса. Для меня как для erlang-девелопера p.m. — это как глоток свежего воздуха в странноватом пока что для меня языке, вот я и использую его. Ну и строго говоря — предложенный вами вариант это просто частный случай p.m.
Использовал Idea для Erlang. Классная штука. Понравилось что слева наглядно показываются места где функции входят в рекурсию, ну и автодополнение очень крутое, для Elixir конечно пока такого нет
Тоже обожаю mix. Он может то что ребару и не снилось)
В статье не стал расписывать mix, OTP и макросы, дабы не перегружать. Хотя мне кажется надо бы про них написать подробнее, ведь в них самый сок
Я не знаю что такое «поиск в глубину и ширину», хотя это конечно не характеризует меня с хорошей стороны. Но я хотел показать что если язык лаконичен и красив, то писать нормальные программы сможет любой, даже с большими пробелами в фундаментальных знаниях. Конечно когда набираешься некоторого опыта — понимаешь что сам язык не так уж и важен. Я просто заметил что Elixir учит меня думать более красиво. А дальше с этим умением можно будет писать нормально «хоть на php».
почему не более компактный JSON или не более читаемый и простой YAML?
Видимо реально проще использовать fay или purescript :)
Это конечно прекрасно :)
Но похоже что это не работает для списков и структур
habrastorage.org/files/91d/83a/ad4/91d83aad404b4e6d8d19082e95e98c33.png
после строчки
f1 = () -> 123
f2 тоже не изменилась, если при присваивании функций данные передаются по указателю? Если в таком случае после второй строчки
f2 = new () -> f1
память всё же выделяется под новую функцию — то тогда почему в третьей строчке они равны?
правда не знаю можно ли из этого извлечь что-то для моей задачи, подумаю над этим на досуге
то что в начальном тексте у меня ошибка это ясно, глупо клонировать функцию вот так
when "[object Function]" then some.bind({})
а потом пытаться сравнивать вот так
when "[object Function]" then a.toString() == b.toString()
Но вот я поковырялся с интерпретатором, и в итоге прикрепляю скриншот того что получилось. Я вижу что функции тут — клонируемые по значению абстракции, и это парадоксально но похоже что сравниваются они тоже по значению. Прикрепляю скриншот чтобы ты не подумал что я жульничаю и набираю это всё в текстовом редакторе :)
Похоже всё работает как надо, но конечно если придерживаться определённых правил.
1) Однородность данных: сервер кидает клиенту через вебсокет сообщения которые содержат какие-то данные. Сервер написан на эрланге. Там нет никаких объектов — есть binaries, integers, floats, lists, maps. Именно в таком виде данные приходят клиенту. Если мы продолжим работать с этими данными именно как с данными а не как с объектами — это здорово снизит накладные расходы на написание всяческого рода классов, конструкторов, и прочих адаптеров erlang_data <=> js_data.
То же самое правило я кстати использую и по отношению в взаимодействию сервер <=> бд. То есть называю поля в эрланговских структурах в точности именами столбцов бд. Это реально здорово снижает накладные расходы, количество кода, увеличивает читаемость и прозрачность.
2) Мне гораздо проще читать / писать код, если он написан в парадигме моего основного языка.
в эрланге например можно
насчёт js — нет, в лоб это не работает
coffee> f1 = () -> 123
[Function]
coffee> f2 = () -> 123
[Function]
coffee> f1 == f2
false
coffee> f1.toString() == f2.toString()
true
можно конечно использовать toString, но как было верно подмечено это костыль :)
Насчёт работы с реальным продакшном у меня сложилась поределённая схема, вот пример:
1) Вот html-страничка, нас интересует вот этот блок который собственно будет отрисовываться в jreact, там будет происходить весь экшн
github.com/timCF/megaweb/blob/c90ede0e0c48373712695fb5a3e3b77247c6f6a7/app/index.jade#L12
2) Вот сам виджет который будет рисоваться пользователю в зависимости от состояния state
github.com/timCF/megaweb/blob/c90ede0e0c48373712695fb5a3e3b77247c6f6a7/app/widget.jreact
3) Когда DOM первый раз построился — мы врубаем jreact через актор
github.com/timCF/megaweb/blob/c90ede0e0c48373712695fb5a3e3b77247c6f6a7/app/scripts/app.coffee#L88-91
4) А дальше уже всё в абсолютно свободном плавании — коллбэки висящие на кнопках, что-то летящее с сервера в вебсокет — всё это отправляет сообщения актору
github.com/timCF/megaweb/blob/c90ede0e0c48373712695fb5a3e3b77247c6f6a7/app/scripts/app.coffee#L51
который строго в порядке очереди их вызывает, обновляя свой внутренний state
5) Периодически опрашиваем актор — получаем копию его текущего state и передаём в react который рисует пользователю страничку
github.com/timCF/megaweb/blob/c90ede0e0c48373712695fb5a3e3b77247c6f6a7/app/scripts/app.coffee#L68
а вы точно хотите на +0 == -0 получать true?
да :)
В моём понимании [head, tail...] — это просто список, а не объект и я никогда не переопределю для него поле length, в моём понимании length тут вообще не поле а метод (хотя судя по тому как он «вызывается» — это не так)
{key: value} — для меня не объект а просто map, хэш-таблица с парами key — value где key и value — любые js-данные, и поэтому я никогда не буду что-то там делать с прототипами
Насчёт when "[object Function]" then a.toString() == b.toString() — реально очень скользкий момент, но я увы так и не смог придумать как ещё можно сравнить две функции по значению. Разыменовывания указателя в js я так и не нашёл, это решило бы все подобные проблемы :(
a == b для примитивов у меня написано просто для красоты и однородности :) Да и мало ли что, просто изучать детально и глубоко реализацию всех типов данных в js не было ни времени ни сил ни желания
Название я позаимствовал у одноимённого аналогичного макроса из библиотеки для ЯП Elixir которой пользуюсь. А вообще, возможно такое понятие как «монада» близко pipe_matching. «Возможно» — потому что Haskell я почти не знаю, так что за этот факт не могу ручаться.
www.erlang.org/doc/man/application.html
www.erlang.org/doc/design_principles/sup_princ.html
www.erlang.org/doc/man/gen_server.html
Насчёт «читать внутреннее устройство макросов» — а зачем в этом случае это делать? Просто задаются некоторые правила ( в данном случае требуется паттерн первым аргументом и n-ное количество выражений ) и макрос гарантированно предоставляет определённую управляющую логику для этих выражений — в данном случае pipe matching с заданным pattern-ом (ну если конечно убрать этот баг с «res»))).
Какую логику тут использовать в качестве управляющей — сугубо дело вкуса. Для меня как для erlang-девелопера p.m. — это как глоток свежего воздуха в странноватом пока что для меня языке, вот я и использую его. Ну и строго говоря — предложенный вами вариант это просто частный случай p.m.
Как химик говорю.
ru.wikipedia.org/wiki/%D0%9D%D0%B8%D0%BA%D0%B5%D0%BB%D1%8C_%D0%A0%D0%B5%D0%BD%D0%B5%D1%8F
Добро пожаловать в 1926 год
На самом деле возможности эликсировских макросов имхо плохо документированы, по крайней мере на официальном сайте
В статье не стал расписывать mix, OTP и макросы, дабы не перегружать. Хотя мне кажется надо бы про них написать подробнее, ведь в них самый сок