如何使用clojure.spec生成相互关联的参数?

如何使用clojure.spec生成相互关联的参数?,clojure,clojure.spec,Clojure,Clojure.spec,我有一个方法可以从成对的字符串中删除公共前缀,并且一直在尝试为它创建一个生成器。生成随机字符串对是很简单的,但是如何强制使许多对具有公共前缀呢?简单地过滤成对生成的示例数量不足,因此我尝试创建一个自定义生成器来满足需求 这就是我现在拥有的;它可以工作,但我想生成更好的参数: (ns liblevenshtein.distance (:require [clojure.spec.alpha :as spec] [clojure.spec.gen.alpha :as ge

我有一个方法可以从成对的字符串中删除公共前缀,并且一直在尝试为它创建一个生成器。生成随机字符串对是很简单的,但是如何强制使许多对具有公共前缀呢?简单地过滤成对生成的示例数量不足,因此我尝试创建一个自定义生成器来满足需求

这就是我现在拥有的;它可以工作,但我想生成更好的参数:

(ns liblevenshtein.distance
  (:require [clojure.spec.alpha :as spec]
            [clojure.spec.gen.alpha :as gen]))

(spec/def ::word
  (spec/and string? (complement nil?)))

(spec/def ::v-w (spec/cat :v ::word, :w ::word))

(spec/def ::non-empty-v-w
  (spec/and ::v-w (fn [{:keys [v w]}]
                    (and (not-empty v)
                         (not-empty w)))))

(defn- drop-common-prefix [v w]
  (loop [v v, a (.charAt v 0), s (.substring v 1),
        w w, b (.charAt w 0), t (.substring w 1)]
    (if (and (= a b)
            (not-empty s)
            (not-empty t))
      (recur s (.charAt s 0) (.substring s 1)
            t (.charAt t 0) (.substring t 1))
      [v a s, w b t])))

(spec/fdef drop-common-prefix
        :args ::non-empty-v-w
        :ret (spec/tuple string? char? string?, string? char? string?)
        :fn (fn [{{:keys [v w]} :args, [v' a s, w' b t] :ret}]
              (and (= v' (str a s))
                   (.endsWith v v')
                   (= w' (str b t))
                   (.endsWith w w'))))
在试验发电机时,我得出了以下结论。它生成满足我要求的字符串对,但我不知道如何将它们拆分为函数的参数:

user=> (def prefix-pair-gen (gen/fmap (fn [[u v w]] [(str u v) (str u w)]) (spec/gen (spec/coll-of string? :type vector? :count 3))))
#'user/prefix-pair-gen
user=> (spec/def ::prefix-pair (spec/with-gen (spec/coll-of string? :type vector? :count 2) (fn [] prefix-pair-gen)))
:user/prefix-pair
user=> (gen/sample (spec/gen ::prefix-pair))
(["" ""]
 ["c" "cR"]
 ["lZ" "2F"]
 ["8a" "8a4"]
 ["n1D8CSq" "n1D8Gb1k"]
 ["X4PO" "X4Pu"]
 ["eAVM1" "eAVM1qg"]
 ["5e3DkZ6i" "5e3DkZv4Y"]
 ["3P7210" "3P7245cHM"]
 ["1c4D2j4UUK738" "1c4D2joFjd"])

我找到了解决办法,这是微不足道的。我应该多注意一下这些文件。
:args
说明:

:args函数参数的正则表达式规范,因为它们是 通过这种方式,单个规范可以处理函数 多重算术

因此,我可以直接提供生成的向量,如下所示:

(defn- drop-common-prefix [v w]
  (loop [v v, a (.charAt v 0), s (.substring v 1),
         w w, b (.charAt w 0), t (.substring w 1)]
    (if (and (= a b)
             (not-empty s)
             (not-empty t))
      (recur s (.charAt s 0) (.substring s 1)
             t (.charAt t 0) (.substring t 1))
      [v a s, w b t])))

(def prefix-pair-gen
  (gen/fmap
   (fn [[u v w]]
     [(str u v) (str u w)])
   (spec/gen
    (spec/and (spec/coll-of string? :type vector? :count 3)
              (fn [[u v w]]
                (and (not-empty v)
                     (not-empty w)))))))

(spec/def ::prefix-pair
  (spec/with-gen
    (spec/coll-of string? :type vector? :count 2)
    (constantly prefix-pair-gen)))

(spec/fdef drop-common-prefix
           :args ::prefix-pair
           :ret (spec/tuple string? char? string?, string? char? string?)
           :fn (fn [{[v w] :args, [v' a s, w' b t] :ret}]
                 (and (= v' (str a s))
                      (.endsWith v v')
                      (= w' (str b t))
                      (.endsWith w w'))))
我可以通过以下方式验证其正确性:

user> (stest/summarize-results (stest/check `liblevenshtein.distance/drop-common-prefix))
{:sym liblevenshtein.distance/drop-common-prefix}
{:total 1, :check-passed 1}

你的问题是,给定一个对序列,如何使用序列中的每一对参数调用一个双参数函数?不是,但它是相关的。我需要为规范函数生成相关参数的元组:这可能超出clojure.spec的范围,在这种情况下,我将把生成器逻辑移到单元测试。