评论者: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)))))
`
这样我就可以扩展记录,如下所示
定义了名为 Foo 的记录类型,包括字段 a 和 b,它是 LiteralGenerator 的示例,使用了 (-literal->generator [this] (record->generator map->AbcDef this)))
我还没有仔细检查将这段代码整合到 test.check 的可能性。在继续深入之前,我想先听听大家对目前成果的看法。