Clojure / Clojurescript: аргумент для разрешения должен быть в кавычках

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

Лучшее способ сделать это так:

SetExceptionMask(exAllArithmeticExceptions);

Это установит управляющее слово 8087 на 32-битные цели, а MXCSR - на 64-битные цели. Вы найдете SetExceptionMask в модуле Math.

Если вы хотите, чтобы исключения с плавающей запятой были разобраны в вашем коде, тогда это становится сложным. Одна из стратегий заключалась бы в том, чтобы запустить ваш код с плавающей точкой в ​​выделенном потоке, который устраняет исключения. Это, безусловно, может работать, но не если вы полагаетесь на функции RTL Set8087CW и SetMXCSR. Обратите внимание, что все в RTL, которое контролирует блоки FP, маршрутизирует эти функции. Например, SetExceptionMask делает.

Проблема в том, что Set8087CW и SetMXCSR не являются потокобезопасными. Кажется, трудно поверить, что Embarcadero может быть настолько неумелым, чтобы создавать фундаментальные подпрограммы, которые работают в контексте потоков, но не могут быть потокобезопасными. Но это то, что они сделали.

Удивительно сложно отменить беспорядок, который у них остался, и для этого требуется довольно много исправления кода. Отсутствие безопасности потоков зависит от (неправильного) использования глобальных переменных Default8087CW и DefaultMXCSR. Если два потока одновременно называют Set8087CW или SetMXCSR, тогда эти глобальные переменные могут влиять на утечку значения из одного потока в другой.

Вы можете заменить Set8087CW и SetMXCSR на версии, которые не изменяли глобальное состояние, но это, к сожалению, не так просто. Глобальное состояние используется в других местах. Это может показаться нескромным, но если вы хотите узнать больше об этом, прочитайте мой документ, прилагаемый к этому отчету о контроле качества: http://qc.embarcadero.com/wc/qcmain.aspx?d=107411

1
задан akond 17 January 2019 в 06:15
поделиться

2 ответа

Вам нужно использовать его следующим образом:

((resolve 'inc)  5))  => 6

или, немного разобрать:

(let [the-fn (resolve 'inc)]
   (the-fn 7))

=> 8

Если у вас есть имя функции в виде строки, используйте symbol функция для преобразования из символа string => ( из clojuredocs.org ):

user=> ((-> "first" symbol resolve) [1 2 3])
1

И никогда не забывайте Clojure CheatSheet!

0
ответ дан Alan Thompson 17 January 2019 в 06:15
поделиться

ClojureScript поддерживает оптимизацию :advanced, в которой Google Closure Compiler будет переименовывать, вставлять или исключать (неиспользуемые) функции для реализации минимизации. Короче говоря, имя функции, которую вы хотите найти, в общем случае просто больше не существует в :advanced.

Из-за этого ClojureScript resolve является средством времени компиляции (макрос, требующий буквально заключенного в кавычки символа).

Если вы используете :simple или самодостаточный ClojureScript, вам доступны дополнительные параметры, поскольку необходимая поддержка сохраняется во время выполнения. Например, у Планка есть planck.core/resolve, который ведет себя как у Clojure resolve. Подобный подход возможен в Lumo , и аналогичные средства могут быть созданы при использовании :simple.

В общем, хотя, учитывая :advanced, если вам нужно отобразить строки в набор функций, вам нужно каким-то образом организовать статическое отображение, построенное во время компиляции для поддержки этого (набор функций должен быть известен [ 1130] априори , во время компиляции).

Если у вас есть пространство имен (имя которого статически известно во время компиляции), которое определяет функции, которые должны вызываться динамически через строки, вы можете рассмотреть использование ns-publics:

cljs.user=> (ns foo.core)

foo.core=> (defn square [x] (* x x))
#'foo.core/square
foo.core=> (in-ns 'cljs.user)
nil
cljs.user=> (when-some [fn-var ((ns-publics 'foo.core) (symbol "square"))]
               (fn-var 3))
9
[1136 ] Это будет работать в соответствии с :advanced. Отображение, построенное в ns-publics, является статическим; построен во время компиляции. Если у вас есть несколько пространств имен, которые требуют такой обработки, вы можете merge сделать несколько вызовов ns-publics, чтобы построить большую карту.

Преимущество этого подхода в том, что используемый код довольно короткий и не требует значительного обслуживания. Недостатком является то, что он сбрасывает все открытые переменные пространства имен (foo.core в этом примере) в ваш сгенерированный код (и сгенерированный код для vars является довольно многословным). Другим недостатком является то, что вам необходимо статически знать пространство имен, задействованное во время компиляции.

Если вам нужно дополнительно минимизировать размер сгенерированного кода, вы можете просто создать / поддерживать простую статическую карту из строки в значение функции, как в

(def fns {"square" foo.core/square})

, и использовать ее соответствующим образом, поддерживая ее в актуальном состоянии, как ваша кодовая база развивается.

Другой вариант - пометить функции, к которым вам нужен доступ, с помощью мета ^:export, а затем вызвать эти функции с помощью взаимодействия JavaScript. Например, если вы определяете функцию таким образом

 (defn ^:export square [x] (* x x))

, то вы можете использовать strings / interop для поиска функции и вызова ее во время выполнения. Вот пример:

 ((goog.object/getValueByKeys js/window #js ["foo" "core" "square"]) 3)

Использование ^:export и :advanced описано здесь . Если вы знаете, что используете :simple или меньше, вы можете просто использовать взаимодействие JavaScript для вызова интересующих функций, без необходимости использовать ^:export.

Обратите внимание, что не существует общего решения, которое позволило бы вам искать функцию по имени во время выполнения в :advanced, не добавляя какой-либо аспект этой функции в ваш код во время компиляции. (Фактически, если на функцию не ссылаются так, как статически компилятор Google Closure может видеть, реализация функции будет полностью исключена как мертвый код.) В приведенном выше ns-publics захватывает все переменные для пространства имен при компиляции время, когда вы катите свою собственную карту поиска, устанавливает статический код для ссылки на значение функции и использует статическое расположение ^:export, чтобы имя функции сохранялось во время выполнения.

0
ответ дан Mike Fikes 17 January 2019 в 06:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: