【问题标题】:Clojure and compile time checking of specClojure 和规范的编译时检查
【发布时间】:2017-12-14 22:42:45
【问题描述】:

我正在使用函数规范,我想知道是否可以使用它来模拟编译类型检查? 宏是在编译时评估的,所以如果我可以这样做:

(:require [clojure.spec.alpha :as s]
          [clojure.spec.test.alpha :as st])

(s/fdef divide
        :args (s/cat :x integer? :y integer?)
        :ret number?)

(defn divide [x y] (/ x y))

(st/instrument `divide)

(defmacro typed-divide [arg1 arg2]
  (eval `(divide ~arg1 ~arg2)))

;; this should fail to compile?
(defn typed-divide-by-foo [arg]
  (typed-divide arg :foo))

【问题讨论】:

  • 仅供参考 (typed-divide arg 2) 也会通过异常,因为符号 arg 是在编译时传入的。您只能使用 typed-divide 来划分其值在编译时已知的事物,这几乎仅限于文字。 (typed-divide 2 :foo) 应该会给你一个规范错误。
  • (eval 'x)x一样,所以typed-divide的body可以简化为(divide ~arg1 ~arg2)
  • 可能是:(defmacro typed-divide [arg1 arg2] (divide arg1 arg2))。但实际上只有在编译时知道两个参数时才会抛出:(defn typed-divide-by-foo [] (typed-divide 6 :foo))。尽管我对 clojure 的动态特性没有任何问题,但这是一项纯粹的学术调查:)
  • 哎呀,你说得对,不是~。我假设您收到 (typed-divide 6 :foo) 的规范失败异常和 (typed-divide arg :foo) 的“无法解析符号”异常?
  • 查看:github.com/arohner/spectrum 它将准确捕获您在编译时遇到的错误。它仍处于早期 alpha 阶段,但比您提出的方案更好的长期解决方案。

标签: clojure macros clojure.spec


【解决方案1】:

虽然宏系统可能有一些技巧,但您最好只为此编写单元测试。编译时错误非常模糊,会阻止 REPL 启动。相反,测试也会处理异常并在出现问题时收集漂亮的报告。

在生产环境中检测函数也不是一个好主意,因为它确实会降低其性能。仅在测试中使用它们。请参见下面的示例:

(ns project.tests
  (:require [clojure.test :refer :all]
            [project.code :refer [divide]]))

;; here, in test namespace, you instrument a function 
;; you'd like to test
(st/instrument `divide)

;; and then add a test
(deftest test-divide
  (is (= (divide 6 2) 3)))

现在,运行测试:

lein test

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-08
    • 2013-08-30
    • 1970-01-01
    • 1970-01-01
    • 2014-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多