代码之家  ›  专栏  ›  技术社区  ›  Michiel de Mare

Clojure宏在常量中收集字符串

  •  1
  • Michiel de Mare  · 技术社区  · 14 年前

    我有一个带有很多字符串常量的Clojure文件。我想通过在宏中包装这些字符串来在集合中收集它们。经过几次尝试,我成功了,但我的解决方案看起来相当可怕。

    (ns Memorable)
    (def MEMORY (atom []))
    (defmacro memorize [s] (swap! MEMORY conj s) s)
    
    (prn (str (memorize "hello") " brave new " (memorize "world")))  ;  test
    
    (defmacro make-memories-constant [] `(def MEMORIES ~(deref MEMORY)))
    (make-memories-constant)
    

    有没有更好的解决方案?

    1 回复  |  直到 14 年前
        1
  •  1
  •   Michał Marczyk    14 年前

    就代码清理而言,我将删除 make-memories-constant 宏——你可以

    (def MEMORIES @MEMORY)
    

    甚至

    (def MEMORY @MEMORY)
    

    这样就不会用另一个变量搅乱名称空间 memorize ,这将保存 MEMORY 与所有人 记住 d弦在里面。

    我认为这实际上是非常干净的,实际的代码在运行时执行与没有任何不同 记住 -正在。。。

    另一种方法是准备一种“记忆框架”,作为一个单独的名称空间,导出一个名为 setup-memorization ,比如,看起来像这样( 只是一个粗略的草图 如果不抛光就不行了 ... 更新了一个(不是很彻底)经过测试的版本——这实际上是可行的! ... 不过,请根据您的需要进行调整):

    (ns memorization-framework)
    
    (defmacro setup-memorization []
      (let [MEMORY (gensym "MEMORY")
            MEMORIES (gensym "MEMORIES")]
        `(do (def ~MEMORY (atom []))
             (defmacro ~'memorize [s#] (swap! ~MEMORY conj s#) s#)
             (defmacro ~'get-memory [] @~MEMORY)
             (defmacro ~'defmemories [~MEMORIES]
               `(do (def ~~MEMORIES @~~MEMORY)
                    (ns-unmap ~~*ns* '~'~'get-memory)
                    (ns-unmap ~~*ns* '~'~'memorize)
                    (ns-unmap ~~*ns* '~'~MEMORY)
                    ~~MEMORIES)))))
    

    那么你会 use 这个 memorization-framework 命名空间,do (setup-memorization) 在你的名字空间顶部设置,调用 记住 就像你在你的示例代码中所做的那样,记住一些事情并最终使用 end-memorization defmemories 存储字符串集合 在某处 在一个Var中,删除用于存储用于构建时存储的atom的临时Var,以及对 记住 从这个名称空间。( 这个 结束记忆 宏的意思是,当调用集合时,如果没有参数,则只将集合返回到调用它的位置,或者定义一个新的变量(如果给定了一个参数,则必须是用于命名该变量的符号)来存储该集合。 更新:我只测试了 解除记忆 版本,所以我把它留在这里,删除“就地返回”变量。)

    命名空间中REPL处的示例交互 foo (注1定义 设置记忆 user 命名空间):

    foo> (user/setup-memorization)
    #'foo/defmemories
    foo> (get-memory)
    []
    foo> (memorize "foo")
    "foo"
    foo> (memorize "bar")
    "bar"
    foo> (get-memory)
    ["foo" "bar"]
    foo> (defmemories quux)
    ["foo" "bar"]
    foo> quux
    ["foo" "bar"]
    foo> (get-memory)
    ; Evaluation aborted.
    foo> (memorize)
    ; Evaluation aborted.
    

    那些“评估中止”消息表明 get-memory 记住 在之后引发异常 解除记忆 已被呼叫。这是设计的,如上所述。也, 获取内存 主要是为了简化测试/调试。

    如果你只想用一次这一切 设置记忆 这种方法可能有点过头了,但我想如果你多用它,它会帮你去掉一些样板文件。