使用 Spectre 递归地改变地图中的值

Recursively mutating values in a map of maps with Specter

完整的 Clojure 新手在这里。这是一个简单的问题,但我似乎无法理解:

鉴于我有一个未知深度的嵌套 hasmap,我如何使用 Spectre 的 transform() 来改变数据结构的值?我想这里需要一个递归路径,但我无法让它工作。一个工作示例就是我所追求的,不幸的是,文档中没有。

(在递归映射上有一个用于 set-val 的 example,但我不知道如何将其转换为转换用例)

编辑:要求提供更多详细信息,因此它们是: 我对一种变换形式很感兴趣,它可以改变嵌套地图的所有值——任何深度)。例如,此转换将能够增加以下映射(以及任何其他嵌套映射)中的所有值:

{:a 1 :b {:c 2 :d {:e 3}}} 
AND
{:a 1 :b {:c 2}}
AND
{:a 1}

我感兴趣的代码行可能看起来像这样:

(transform <missing selector here> inc data)

使用 linked example

(def MAP-NODES
   (recursive-path [] p
     (if-path map?
       (continue-then-stay MAP-VALS p))))
(transform [MAP-NODES MAP-VALS number?] inc data)

一定要经常学习Clojure CheatSheet。对于这么简单的事情,使用 clojure.walk/postwalk

可能是最简单的
(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require [clojure.walk :as walk]))

(dotest
  (let [data   {:a 1 :b {:c 2 :d {:e 3}}}
        result (walk/postwalk (fn [item]
                                (if (int? item)
                                  (inc item)
                                  item))
                 data)]
    (is= result {:a 2, :b {:c 3, :d {:e 4}}})))

对于更高级的问题,您可能对函数 walk-with-parents 感兴趣,它允许您检查从根节点到当前节点的路径上的所有项目。