Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Error handling 如何编写Clojure线程宏?_Error Handling_Clojure - Fatal编程技术网

Error handling 如何编写Clojure线程宏?

Error handling 如何编写Clojure线程宏?,error-handling,clojure,Error Handling,Clojure,我正在尝试使用failjure/ok->()编写一个线程宏,线程中的最后一个函数需要执行一个条件。代码如下所示: (f/ok->> (function1 param) (function2 param1 param 2) ... ({conditional function here})) (f/ok->> (function1 param) (function2 param1 param 2)

我正在尝试使用
failjure/ok->
()编写一个线程宏,线程中的最后一个函数需要执行一个条件。代码如下所示:

(f/ok->> (function1 param)
         (function2 param1 param 2)
         ...
         ({conditional function here}))

(f/ok->> (function1 param)
         (function2 param1 param 2)
         ...
         (cond (condition?)
             (function_if_passes_condition)
             #(%))
其中,如果未命中条件,线程宏将返回倒数第二个函数调用的结果。 我试图编写一个检查必要条件的
cond
函数,然后如果条件通过,则返回该函数,或者仅返回上一个函数的结果,但是线程宏似乎不会将结果传递给
cond
中的函数,而只传递给
cond
本身。(不正确)代码如下所示:

(f/ok->> (function1 param)
         (function2 param1 param 2)
         ...
         ({conditional function here}))

(f/ok->> (function1 param)
         (function2 param1 param 2)
         ...
         (cond (condition?)
             (function_if_passes_condition)
             #(%))

我想知道是否有一个干净的方法来正确地做到这一点。我认为有可能编写一个具有这种功能的全新线程宏,但到目前为止,我所有的尝试都没有成功(我以前没有编写一个实现线程宏的
defmacro
,这是相当困难的,因为我是clojure的新手,有3个月的经验).

您的问题陈述似乎有点模糊,因此我将解决问题的简化版本

请记住,宏是一种代码转换机制。也就是说,它将您希望编写的代码转换为编译器可以接受的代码。这样,最好将结果视为编译器扩展。编写宏非常复杂,几乎总是不必要的。所以,除非你真的需要,否则不要这样做

让我们编写一个助手谓词和单元测试:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)   ; <= *** convenience functions! ***
  (:require [clojure.pprint :as pprint]))

(defn century? [x] (zero? (mod x 100)))
(dotest
  (isnt (century? 1399))
  (is   (century? 1300)))
为此:

  (-> 10
    (+ 3)
    (* 100)
    (if (century) ; <= arg goes here
        :pass
        :fail))
并进行单元测试。确保遵循将args包装在带引号的向量中的模式。这模拟了
[&args]
defmacro
表达式中所做的操作

(dotest
  (pprint/pprint
    (check->-impl '[10
                    (+ 3)
                    (* 100)
                    (century?)])
    ))
结果:

args => [10 (+ 3) (* 100) (century?)]   ; 1 (from spyx)
[10 (+ 3) (* 100) (century?)]           ; 2 (from pprint)
(clojure.core/let
 [tst.demo.core/x (clojure.core/-> 10 (+ 3) (* 100))]
 (if (century? x) :pass :fail))
-------------------------------
   Clojure 1.10.1    Java 13
-------------------------------

Testing tst.demo.core

Ran 3 tests containing 4 assertions.
0 failures, 0 errors.
因此,我们看到(1)中打印的结果,然后impl函数返回(2)中的(未修改的)代码。这是关键。宏返回修改后的代码。然后,编译器编译修改后的代码以代替原始代码

编写更多带有更多打印的代码:

(defn check->-impl
  [args]  ; no `&`
  (let [all-but-last (butlast args)
        last-arg     (last args) ]
    (spyx all-but-last)        ; (1)
    (spyx last-arg)            ; (2)
))
结果

all-but-last => (10 (+ 3) (* 100))    ; from (1)
last-arg     => (century?)            ; from (2)
(century?)                            ; from pprint
注意发生了什么。我们看到了修改后的变量,但输出也发生了变化。编写更多代码:

(defn check->-impl
  [args]  ; no `&`
  (let [all-but-last (butlast args)
        last-arg     (last args)
        cond-expr    (append last-arg 'x)]  ; from tupelo.core
    (spyx cond-expr)
))

cond-expr => [century? x]  ; oops!  need a list, not a vector
哎呀!
append
函数始终返回向量。只需使用
->list
将其转换为列表即可。您还可以键入
(应用列表…

现在,我们可以使用语法引号创建输出模板代码:

(defn check->-impl
  [args]  ; no `&`
  (let [all-but-last (butlast args)
        last-arg     (last args)
        cond-expr    (->list (append last-arg 'x))]
    ; template for output code
    `(let [x (-> ~@all-but-last)] ; Note using `~@` eval-splicing
       (if ~cond-expr
         :pass
         :fail))))
结果:

args => [10 (+ 3) (* 100) (century?)]   ; 1 (from spyx)
[10 (+ 3) (* 100) (century?)]           ; 2 (from pprint)
(clojure.core/let
 [tst.demo.core/x (clojure.core/-> 10 (+ 3) (* 100))]
 (if (century? x) :pass :fail))
-------------------------------
   Clojure 1.10.1    Java 13
-------------------------------

Testing tst.demo.core

Ran 3 tests containing 4 assertions.
0 failures, 0 errors.
参见
tst.demo.core/x
部分?这是个问题。我们需要重新编写:

(defn check->-impl
  [args]  ; no `&`
  (let [all-but-last (butlast args)
        last-arg     (last args)]
    ; template for output code.  Note all 'let' variables need a `#` suffix for gensym
    `(let [x#           (-> ~@all-but-last) ; re-use pre-existing threading macro
           pred-result# (-> x# ~last-arg)] ; simplest way of getting x# into `last-arg`
       (if pred-result#
         :pass
         :fail))))
注意:正确使用
~
(eval)和
~@
(eval拼接)非常重要。容易出错。现在我们得到

(clojure.core/let
 [x__20331__auto__             (clojure.core/-> 10 (+ 3) (* 100))
  pred-result__20332__auto__   (clojure.core/-> x__20331__auto__ (century?))]
 (if pred-expr__20333__auto__ 
    :pass 
    :fail))
真的试试看。从带引号的向量中展开参数,并调用宏而不是impl函数:

  (spyx-pretty :final-result
    (check-> 10
      (+ 3)
      (* 100)
      (century?)))
输出:

 :final-result
(check-> 10 (+ 3) (* 100) (century?)) => 
:pass
并编写一些单元测试:

(dotest
  (is= :pass (check-> 10
               (+ 3)
               (* 100)
               (century?)))
  (is= :fail (check-> 10
               (+ 3)
               (* 101)
               (century?))))
结果:

args => [10 (+ 3) (* 100) (century?)]   ; 1 (from spyx)
[10 (+ 3) (* 100) (century?)]           ; 2 (from pprint)
(clojure.core/let
 [tst.demo.core/x (clojure.core/-> 10 (+ 3) (* 100))]
 (if (century? x) :pass :fail))
-------------------------------
   Clojure 1.10.1    Java 13
-------------------------------

Testing tst.demo.core

Ran 3 tests containing 4 assertions.
0 failures, 0 errors.

您也可能对本书感兴趣:


您的问题陈述似乎有点模糊,因此我将解决问题的简化版本

请记住,宏是一种代码转换机制。也就是说,它将您希望编写的代码转换为编译器可以接受的代码。这样,最好将结果视为编译器扩展。编写宏非常复杂,几乎总是不必要的。所以,除非你真的需要,否则不要这样做

让我们编写一个助手谓词和单元测试:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)   ; <= *** convenience functions! ***
  (:require [clojure.pprint :as pprint]))

(defn century? [x] (zero? (mod x 100)))
(dotest
  (isnt (century? 1399))
  (is   (century? 1300)))
为此:

  (-> 10
    (+ 3)
    (* 100)
    (if (century) ; <= arg goes here
        :pass
        :fail))
并进行单元测试。确保遵循将args包装在带引号的向量中的模式。这模拟了
[&args]
defmacro
表达式中所做的操作

(dotest
  (pprint/pprint
    (check->-impl '[10
                    (+ 3)
                    (* 100)
                    (century?)])
    ))
结果:

args => [10 (+ 3) (* 100) (century?)]   ; 1 (from spyx)
[10 (+ 3) (* 100) (century?)]           ; 2 (from pprint)
(clojure.core/let
 [tst.demo.core/x (clojure.core/-> 10 (+ 3) (* 100))]
 (if (century? x) :pass :fail))
-------------------------------
   Clojure 1.10.1    Java 13
-------------------------------

Testing tst.demo.core

Ran 3 tests containing 4 assertions.
0 failures, 0 errors.
因此,我们看到(1)中打印的结果,然后impl函数返回(2)中的(未修改的)代码。这是关键。宏返回修改后的代码。然后,编译器编译修改后的代码以代替原始代码

编写更多带有更多打印的代码:

(defn check->-impl
  [args]  ; no `&`
  (let [all-but-last (butlast args)
        last-arg     (last args) ]
    (spyx all-but-last)        ; (1)
    (spyx last-arg)            ; (2)
))
结果

all-but-last => (10 (+ 3) (* 100))    ; from (1)
last-arg     => (century?)            ; from (2)
(century?)                            ; from pprint
注意发生了什么。我们看到了修改后的变量,但输出也发生了变化。编写更多代码:

(defn check->-impl
  [args]  ; no `&`
  (let [all-but-last (butlast args)
        last-arg     (last args)
        cond-expr    (append last-arg 'x)]  ; from tupelo.core
    (spyx cond-expr)
))

cond-expr => [century? x]  ; oops!  need a list, not a vector
哎呀!
append
函数始终返回向量。只需使用
->list
将其转换为列表即可。您还可以键入
(应用列表…

现在,我们可以使用语法引号创建输出模板代码:

(defn check->-impl
  [args]  ; no `&`
  (let [all-but-last (butlast args)
        last-arg     (last args)
        cond-expr    (->list (append last-arg 'x))]
    ; template for output code
    `(let [x (-> ~@all-but-last)] ; Note using `~@` eval-splicing
       (if ~cond-expr
         :pass
         :fail))))
结果:

args => [10 (+ 3) (* 100) (century?)]   ; 1 (from spyx)
[10 (+ 3) (* 100) (century?)]           ; 2 (from pprint)
(clojure.core/let
 [tst.demo.core/x (clojure.core/-> 10 (+ 3) (* 100))]
 (if (century? x) :pass :fail))
-------------------------------
   Clojure 1.10.1    Java 13
-------------------------------

Testing tst.demo.core

Ran 3 tests containing 4 assertions.
0 failures, 0 errors.
参见
tst.demo.core/x
部分?这是个问题。我们需要重新编写:

(defn check->-impl
  [args]  ; no `&`
  (let [all-but-last (butlast args)
        last-arg     (last args)]
    ; template for output code.  Note all 'let' variables need a `#` suffix for gensym
    `(let [x#           (-> ~@all-but-last) ; re-use pre-existing threading macro
           pred-result# (-> x# ~last-arg)] ; simplest way of getting x# into `last-arg`
       (if pred-result#
         :pass
         :fail))))
注意:正确使用
~
(eval)和
~@
(eval拼接)非常重要。容易出错。现在我们得到

(clojure.core/let
 [x__20331__auto__             (clojure.core/-> 10 (+ 3) (* 100))
  pred-result__20332__auto__   (clojure.core/-> x__20331__auto__ (century?))]
 (if pred-expr__20333__auto__ 
    :pass 
    :fail))
真的试试看。从带引号的向量中展开参数,并调用宏而不是impl函数:

  (spyx-pretty :final-result
    (check-> 10
      (+ 3)
      (* 100)
      (century?)))
输出:

 :final-result
(check-> 10 (+ 3) (* 100) (century?)) => 
:pass
并编写一些单元测试:

(dotest
  (is= :pass (check-> 10
               (+ 3)
               (* 100)
               (century?)))
  (is= :fail (check-> 10
               (+ 3)
               (* 101)
               (century?))))
结果:

args => [10 (+ 3) (* 100) (century?)]   ; 1 (from spyx)
[10 (+ 3) (* 100) (century?)]           ; 2 (from pprint)
(clojure.core/let
 [tst.demo.core/x (clojure.core/-> 10 (+ 3) (* 100))]
 (if (century? x) :pass :fail))
-------------------------------
   Clojure 1.10.1    Java 13
-------------------------------

Testing tst.demo.core

Ran 3 tests containing 4 assertions.
0 failures, 0 errors.

您也可能对本书感兴趣:


您熟悉
cond->
吗?例如,
(>“tuba”(string/replace#a“e”)(str“r”)(cond->(偶数12)(str“s”)
产生“tubers”,因为12是偶数。您熟悉
cond->
?例如,
(>“tuba”(string/replace#a“e”)(str“r”)(cond->(偶数12)(str“s”))
产生“tubers”,因为12是偶数。