添加一个新的kwarg到fspec,是否似乎有用,以便函数规范可以在函数的不同调用之间提供或保持一个或多个约束或不变量,从而提供如交换性之类的约束?我正在研究这个,但认为最好检查是否还有人认为这是有用的。
这个新的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 实现,但似乎在放置::comm 和 :assoc 后将其放在一起会更方便。
这可能会引发关于如何类似地处理对一组相关函数进行或不变量的约束的问题,尽管这可能不太常用。然而,这可能表明实际上这最好作为fspec之外的单独规范来完成,?