如何在clojure中将值序列/集合指定为函数的一个值?

如何在clojure中将值序列/集合指定为函数的一个值?,clojure,clojure.spec,Clojure,Clojure.spec,我试图以这样一种方式规范一个函数,即它将两个字符串的序列作为函数的第一个参数 这就是我尝试过的: (ns yoostan-lib.test (:require [clojure.spec :as s] [clojure.spec.gen :as gen])) (s/def ::two-strings (s/cat :s1 string? :s2 string?)) ;; (gen/sample (s/gen

我试图以这样一种方式规范一个函数,即它将两个字符串的序列作为函数的第一个参数

这就是我尝试过的:

(ns yoostan-lib.test
  (:require [clojure.spec :as s]
            [clojure.spec.gen :as gen]))

(s/def ::two-strings (s/cat :s1 string?
                            :s2 string?))

;; (gen/sample (s/gen ::two-strings) 3)
;; (("" "") ("7" "J") ("Tx1" "oQ"))

(s/fdef print-two-strings
        :args (s/cat :ss ::two-strings)
        :ret string?)

(defn print-two-strings
  [ss & rst]
  (with-out-str (clojure.pprint/pprint {:ss ss
                                        :rst rst})))

;; this is what I want
;; (print-two-strings '("oeu" "oeu"))
;; => "{:ss (\"oeu\" \"oeu\"), :rst nil}\n"

;; this is what I get instead
;; (s/exercise-fn `print-two-strings)
;; ([("" "") "{:ss \"\", :rst (\"\")}\n"] [("" "") "{:ss \"\", :rst (\"\")}\n"] [("90" "g") "{:ss \"90\", :rst (\"g\")}\n"]     [("IhE" "a6") "{:ss \"IhE\", :rst (\"a6\")}\n"] [("8P5" "70A") "{:ss \"8P5\", :rst (\"70A\")}\n"] [("738a" "41j4") "{:ss     \"738a\", :rst (\"41j4\")}\n"] [("M8" "4GD1") "{:ss \"M8\", :rst (\"4GD1\")}\n"] [("" "G") "{:ss \"\", :rst (\"G\")}\n"]     [("R" "8s43p") "{:ss \"R\", :rst (\"8s43p\")}\n"] [("C1e" "EY2AUE") "{:ss \"C1e\", :rst (\"EY2AUE\")}\n"])
说清楚。我的问题是,
练习fn
解释了我给它的
fdef
规范,这意味着它可以向我的函数传递两个参数,都是
string?
类型。相反,我希望得到一个参数,由作为一个集合传递的两个字符串组成。

来自
规范
指南的部分:

当组合正则表达式操作时,它们描述单个序列。如果需要指定嵌套顺序集合,则必须使用显式调用来启动新的嵌套正则表达式上下文

因此,您可以按如下方式指定
打印两个字符串

(s/fdef print-two-strings
  :args (s/cat :ss (s/spec ::two-strings))
  :ret string?)

旁注:我看到您将参数垂直对齐到
fdef
,而不是像
spec
指南那样使用两个空格缩进。如果使用,可以将其配置为对该宏使用两个空格缩进,如文档所示:

(将clojure缩进'clojure.spec/fdef 1)
或者,相当于:

(定义clojure缩进
(clojure.spec/fdef 1))
以下是我的Emacs配置中的一个示例。

来自
spec
指南部分:

;; any of these will work, I'd probably use tuple here
(s/def ::two-strings (s/tuple string? string?))
(s/def ::two-strings (s/coll-of string? :count 2))
(s/def ::two-strings (s/coll-of string? :count 2 :into ())) ;; for lists in conformed value

(s/fdef print-two-strings
  :args (s/cat :ss ::two-strings :rst (s/? string?))
  :ret string?)

(pprint (s/exercise-fn `print-two-strings))

;;=> ([(["" ""] "") "{:ss [\"\" \"\"], :rst (\"\")}\n"]
 [(["H" "4"]) "{:ss [\"H\" \"4\"], :rst nil}\n"]
 [(["yZ" "7"] "OU") "{:ss [\"yZ\" \"7\"], :rst (\"OU\")}\n"]
 [(["" "FFt"]) "{:ss [\"\" \"FFt\"], :rst nil}\n"]
 [(["9" "Q0"]) "{:ss [\"9\" \"Q0\"], :rst nil}\n"]
 [(["o" "OuSA"]) "{:ss [\"o\" \"OuSA\"], :rst nil}\n"]
 [(["1JN" "bT"]) "{:ss [\"1JN\" \"bT\"], :rst nil}\n"]
 [(["IUY" ""]) "{:ss [\"IUY\" \"\"], :rst nil}\n"]
 [(["8G" "71H3r3d"]) "{:ss [\"8G\" \"71H3r3d\"], :rst nil}\n"]
 [(["qL" "zK3ZXA"] "9PV5X1")
  "{:ss [\"qL\" \"zK3ZXA\"], :rst (\"9PV5X1\")}\n"])
当组合正则表达式操作时,它们描述单个序列。如果需要指定嵌套顺序集合,则必须使用显式调用来启动新的嵌套正则表达式上下文

因此,您可以按如下方式指定
打印两个字符串

(s/fdef print-two-strings
  :args (s/cat :ss (s/spec ::two-strings))
  :ret string?)

旁注:我看到您将参数垂直对齐到
fdef
,而不是像
spec
指南那样使用两个空格缩进。如果使用,可以将其配置为对该宏使用两个空格缩进,如文档所示:

(将clojure缩进'clojure.spec/fdef 1)
或者,相当于:

(定义clojure缩进
(clojure.spec/fdef 1))

这是我的Emacs配置中的一个缩进提示。

感谢您提供缩进提示!根据问题中定义的函数,这个例子是错误的,因为第二个参数不是可选的。答案解决了我实际遇到的问题或挫折。不过,如果你能提出建议,我很乐意修改和/或澄清这个问题。谢谢你提供的缩进提示!根据问题中定义的函数,这个例子是错误的,因为第二个参数不是可选的。答案解决了我实际遇到的问题或挫折。但是,如果你能提出建议,我很乐意修改和/或澄清这个问题。你误读了这个问题。
rst
参数仅显示原始的
fdef
不能正常工作。对于采用“一个参数,由作为一个集合传递的两个字符串组成”的函数,您的
fdef
不正确。。。我明白你的意思。但是我仍然认为你给出的例子是错误的,因为它没有规定rst。我想OP需要澄清他对
rst
参数的意图。然而,由于他的实际问题实际上只是关于
ss
参数,我在回答中正确地提到了这一点,我认为你对我的回答投了否决票是不公平的,因为它没有解决问题的一个切点/附带的部分。我很乐意撤销否决票,但不能b/c它被锁定了。我仍然认为ss部分至少也有一部分不正确,因为您需要更改
::两个字符串
以获得所需的特定conform OP(字符串集合,而不是字符串部分的映射)。实际上,OP没有指定他想要的
conform
行为;他只展示了他原来的
fdef
的行为。不过,我可以肯定地看出,你的
fdef
conform
行为可能比我的行为更可取。你误读了这个问题。
rst
参数仅显示原始的
fdef
不能正常工作。对于采用“一个参数,由作为一个集合传递的两个字符串组成”的函数,您的
fdef
不正确。。。我明白你的意思。但是我仍然认为你给出的例子是错误的,因为它没有规定rst。我想OP需要澄清他对
rst
参数的意图。然而,由于他的实际问题实际上只是关于
ss
参数,我在回答中正确地提到了这一点,我认为你对我的回答投了否决票是不公平的,因为它没有解决问题的一个切点/附带的部分。我很乐意撤销否决票,但不能b/c它被锁定了。我仍然认为ss部分至少也有一部分不正确,因为您需要更改
::两个字符串
以获得所需的特定conform OP(字符串集合,而不是字符串部分的映射)。实际上,OP没有指定他想要的
conform
行为;他只展示了他原来的
fdef
的行为。不过,我可以肯定地看到,您的
fdef
conform
行为比我的行为更可取。
;; any of these will work, I'd probably use tuple here
(s/def ::two-strings (s/tuple string? string?))
(s/def ::two-strings (s/coll-of string? :count 2))
(s/def ::two-strings (s/coll-of string? :count 2 :into ())) ;; for lists in conformed value

(s/fdef print-two-strings
  :args (s/cat :ss ::two-strings :rst (s/? string?))
  :ret string?)

(pprint (s/exercise-fn `print-two-strings))

;;=> ([(["" ""] "") "{:ss [\"\" \"\"], :rst (\"\")}\n"]
 [(["H" "4"]) "{:ss [\"H\" \"4\"], :rst nil}\n"]
 [(["yZ" "7"] "OU") "{:ss [\"yZ\" \"7\"], :rst (\"OU\")}\n"]
 [(["" "FFt"]) "{:ss [\"\" \"FFt\"], :rst nil}\n"]
 [(["9" "Q0"]) "{:ss [\"9\" \"Q0\"], :rst nil}\n"]
 [(["o" "OuSA"]) "{:ss [\"o\" \"OuSA\"], :rst nil}\n"]
 [(["1JN" "bT"]) "{:ss [\"1JN\" \"bT\"], :rst nil}\n"]
 [(["IUY" ""]) "{:ss [\"IUY\" \"\"], :rst nil}\n"]
 [(["8G" "71H3r3d"]) "{:ss [\"8G\" \"71H3r3d\"], :rst nil}\n"]
 [(["qL" "zK3ZXA"] "9PV5X1")
  "{:ss [\"qL\" \"zK3ZXA\"], :rst (\"9PV5X1\")}\n"])