是否觉得在fspec中添加一个新的kwarg,允许函数规范在函数的不同调用中提供一条或多条约束,例如交换性很有用。我正在做这个,但想看看是否有人觉得这很有用。
新的kwarg可能是:alg,因为这个选项允许表达函数的代数属性,它将接受一个映射,其中键命名为关键字,值是谓词(通常需要一个let)。
像下面这样,看起来像几个二元操作符
(s/fdef add
:args (s/cat :x int? :y int?)
:ret int?
:alg { :comm
(let [f (:f %)
x (-> % args :x)
y (-> % args :x)]
(= ((f x y) (f y x))
:assoc
(let [f (:f %)
x (-> % args :x)
y (-> % args :x)
z (-> % args :x)]
(= (f (f x y) z) (f x (f y z)))
:ident
(let [f (:f %)
x (-> % args :x)]
(= (f x 0) x))})
(s/fdef mul
:args (s/cat :x int? :y int?)
:ret int?
:alg { :comm
(let [f (:f %)
x (-> % args :x)
y (-> % args :x)]
(= ((f x y) (f y x))
:assoc
(let [f (:f %)
x (-> % args :x)
y (-> % args :x)
z (-> % args :x)]
(= (f (f x y) z) (f x (f y z)))
:ident
(let [f (:f %)
x (-> % args :x)]
(= (f x 0) x))
:super
(let [f (:f %)
x (-> % args :x)]
(= (f x 0) 0))})
(s/fdef max
:args (s/cat :x int? :y int?)
:ret int?
:alg { :comm
(let [f (:f %)
x (-> % args :x)
y (-> % args :x)]
(= ((f x y) (f y x))
:assoc
(let [f (:f %)
x (-> % args :x)
y (-> % args :x)
z (-> % args :x)]
(= (f (f x y) z) (f x (f y z)))
:idem
(let [f (:f %)
x (-> % args :x)]
(= (f x x) x)})
:ident, :super和:idem上面可以通过:fn来实现,但似乎在实际操作中放在一起会更方便。
这可能会引发一个问题:如何类似地处理相关函数集中或不变式的约束,尽管这可能不太常用。然而,这可能表明实际上应该将此与fspec分开,在单独的spec中实现 - ?