Русский
Русский
English
Статистика
Реклама

Clojure

Перевод Reagent Минималистичный React для ClojureScript

29.07.2020 14:20:10 | Автор: admin
Хабр, привет.

Я PM, которые лезет в то, что его может сожрать. Так что, я перевела часть документации по Reagent, если будет полезно, выложу продолжение.


In the no-holds-barred world of coding, the end justifies the extreme.

Введение в Reagent


Reagent обеспечивает минималистичное взаимодействие между ClojureScript и React. Он позволяет вам создавать эффективные компоненты React, используя только простые функции ClojureScript и данные, которые описывают пользовательский интерфейс, используя Hiccup-подобный синтаксис.

Цель Reagent сделать возможным создание произвольно сложных пользовательских интерфейсов, используя пару основных понятий, и быть по-умолчанию достаточно быстрым, чтобы вам редко приходилось думать о производительности.

Простейший компонент Reagent

может выглядеть примерно так:
(defn simple-component []  [:div   [:p "I am a component!"]   [:p.someclass    "I have " [:strong "bold"]    [:span {:style {:color "red"}} " and red "] "text."]])





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

Как в этом примере:
(defn simple-parent []  [:div   [:p "I include simple-component."]   [simple-component]])




Данные передаются дочерним компонентам с помощью простых типов данных Clojure.

Как в этом примере:
(defn hello-component [name]  [:p "Hello, " name "!"])(defn say-hello []  [hello-component "world"])




Примечание: В приведенном выше примере hello-component можно было бы точно так же вызвать как нормальную функцию Clojure, а не как компонент Reagent, т.е. с круглыми скобками вместо квадратных скобок. Единственным отличием была бы производительность, так как реальные компоненты Reagent перерисовываются только тогда, когда их данные изменились. Однако более продвинутые компоненты (см. ниже) должны вызываться в квадратных скобках.

Вот еще один пример, который рендерит список элементов:
(defn lister [items]  [:ul   (for [item items]     ^{:key item} [:li "Item " item])])(defn lister-user []  [:div   "Here is a list:"   [lister (range 3)]])




Примечание: приведенная выше часть ^{: key item} на самом деле не является необходимой в этом простом примере, но добавление уникального ключа к каждому элементу в динамически генерируемом списке компонентов является хорошей практикой и и увеличивает производительность рендеринга больших списков. Ключ может быть задан либо (как в этом примере) как метаданные, либо как элемент :key в первом аргументе компонента (если это map). Дополнительную информацию смотрите в документации React.

Управление состоянием в React


Самый простой способ управлять состоянием использовать собственную версию atom из Reagent. Он работает точно так же, как и в clojure.core, за исключением того, что при каждом использовании дерефается/разыменовывается (deref). Любой компонент, использующий atom, автоматически ререндерится при изменении его значения.

Продемонстрируем это на простом примере:
(ns example  (:require [reagent.core :as r]))(def click-count (r/atom 0))(defn counting-component []  [:div   "The atom " [:code "click-count"] " has value: "   @click-count ". "   [:input {:type "button" :value "Click me!"            :on-click #(swap! click-count inc)}]])




Иногда вы можете захотеть использовать локальный стейт в компоненте. Это легко сделать и с атомом.

Мы вызываем setTimeout, и каждый раз компонент перерендеривается с обновленным счетчиком:
Вот пример
(ns example  (:require [reagent.core :as r]))(def click-count (r/atom 0))(defn counting-component []  [:div   "The atom " [:code "click-count"] " has value: "   @click-count ". "   [:input {:type "button" :value "Click me!"            :on-click #(swap! click-count inc)}]])




В предыдущем примере также используется другая особенность Reagent: компонентная функция может возвращать другую функцию, которая используется для фактического рендеринга. Эта функция вызывается с теми же аргументами, что и первая.

Это позволяет выполнить некоторую настройку вновь создаваемых компонентов, не прибегая к событиям жизненного цикла Reagent.

Просто передавая атом, вы можете разделить управление состоянием между компонентами.

Как это делается:
(ns example  (:require [reagent.core :as r]))(defn atom-input [value]  [:input {:type "text"           :value @value           :on-change #(reset! value (-> % .-target .-value))}])(defn shared-state []  (let [val (r/atom "foo")]    (fn []      [:div       [:p "The value is now: " @val]       [:p "Change it here: " [atom-input val]]])))




Замечание: Функции компонентов могут вызываться с любыми аргументами до тех пор, пока они неизменны. Вы могли бы использовать и мутабельные структуры, но тогда было бы необходимо убедиться, что компонент ререндерится при изменении данных. Reagent предполагает по-умолчанию, что два объекта равны, если они являются одним и тем же объектом.

Основное API



Reagent поддерживает большинство API React, но на самом деле существует только одна точка входа, необходимая для большинства приложений: reagent.dom/render.

Требуется два аргумента: компонент и DOM-узел.

Например, код самого первого примера по странице будет выглядеть так:
(ns example  (:require [reagent.core :as r]))(defn simple-component []  [:div   [:p "I am a component!"]   [:p.someclass    "I have " [:strong "bold"]    [:span {:style {:color "red"}} " and red "] "text."]])(defn render-simple []  (rdom/render    [simple-component]    (.-body js/document)))


Складывая все вместе


Вот более жизненный пример: простой калькулятор BMI.

Данные хранятся в одном reagent.core/atom: map со следующими ключами: высота, вес и BMI.
(ns example  (:require [reagent.core :as r]))(defn calc-bmi [{:keys [height weight bmi] :as data}]  (let [h (/ height 100)]    (if (nil? bmi)      (assoc data :bmi (/ weight (* h h)))      (assoc data :weight (* bmi h h)))))(def bmi-data (r/atom (calc-bmi {:height 180 :weight 80})))(defn slider [param value min max invalidates]  [:input {:type "range" :value value :min min :max max           :style {:width "100%"}           :on-change (fn [e]                        (let [new-value (js/parseInt (.. e -target -value))]                          (swap! bmi-data                                 (fn [data]                                   (-> data                                     (assoc param new-value)                                     (dissoc invalidates)                                     calc-bmi)))))}])(defn bmi-component []  (let [{:keys [weight height bmi]} @bmi-data        [color diagnose] (cond                          (< bmi 18.5) ["orange" "underweight"]                          (< bmi 25) ["inherit" "normal"]                          (< bmi 30) ["orange" "overweight"]                          :else ["red" "obese"])]    [:div     [:h3 "BMI calculator"]     [:div      "Height: " (int height) "cm"      [slider :height height 100 220 :bmi]]     [:div      "Weight: " (int weight) "kg"      [slider :weight weight 30 150 :bmi]]     [:div      "BMI: " (int bmi) " "      [:span {:style {:color color}} diagnose]      [slider :bmi bmi 10 50 :weight]]]))



Производительность


React очень быстрый, как и Reagent. На самом деле, Reagent будет даже быстрее, чем обычный React практически всегда, благодаря оптимизациям, сделанным ClojureScript.

Смонтированные компоненты ререндерятся только тогда, когда их параметры изменились. Ререндеринг может вызываться сменой значения атома, аргументы передаются компоненту или состоянию компонента.

Все параметры сравниваются через функцию identical?, которая сравнивает указатели, поэтому не влияет на производительность. Mapы, передаваемые в качестве аргументов компонентам, сравниваются так же: они считаются идентичными, если все их элементы идентичны. Это относится и к встроенным компонентам React, таким как :div, :p и т. д.

Все это означает, что большую часть времени вам просто не придется заботиться о производительности. Просто определите свой пользовательский интерфейс как угодно он будет достаточно быстрым.

Есть пара ситуаций, о которых вам, возможно, придется позаботиться. Если вы дадите Reagent большой список компонентов для рендеринга, вам, возможно, придется снабдить их все уникальным атрибутом :key для ускорения рендеринга (см. выше). Также обратите внимание, что анонимные функции в целом не равны друг другу, даже если они представляют один и тот же код и замыкание.

Но опять же, в целом, стоит просто поверить, что React и Reagent будут достаточно быстрыми. Именно эта страница состоит из одного компонента Reagent с тысячами дочерних компонентов (каждая скобка и т.д. в примерах кода это отдельный компонент), и все же страница может обновляться многократно каждую секунду, не нагружая браузер.

Кстати, та страница также использует другой трюк React: вся страница пререндериватся с помощью Nodejs и reagent.dom.server/render-to-string. Когда она загружается в браузер, React автоматически добавляет обработчики событий к уже существующему DOM-дереву.

Полная демонстрация



Reagent поставляется с парой полных примеров, с проектными файлами Leiningen и всем остальным.

Вот один из них в действии:
(ns simpleexample.core  (:require [reagent.core :as r]            [reagent.dom :as rdom]            [clojure.string :as str]))(defonce timer (r/atom (js/Date.)))(defonce time-color (r/atom "#f34"))(defonce time-updater (js/setInterval                       #(reset! timer (js/Date.)) 1000))(defn greeting [message]  [:h1 message])(defn clock []  (let [time-str (-> @timer .toTimeString (str/split " ") first)]    [:div.example-clock     {:style {:color @time-color}}     time-str]))(defn color-input []  [:div.color-input   "Time color: "   [:input {:type "text"            :value @time-color            :on-change #(reset! time-color (-> % .-target .-value))}]])(defn simple-example []  [:div   [greeting "Hello world, it is now"]   [clock]   [color-input]])(defn ^:export run []  (rdom/render [simple-example] (js/document.getElementById "app")))



Todomvc


Список дел (ToDo List) в Reagent (за исключением роутинга и сохранения данных)

выглядит примерно так:
(ns todomvc.core  (:require [reagent.core :as r]            [reagent.dom :as rdom]            [clojure.string :as str]))(defonce todos (r/atom (sorted-map)))(defonce counter (r/atom 0))(defn add-todo [text]  (let [id (swap! counter inc)]    (swap! todos assoc id {:id id :title text :done false})))(defn toggle [id] (swap! todos update-in [id :done] not))(defn save [id title] (swap! todos assoc-in [id :title] title))(defn delete [id] (swap! todos dissoc id))(defn mmap [m f a] (->> m (f a) (into (empty m))))(defn complete-all [v] (swap! todos mmap map #(assoc-in % [1 :done] v)))(defn clear-done [] (swap! todos mmap remove #(get-in % [1 :done])))(defonce init (do                (add-todo "Rename Cloact to Reagent")                (add-todo "Add undo demo")                (add-todo "Make all rendering async")                (add-todo "Allow any arguments to component functions")                (complete-all true)))(defn todo-input [{:keys [title on-save on-stop]}]  (let [val (r/atom title)        stop #(do (reset! val "")                  (if on-stop (on-stop)))        save #(let [v (-> @val str str/trim)]                (if-not (empty? v) (on-save v))                (stop))]    (fn [{:keys [id class placeholder]}]      [:input {:type "text" :value @val               :id id :class class :placeholder placeholder               :on-blur save               :on-change #(reset! val (-> % .-target .-value))               :on-key-down #(case (.-which %)                               13 (save)                               27 (stop)                               nil)}])))(def todo-edit (with-meta todo-input                 {:component-did-mount #(.focus (rdom/dom-node %))}))(defn todo-stats [{:keys [filt active done]}]  (let [props-for (fn [name]                    {:class (if (= name @filt) "selected")                     :on-click #(reset! filt name)})]    [:div     [:span#todo-count      [:strong active] " " (case active 1 "item" "items") " left"]     [:ul#filters      [:li [:a (props-for :all) "All"]]      [:li [:a (props-for :active) "Active"]]      [:li [:a (props-for :done) "Completed"]]]     (when (pos? done)       [:button#clear-completed {:on-click clear-done}        "Clear completed " done])]))(defn todo-item []  (let [editing (r/atom false)]    (fn [{:keys [id done title]}]      [:li {:class (str (if done "completed ")                        (if @editing "editing"))}       [:div.view        [:input.toggle {:type "checkbox" :checked done                        :on-change #(toggle id)}]        [:label {:on-double-click #(reset! editing true)} title]        [:button.destroy {:on-click #(delete id)}]]       (when @editing         [todo-edit {:class "edit" :title title                     :on-save #(save id %)                     :on-stop #(reset! editing false)}])])))(defn todo-app [props]  (let [filt (r/atom :all)]    (fn []      (let [items (vals @todos)            done (->> items (filter :done) count)            active (- (count items) done)]        [:div         [:section#todoapp          [:header#header           [:h1 "todos"]           [todo-input {:id "new-todo"                        :placeholder "What needs to be done?"                        :on-save add-todo}]]          (when (-> items count pos?)            [:div             [:section#main              [:input#toggle-all {:type "checkbox" :checked (zero? active)                                  :on-change #(complete-all (pos? active))}]              [:label {:for "toggle-all"} "Mark all as complete"]              [:ul#todo-list               (for [todo (filter (case @filt                                    :active (complement :done)                                    :done :done                                    :all identity) items)]                 ^{:key (:id todo)} [todo-item todo])]]             [:footer#footer              [todo-stats {:active active :done done :filt filt}]]])]         [:footer#info          [:p "Double-click to edit a todo"]]]))))(defn ^:export run []  (rdom/render [todo-app] (js/document.getElementById "app")))




Благодарность
Благодарю за помощь в переводе zombiQWERTY.
Подробнее..

Перевод Что не так с Лиспом?

23.02.2021 16:14:33 | Автор: admin

Во-первых, позвольте мне сказать, что лично я не думаю, что с Лиспом что-то особенно не так. Таким образом, в этом эссе я не буду пытаться отвечать на риторический вопрос в заголовке. Тем не менее, я попытаюсь проанализировать некоторые часто повторяющиеся критические замечания в адрес Lisp, чтобы пролить свет на этот вопрос и на то, почему его так часто задают.

Позвольте мне начать с пары слов для тех кто не в курсе. Lisp - это семейство языков, включая Common Lisp, Emacs Lisp и несколько диалектов, которые сегодня используются лишь изредка. Иногда даже язык Scheme считается членом этого семейства. Считать ли это верным, зависит от того, каково ваше точное определение Lisp, но это является слишком сложным (и неинтересным) вопросом для этого эссе.

В основном я буду использовать Lisp для обозначения Common Lisp, а иногда, когда это удобно, также буду включать Emacs Lisp. Lisp существует уже давно, хотя он был значительно преобразован с момента своего изобретения (некоторые говорят, что он был открыт). Сегодня это современный, мультипарадигменный язык, который обладает, пожалуй, самыми сложными фичами из всех используемых языков общего назначения (объектная система CLOS, языковые макросы, специальные макросы чтения, система условий и рестартов и т. д.).

Первый вопрос, который часто задают: Если Lisp настолько хорош, почему он не популярен?. Люди, которые задают такой вопрос, обычно предполагают, что хороший подразумевает популярный, и поэтому ищут какую-то часть Lisp, которая НЕ является хорошей, что могло бы объяснить, почему он не популярен. Однако нет абсолютно никаких оснований предполагать, что хороший подразумевает популярный, поэтому вопрос действительно довольно наивный. Но вместо того, чтобы просто игнорировать этот вопрос в некоторых частях этого эссе, я на мгновение приму его за чистую монету и попытаюсь объяснить, почему Lisp не так популярен, как хотели бы некоторые его последователи.

Однако позвольте мне сделать небольшое замечание. Lisp не настолько непопулярный, как можно думать (и теперь для удобства я добавлю Emacs Lisp). В недавнем подсчете количества строк Lisp занял 4-е место по количеству строк исходного кода (SLOC) в дистрибутиве Debian GNU/Linux (Woody) после C, C++ и bash с примерно 4 миллионами SLOC (около 4%), опередив Perl, Python, ML, Fortran и т. д. Это довольно популярный язык, лишь несколько менее популярный, чем C и C++. Конечно, количество SLOC в Debian GNU/Linux - не единственный возможный показатель популярности, но это показатель, как и любой другой.

Недавно я увидел статью в comp.lang.lisp, в которой автор серьезно знал, что с Lisp должно быть что-то не так, потому что, если все будет хорошо, рынок обнаружит это, и Lisp начнет использоваться в программных проектах повсюду. Тот факт, что этого не произошло, доказал автору, что с Лиспом ДОЛЖНО быть что-то не так, даже если он не знал, что именно.

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

Возможно, в Lisp действительно что-то не так, потому что он, кажется, привлекает всевозможных психов, хотя, возможно, я просто не знаю, что это так и для других языков, или для любого другого человеческого артефакта. Обычно это проявляется в случае с Лиспом так: кто-то, плохо знакомый с Лиспом, впервые появляется в группе новостей comp.lang.lisp, дает очень умным и очень знающим людям урок о том, что они не поняли, почему Lisp непопулярен, и продолжает рассказывать им, как им следует изменить язык, чтобы исправить проблему (обычно, изменить синтаксис, чтобы избавиться от множества скобок), или просто сообщить им, что они сделали ошибку, и вместо этого следует использовать другой язык.

Я считаю, что эти психи являются ключом к разгадке того, почему Lisp не так популярен, как мы думаем он того заслуживает. Lisp значительно отличается от того, что большинство людей уже знает и ожидает от языка программирования, поэтому они просто не хотят прилагать усилий. В другом эссе я назвал этих людей ориентированными на производительность, и они (к сожалению) составляют подавляющее большинство людей в целом, хотя, возможно, и непропорционально большое среди разработчиков программного обеспечения.

Подводя итог этому эссе, они просто жертвы невероятно сильного психологического стремления (в некоторой степени, существующего во всех нас), которое заставляет человека пытаться обозначить что-то новое как плохое или бесполезное, просто чтобы избежать тяжелой работы, необходимости учиться этому. Чем страннее новая вещь (например, Lisp), тем сложнее человек оценивает работу по ее изучению и тем важнее становится объявить ее плохой или бесполезной.

Итак, как нам исправить Lisp, чтобы сделать его более привлекательным для таких людей? Лично я не думаю, что мы должны пытаться изменить что-то в Лиспе, чтобы привлечь этих людей. Почему быть популярным - это все, что имеет значение в языке программирования?!

Я часто вижу очень показательную параллель, проводимую между Лиспом и хорошей скрипкой. Должны ли мы изменять скрипки, чтобы привлечь людей, которые привыкли играть на аккордеоне и не хотят учиться игре на скрипке, потому что это слишком сложно и слишком отличается от аккордеона? Конечно, нет! У скрипки есть свое место, и она становится прекрасным инструментом, когда играет тот, кто действительно владеет ею.

Lisp - отличный язык программирования, если его использует тот, кто знает, как им пользоваться. Упускать это, чтобы привлечь посредственных программистов, экономящих когнитивные ресурсы, было бы серьезной ошибкой. В некоторых (в частности, французских) группах новостей меня называли элитистом за то, что я говорил такие вещи, но я думаю, что причина этого в том, что программирование по-прежнему воспринимается как деятельность, которую любой, без какой-либо подготовки (чем меньше тренировок, тем лучше, тем лучше), кажется, должен уметь. Мы даже превозносим успешных программистов, бросивших школу. Почему люди думают, что это нормально для разработки программного обеспечения, но не для, скажем, операций на сердце или игры на скрипке, я не понимаю.

Некоторые люди думают, что с Лиспом что-то не так, потому что практически невозможно заставить программное обеспечение работать без изменений на всех платформах (комбинациях Лисп-систем и операционных систем), тогда как с чем-то вроде Python или Ruby это легко. Ясно же, что здесь с Лиспом что-то не так, верно?

Нет, на самом деле нет! Lisp - это не отдельная реализация, а ANSI-стандарт (теперь уже Common Lisp). Как и многие другие стандарты (например, ANSI-стандарт для языка программирования Си), он не содержит всего, что вам может понадобиться при написании приложений, например сокетов, синтаксических анализаторов XML, библиотек SQL и т. д. Вместо этого предоставляются отдельные библиотеки, которые в случае Lisp либо поставляются поставщиком коммерческой системы Lisp, либо бесплатно авторами свободных библиотек для других разработчиков. Таким образом, предполагаемая трудность состоит в том, чтобы написать приложение, которое могло бы работать со всеми этими, возможно, взаимно несовместимыми библиотеками. Разработчик, столкнувшийся с этой проблемой, обычно очень расстраивается, жалуется в comp.lang.lisp, что мы должны исправить стандарт ANSI Common Lisp как можно скорее, чтобы включить эти библиотеки.

Подождите секунду! Почему это не проблема для таких языков, как Python и Ruby, которые даже НЕ ИМЕЮТ стандарта ANSI? Почему люди не жалуются громко, что они даже не могут написать кросс-платформенный цикл или оператор присваивания на Python, потому что способ сделать это не стандартизирован? Ответ: потому что эти люди сравнивают яблоки и апельсины или, в данном случае, язык, определяемый (в основном) одной реализацией, и стандарт с несколькими реализациями. Вот как увидеть, насколько это сравнение абсурдно: если бы я написал новую реализацию Python, в которой не было бы сокетов, разве это внезапно ухудшило бы положение языка Python, в сравнении с тем, что было раньше? Конечно, нет! Точно так же люди, которые хотят использовать язык с единственной реализацией и тем самым рискуют, что язык может измениться в одночасье, что, возможно, сделает большую часть некоторых крупных инвестиций устаревшими, должны принять то же самое с Lisp и выбрать единственную реализацию. который работает во всех операционных системах. Это будет не хуже, чем у любого языка с одной реализацией.

Некоторые ВНУТРИ Lisp-сообщества думают, что Lisp не так популярен, как он того заслуживает, потому что в языке есть недостатки. Таким образом, предполагаемое решение проблемы состоит в создании лучшего диалекта Lisp. Откровенно говоря, если бы это было правдой, то ни у одного другого языка не было бы ни единого последователя, учитывая количество недостатков в других языках по сравнению с недостатками Common Lisp. Одной из типичных попыток создать лучший Lisp был Dylan (больше похожий на Scheme, чем на Lisp, на самом деле), который определяет синтаксис без скобок для Lisp-подобного языка, тем самым по существу лишая Lisp одного из его, пожалуй, величайших преимуществ, а именно почти однозначного соответствия между внешним синтаксисом и внутренним представлением кода, что является важной фичей для создания макросов. А Dylan не более популярен, чем Common Lisp.

В последнее время мы регулярно видим людей (обычно также в сообществе Lisp), у которых есть идеальное объяснение того, почему Lisp не так популярен, как он того заслуживает, а именно, что нет ни одной бесплатной реализации, которая работала бы во всех операционных системах и в которой были бы ВСЕ необходимые библиотеки, как в Python и Ruby для веб-программирования и т. д. (мы уже видели, что в стандарте ANSI Common Lisp их нет). Типичная статья одного из этих людей очень снисходительна. Недавно я видел фразы, похожие на Простите, ребята, но интерфейсы командной строки больше не подходят, в наши дни все основано на графическом интерфейсе, а у вас даже нет стандартной библиотеки графического интерфейса.

Общий тон, кажется, обвиняет некоторое вымышленное сообщество Lisp в том, что оно не понимает, что именно требуется Lisp с точки зрения библиотек, чтобы стать более популярным. Я согласен, что они правы, что на данный момент нет достаточно хороших библиотек для всех применений. Однако я серьезно сомневаюсь, что решение этой проблемы каким-либо образом повлияет на популярность Lisp. Хуже того, я не понимаю, кому адресованы эти статьи. Некоторые из них, без сомнения, предназначены только для того, чтобы автор отказался от Lisp в пользу более популярного языка, делая это с чистой совестью (это не моя вина, я должен был сделать это, потому что не смог получить нужные мне библиотеки. ). Все они определенно имеют негативный эффект (желаемый или нежелательный) на людей, которые могут рассматривать использование Lisp. Для людей, которые не знают Lisp и НЕ рассматривают возможность его использования, они определенно не имеют абсолютно никакого эффекта.

Большинство авторов этих статей, кажется, серьезно думают, что каким-то образом они будут серьезно восприняты участниками Lisp-сообщества, и что эти участники осознают свои ошибки и начнут предоставлять высококачественные библиотеки для веб-программирования и синтаксического анализа XML бесплатно и сразу. Я не думаю, что это случится. Чтобы понять, почему, мы можем (для этой цели) разделить членов "сообщества Lisp" на три типа людей:
- тех, кто уже тратит значительную энергию и время на написание таких библиотек,
- тех, кто не имеет возможности писать такие библиотеки. (из-за недостатка знаний, энергии или времени), и
- тех, у кого есть возможность сделать это, но они не делают этого.

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

Люди из второй категории не собираются вдруг начать писать нужные библиотеки.

Таким образом, остается третья категория, в которую обычно входят авторы этих статей, взаимно обвиняющие друг друга в том, что они не предоставляют инструменты, которые им нужны. Лично я считаю, что было бы лучше использовать их время и энергию, чтобы начать писать некоторые из этих библиотек (в качестве хороших примеров для других), чем сетовать на то, что этих библиотек не существует.

Меня, в основном, не волнует, насколько популярен Lisp. Я использую Lisp не для того, чтобы набрать больше очков в соревновании по популярности. Я использую Lisp, потому что это лучший язык программирования, который я знаю. Я не думаю, что с Лиспом что-то особенно или серьезно не так. Возможно, на данный момент он не обеспечивает того, что некоторые люди ожидают от языка программирования (например, бесплатную кроссплатформенную реализацию со всеми библиотеками, которые могут вам понадобиться). Произойдет ли это когда-нибудь, я не знаю, и меня это не заботит (хотя я уважаю, что другие могут волноваться по этому поводу). Думаю, я знаю, что некоторым людям, которые хотят, чтобы это произошло, придется запачкать руки и просто сделать это. Никакие сетования не могут волшебным образом создать какие-либо библиотеки.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru