Functional programming clojure,如何减少重复代码(可能使用宏)

Functional programming clojure,如何减少重复代码(可能使用宏),functional-programming,clojure,cron,quartzite,Functional Programming,Clojure,Cron,Quartzite,TL;DR 如何减少以下重复代码,如从作业清单创建两个作业/触发器,而不是重复两次并创建术语 ;; project.clj中的deps ;; [clojurewerkz/石英岩“2.1.0”] (ns hello.scheduler) (:require[clojurewerkz.quartzite.scheduler:as qs] [clojurewerkz.石英岩.触发器:as t] [clojurewerkz.石英岩.工作:as j] [clojurewerkz.quartize.job

TL;DR

如何减少以下重复代码,如从作业清单创建两个作业/触发器,而不是重复两次并创建术语


;; project.clj中的deps
;; [clojurewerkz/石英岩“2.1.0”]
(ns hello.scheduler)
(:require[clojurewerkz.quartzite.scheduler:as qs]
[clojurewerkz.石英岩.触发器:as t]
[clojurewerkz.石英岩.工作:as j]
[clojurewerkz.quartize.jobs:参考[defjob]]
[clojurewerkz.quartize.schedule.cron:as-cron])
(:使用clojure.tools.logging)
(:gen类)
(def作业清单
[{:name“add”:task'(+1):cron“0/5**?**”}
{:名称“multiply”:任务“(*45):cron“0/3**?**”}”)
(defjob add[ctx](信息“add called,return”(+1)))
(defjob multiply[ctx](信息“调用乘法,返回”(*23)))
(defn自动
[]
(让[s(->(qs/初始化)qs/启动)
_(qs/clear!s)
工作(j/建造)
(j/类型添加)
(j/带有标识(j/键“job.add”))
触发器(t/build)
(t/带有标识(t/键“trigger.add”))
(t/现在开始)
(t/带有时间表(cron/时间表
(cron/cron计划“0/5**?**”))
_(qs/计划s作业触发器)
工作(j/建造)
(j/属于乘法类型)
(j/带有标识(j/键“job.multiply”))
触发器(t/build)
(t/带标识(t/键“触发器.乘法”))
(t/现在开始)
(t/带有时间表(cron/时间表
(cron/cron计划“0/3**?**”))
_(qs/计划s作业触发器)
]
))

与中所述类似, 我有一个代码块来创建作业,并将它们挂起执行

问题是,当我得到越来越多的数据时,我想知道我是否可以有更好的方法来管理它们,比如从
作业清单创建/生成,而不是实际创建变量,比如
添加
倍增

因此,要求多做一层循环 有没有办法利用函数编程,避免创建新名称(在传统语言中,pythonqt说,如果我有一组按钮,我就可以冲进一个巨大的字典,循环创建/禁用,而实际上是将每个名称创建为顶级变量)


我试过宏,但它说无法解析类add,所以我猜我用错了。要记住的关键是函数是数据。虽然您不能很容易地动态创建类型(与通过
具体化
实现接口的实例相反),但您可以静态创建一个类,然后代理您的函数

首先,让我们将
作业清单
:任务
作为一个函数

(def job-inventory
  [{:name "add" :task (fn [] (println (+ 1 1))) :cron "0/5 * * ? * *"}
   {:name "multiply" :task (fn [] (println (* 4 5)))  :cron "0/3 * * ? * *"}])
然后我们需要代理作业类。这将执行它在作业数据中找到的函数

;; require clojurewerkz.quartzite.conversion :as qc
(defjob proxy-job [ctx]
  (let [ctx (qc/from-job-data ctx)]
    ((ctx "proxied-fn"))))
然后,我们创建一个调度函数,该函数从作业资源清册中获取一个映射,并使用代理作业将其调度到间接作业

(defn schedule [scheduler {:keys [:name :task :cron]}]
  (let [job (j/build
             (j/of-type proxy-job)
             (j/using-job-data {"proxied-fn" task})
             (j/with-identity (j/key (str "job." name))))
        trigger (t/build
                 (t/with-identity (t/key (str "trigger." name)))
                 (t/start-now)
                 (t/with-schedule (cron/schedule
                                   (cron/cron-schedule "0/3 * * ? * *"))))]
  (qs/schedule scheduler job trigger)
  scheduler)

(reduce scheduler schedule job-inventory)

如果quartz决定序列化/反序列化作业数据,这种方法可能会崩溃。对于感兴趣的读者来说,我将用另一层间接方式来解决这个问题作为一个简单的练习——老实说,我最初的想法是,我们创建命名函数,然后用符号来引用,但这会使代理复杂化,让你想知道为什么不使用defjob。如果您准备解除作业功能,您仍然可以在作业清单中引用它们,并拥有一个基于数据的作业生成器功能。

您可能希望考虑的相关库:@AlanThompson感谢您的关注,这里只有三个任务,但在这样的石英术语中,我必须构建一个job-a类型的job-a和一个trigger-a,然后连接到日程,可能会考虑看看他们的教程,没有严格的连接或这些工作之间的依赖关系。@ AlanThompson感谢线索,并一定要看看,在这里我有一个项目已经是一种CRON格式时间表配置,所以将更吸引人,如果这是兼容的,感谢您的时间:)@AlanThompson这里的问题可能是,我如何在循环中调用
defjob-a defjob-b defjob-c
,这是一种代码生成技巧。@AlanThompson嗨,Alan,我已经减少了描述,只显示了代码片段,希望它更清晰一些
(def job-inventory
  [{:name "add" :task (fn [] (println (+ 1 1))) :cron "0/5 * * ? * *"}
   {:name "multiply" :task (fn [] (println (* 4 5)))  :cron "0/3 * * ? * *"}])