【问题标题】:Clojure: Function to determine map's valueClojure:确定地图值的函数
【发布时间】:2013-07-02 13:50:07
【问题描述】:

这个问题我越想越觉得不对……

我在我的程序中定义了类似“地图构造函数”的东西。这背后的想法是我有一个通用的地图结构来处理一些“项目”,但我想为特定类型的项目强制执行一些默认值。

我遇到的问题是这个“地图构造函数”有一个 k-v 对,并且该对的值应该由使用该地图的函数确定(在下面的示例中可能会更清楚)。

我的第一个想法是在值中引用一个表达式,然后在上述函数中对其执行eval。第二个想法是将值替换为fn,但这似乎返回类似于引用表达式的内容。

让我试着描述一下这个问题:

  • 模型生成的地图应该类似于 {:a 1 :b 2 :c 3}
  • 构造函数类似于

    (defn cons-field [b]
      {:a (fn [name] (str name "!"))
       :b b
       :c "default"})
    
  • 项目已创建(def a-field (cons-field 5))

  • 使用地图的调用函数类似于

     (defn the-function [name field]
       (str (get-in field [:a])))
    

现在我需要的是这个 :a 的值作为 'the-function' 中参数名称的函数。当然最后一个功能不起作用,我不确定它是否是正确的方法。 ':a' 键并不总是fn;有时它只是一个字符串文字。有什么想法吗?

干杯!

【问题讨论】:

  • 代替构造函数,为什么不用assoc 到默认映射呢?对于一般问题,尝试将逻辑与数据分离,并从对数据的连续转换的角度进行思考。您能否提供更多详细信息或示例,说明您到底想要完成什么?
  • 我最初的想法是合并两个地图,但是通过提供构造函数,您有点限制有效输入。我知道我应该将逻辑和数据分开,但是对于这个特殊的问题,我想不出一个通用的方法来处理它。实际问题与工作有关,我不喜欢共享代码,但想法是一样的。我需要生成一些报告,对于每个报告,此字段具有不同的功能。
  • @DimitriosK.,你仍然可以让你的构造函数提供默认值(比如:c),只是不要提供:a。如果需要通过函数调用确定:a 的值,则在地图上进行转换。
  • @JeremyHeiler,是的,我在地图外创建了一个新函数,并在调用者上创建了一个 cond 以确定它是否是特殊情况,然后调用该函数。 :)

标签: clojure


【解决方案1】:

这就是我在 A. Webb 和 Jeremy Heiler 的 cmets 之后解决这个问题的方法。

初始构造函数改成这样:

(defn cons-field [b]
  {:a nil ; either delete completely or comment that
          ; the case will be handled by the caller
   :flag xx ; true or :case-qualifier
   :b b
   :c "default"})

调用函数改成这样:

(defn the-function [name field]
  (let [case-q (:flag field)]
    (cond
      (= case-q :case-qualifier) (get-name name) ; you can have many different cases
                                              ; conciser using constants for these qualifiers
      (...) ()))) ; else as normal

然后最初放入地图的逻辑进入不同的函数:

(defn get-name [name] (str name "!"))

希望这对其他人有帮助:)

【讨论】:

    【解决方案2】:

    根据您发布的内容,无法真正理解您的问题。我能为您做的就是告诉您您提供的代码做了什么,并猜测您希望它做什么。

    (def r (cons-field 5)) 使用 (r :b) = 5、(r :c) = "default" 和 (r :a) = (fn [name] (str name "!")) 创建一个哈希映射 r。如您所见,(r :a) 的结果和(r :c) 的结果都与 r 或 5 无关。

    如果上面描述的结果是你想要的,那么做一些重构是合乎逻辑的:

    (def default-field {:a (fn [name] (str name "!"))
                        :c "default"})
    
    (def cons-field (partial assoc default-field :b))
    

    关于the-function:对(get-in field [:a]) 的调用与(field :a) 相同,将返回函数(fn [name] ...)the-function 将使用 str 对该 fn 进行字符串化,并且很可能返回类似“user.fn$23092....”的内容

    如果您希望 the-function 返回调用 (fn [name] ...) 的结果并将名称传递给函数,您需要更改您的 the-function 如下:

    (defn the-function 
      [name field]
      (str ((field :a) name)))
    

    如果你想让the function根据:a的实际值返回别的东西,你可以检查它是否是一个函数并用名字调用它,否则返回值。

    (defn the-function
      [name field]
      (when-let [v (field :a)]
        (or (when (fn? v)
              (v name))
            v)))
    

    现在阅读您自己的答案,我更加困惑您要解决的实际问题是什么,但我希望这个答案可以提供帮助。

    【讨论】:

    • 我在我的解决方案中所做的基本上是从地图中取出函数(因为函数对所有内容都是相同的)并将其作为一个单独的函数并添加一个标志来确定调用者是否应该调用此函数或仅使用字段中的字符串。我承认我的英语不是最好的,而且我在 clojure 和 FP 方面的经验已经有 4 周了...感谢您的解决方案,我会尝试一下。
    • 我认为您需要地图中的函数,以便以后可以将其替换为采用 [name] 的其他函数。如果您还有任何问题,请不要犹豫:)
    猜你喜欢
    • 2015-11-20
    • 2020-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-07
    • 2019-10-26
    • 2017-03-27
    相关资源
    最近更新 更多