【问题标题】:Is gathering namespace functions into a map via a macros idiomatic Clojure?是否通过宏惯用的 Clojure 将命名空间函数收集到地图中?
【发布时间】:2019-01-25 06:49:21
【问题描述】:

我正在通过一个宠物项目学习 Clojure。该项目将由几个 workers 组成,它们将从其他函数中调用。

每个工作人员在自己的命名空间中定义为一组函数(目前有两个:get-data 用于收集数据,write-data 用于将收集的数据写入文件)。

为了使代码更干一点,我决定编写一个宏,将命名空间中的函数收集到一个可以传递的映射中:

(ns clojure-bgproc.workers)

(defmacro gen-worker-info []
  (let [get-data (ns-resolve *ns* 'get-data)
        write-data (ns-resolve *ns* 'write-data)]
    `(def ~(quote worker-info)
       {:get-data ~get-data
        :write-data ~write-data}
       )
    )
  )

在我的工作代码中,我使用了我的宏(为清楚起见,代码被删减):

(ns clojure-bgproc.workers.summary
  (:require [clojure-bgproc.workers :refer [gen-worker-info]]))

(defn get-data [params]
  <...>
  )

(defn write-data [data file]
  ;; <...>
  )

(gen-worker-info)

虽然它确实有效(我在 clojure-bgproc.workers.summary/worker-info 中获得了我的 get-datawrite-data 函数,但我觉得它有点恶心,特别是因为如果我将宏调用移动到文件顶部,它不会没用。

我的问题是,有没有更惯用的方法呢?这就是惯用的 Clojure 吗?

谢谢。

【问题讨论】:

  • 这可能更适合codereview.stackexchange.com
  • 哦,好的,谢谢!可以在那里交叉发布吗?还是我应该先在这里删除这个问题?

标签: clojure macros


【解决方案1】:

我认为你的情况很奇怪,因为你的程序结构错误:

每个工作人员都在自己的命名空间中定义为一组函数

这是真正的问题。命名空间是放置您将在手写代码中引用的函数和值的好地方。对于你想以编程方式访问的东西,它们不是一个好的存储空间。取而代之的是,通过将您想要访问的数据放入一个普通的适当数据结构中,使其成为一流的,然后它就很容易操作。

例如,您正在考虑从命名空间派生的这个worker-info 映射非常棒!事实上,这应该是唯一工人的表现方式:作为具有工人功能键的地图。然后,您只需在某处定义此类工作人员地图的列表(或向量或地图),这就是您的工作人员列表。不需要搞乱命名空间。

【讨论】:

    【解决方案2】:

    我定义工人的首选解决方案是协议。我还将应用一些久经考验的系统生命周期管理框架。

    Protocols 提供了一种定义一组方法及其签名的方法。您可能认为它们与面向对象编程中的接口 相似,但更灵活。

    您的工人可能会有一些状态和生命周期,例如,工人可能正在运行或停止,获取和释放资源,等等。我建议您查看 Integrant 以管理具有状态组件(即工作人员)的系统。

    在这种情况下,我会主张避免使用宏。格言data over functions over macros 似乎适用于此。宏在运行时不可用,使调试更加困难,并迫使所有其他查看您的代码的程序员学习一种新的领域特定语言,即您使用宏定义的语言。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-12
      • 2016-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-05
      相关资源
      最近更新 更多