向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 and :idem above could obvs be done with :fn, but seems handy to put together once one gets :comm and :assoc in place.
这可能引出对如何同样处理相关函数集的约束或不变性的问题,尽管这可能不太有用。然而,这实际上可能更合适的是将其作为fspec之外的单独规范来做 - ?