如何使用clojure.spec生成相互关联的args?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用clojure.spec生成相互关联的args?相关的知识,希望对你有一定的参考价值。
我有一个方法从字符串对中删除公共前缀,并一直在尝试为它创建一个生成器。生成随机字符串对是微不足道的,但是如何强制执行许多对具有共同的前缀?简单地过滤这些对会产生足够数量的示例,因此我尝试创建一个自定义生成器来满足要求。
这就是我现在拥有的;它有效,但我想生成更好的参数:
(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
documentation for fdef
说:
:args函数参数的正则表达式规范,因为它们是要传递给应用的列表 - 这样,单个规范可以处理具有多个arities的函数
因此,我可以直接提供生成的向量,如下所示:
(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生成相互关联的args?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用带有 Ninja 生成器的 CMake 将修饰符标志传递给存档文件(ar)