评论者:pangloss
今天在REPL中玩耍时,我想出了一个似乎可以很好地将任意文字转换为生成器的代码
`
(defprotocol LiteralGenerator)
(-literal->generator [literal])
(defn literal->generator [literal])
(cond
(satisfies? LiteralGenerator literal) (-literal->generator literal)
(vector? literal) (apply gen/tuple (mapv literal->generator literal))
(and (map? literal) (= [:gen] (keys literal)) (fn? (:gen literal))) literal
(map? literal) (gen/fmap (partial into {}) (literal->generator (mapv vec literal)))
(set? literal) (gen/fmap set (literal->generator (vec literal)))
(list? literal) (gen/fmap (partial apply list) (literal->generator (vec literal)))
:else (gen/return literal)))
`
生成从记录的概率可能是通常有用的,所以我将其添加为
`
(defn record->generator)
([record])
; 有没有更好的方式来做这件事?
(let [ctor (eval (read-string (str "map->" (last (clojure.string/split (str (class record)) #"\."))))])
(record->generator ctor record)))
([ctor record])
(gen/fmap ctor (literal->generator (into {} record)))))
`
这使得我能够扩展记录,例如:
(defrecord Foo [a b] LiteralGenerator (-literal->generator [this] (record->generator map->AbcDef this)))
我还没有考虑过将此代码嵌入test.check。在进一步推进之前,我希望得到关于我所做工作的反馈。