2024 Clojure 状态调查中分享您的想法!

欢迎!请查看关于页面以了解更多关于如何使用本站的信息。

+8
协议
重新标记

clojure.protocols/nav 函数的签名是

[coll k v]

我不明白collkv应该是什么。有人能解释一下吗?也许可以提供一个用实际参数调用nav的示例?

例如,coll代表什么。它是指之前调用datafy的返回结果吗?因此,coll是我们将导航到的对象,还是说是v

我猜想k是用于深入探索所需的必要信息。

现在有v,所以我又不确定这是否意味着这是我们要导航进入的值。但如果是这样,那么coll又是什么?如果v不是那个,我就不明白它应该是什么了。不是值就是我们想让nav返回的吗?我们为什么还要提供它呢?

谢谢

2 个回答

+6

让我们假设我们有一个类型为Thing的对象,并且它有一个实现了datafy的方法,该方法生成一个描述该对象的Clojure哈希表。

myThing -> datafy -> description-hash-map

现在我们可以使用 get 在散列图中进行导航: (get description-hash-map :foo) 并会产生一个我们称为 foo-val 的值。

通过使用 datafyThing 世界到 Clojure 数据世界,我们可以使用所有常规的 Clojure 函数在 数据世界 中导航,但我们通常需要一种方法来在由数据世界中的元素表示的点返回到 Thing 世界。

这就是 nav 的作用所在。对于任何生成某些 foo-val 值的 (get description-hash-map :foo),我们可以通过调用 (nav description-hash-map :foo foo-val) 来返回到 Thing 世界中等效的点,并且这将产生一个 Thing 世界中的新对象。

然后我们可以通过在该新对象上调用 datafy 返回到 Clojure 数据世界,使用 get 在数据世界中导航,以及在 Thing 世界中导航回等效点。

myThing -> datafy -> description-hash-map

description-hash-map -> get -> more-data

description-hash-map -> nav (带 more-data) -> someNewThing

如果 datafy 产生一个向量,你可以通过向量、索引(向量的索引是有联系的)和该索引处的元素来调用 nav

在任何情况下,nav 可能会关心也可能不会关心值参数(确实,它也可能不会关心键参数...但这不太可能)。请注意,当 datafy 产生某些对象的的数据表示时,它会将原始对象添加为数据的元数据 - 并且此元数据可以通过 coll 参数提供给 nav,以便它可以访问原始对象,如果它需要的话。

如果你想在现实世界中查看一个具体的例子,请参阅 next.jdbc 的 datafynav:schema 机制

by
我已经检查了 next.jdbc 的实现,并且 never 在 nav 的实现中使用 collhttps://github.com/seancorfield/next-jdbc/blob/1b93d3a04ba033bb627e493df28f32330dfeb2e5/src/next/jdbc/result_set.clj#L643-L664

这让我更加困惑 :)
by
当这种情况发生时,“新的 Thing” 只需通过键和值来查找 - 因为外键关系是基于键和值(以及可能地,模式选项),而不是在找到它的行。

所以 nav 可能会关心也可能不会关心值、键,甚至是集合 :)
在导航期间,集合(coll)通常是一个存放所需元数据的便利地方。
好吧,所以我认为

- `v` 是我们要导航到的对象。
- `coll` 应该是调用 `datafy` 的结果
- `v` 应该在 `coll` 中,可以通过 `k` 获取

因此,一种使用场景可以是

(let [coll (datafy some-obj)
      k :next-thing
      v (get coll k)]
  (nav coll k v))

这将返回另一个东西(即任意可序列化对象),这是通过导航到 `v` 获得的。

从这个意义上说,`v` 应该是一个超链接,而且它实际上不是一个集合,这就是为什么我们导航到超链接指向的地方,并返回另一个我们可以稍后也进行序列化的东西。

所以一个完整的例子可以是

(let [url (as-url "https://clojure.org")
      clojure-page-as-coll (datafy url) ...

在这个地方,根据 URL 的 datafy 实现方式,我们可以假设返回了以下内容

{:content
 :links {:get-started (as-url "https://clojure.org/guides/getting_started")
         :overview (as-url "https://clojure.org/about/rationale")
         ...}
...}

那么,如果我们想导航到 [:links :overview],我们会这样做

(let [url (as-url "https://clojure.org")
      clojure-page-as-coll (datafy url)
      overview-url (get-in coll [:links :overview])
      overview-page (nav clojure-page-as-coll [:links :overview] overview-url) ...

所以现在我们已将一个 URL 作为 Clojure 集合进行了序列化。我们使用常规的 Clojure 集合函数进行了深入探索。当我们达到了另一个可导航值时,我们对其调用 nav 来获取下一页。

我对其中有几点仍然感到困惑。如果你看我提供的例子,我假设 nav 返回了一个序列化的结果。但肖恩提到它不应该返回,但在我提供的例子中这甚至都没有意义。我从 URL 开始。我可以 nav 到这个 URL 得到页面,但还没有 `coll` 上下文。而且我可以让 nav 返回一个尚未序列化的东西,但我没有这种东西,硬造一个也是怪异的。

在这里,我假设 `nav` 函数可以返回数据或可数据化的事物,这真的无所谓。我假定无论如何都会调用 `datafy`,但如果它已经是数据,`datafy` 将直接返回数据,因为这是 Map 的默认实现。

所以你可以继续这样操作

(let [url (as-url "https://clojure.org")
      clojure-page-as-coll (datafy url)
      overview-url (get-in coll [:links :overview])
      overview-page (nav clojure-page-as-coll [:links :overview] overview-url)
      overview-page-as-coll (datafy overview-page)]
  overview-page)

这是正确的吗?或者你应该从 `nav` 开始?或者我的例子可能不好,因为在这种情况下,`datafy` 可能是多余的,因为有人可能只是这样做

(let [clojure-page (nav nil nil (as-url "https://clojure.org"))
      overview-url (get-in clojure-page [:links :overview])
      overview-page (nav clojure-page [:links :overview] overview-url)]
  overview-page)

谢谢!
by
我期望 nav 与 get 匹配,而不是 get-in,我预计它是基于数据类型的(因为它基于协议)。

(注释对共享代码非常不好,所以我不会尝试,但我会基于你的 URI 导航构建一个示例,稍后带回来)
by
"我假设 `nav` 返回一个数据化的结果。"

不,应该返回一个对象。

"我可以通过 nav 进入该 URL 获取页面回传的结果 "

不,你首先应该数据化 URL 获取数据,然后在内获取数据(那里是你的集合)。

"并且我可能让 nav 返回一个非数据的事物,但我没有这样的事情,只是为它制造一件似乎很奇怪。”

如果你已经有数据,从 nav 返回它是完全可能的。但在这里,我认为你想要返回一个“as-url”对象,无论其形式如何。
by
> 否则,您应该首先数据化 URL 获取数据,然后在内获取数据(那里是你的集合)。

当你说“nav到数据”,我就感到困惑,因为集合可以被导航,比如get、get-in、first、nth等可以做到。为了导航到数据元素或其中的嵌套集合。但是,如果元素是超链接的形式,也可以导航到,因为这些内容需要从远程获取或渲染。

最初我以为nav既做前者也做后者,甚至把结果也“数据化”。但现在看来,nav可能只做后者?

如果nav只做后者,那么对于许多用例来说,它似乎将不会有任何作用,对吗?比如一个恒等函数。比如在不需要获取或渲染,只需要将内容转换为数据的情况下。比如在嵌套对象内部?

对于这一点,我假设datafy不应该深入。但这真的吗?datafy是否应该深度和递归地转换整个对象及其所有包含的对象,除了需要从远程获取更多数据或渲染的情况外?
by
事物世界 -> datafy -> Clojure数据世界

Clojure数据世界 -> get等 -> Clojure数据世界

Clojure数据世界 -> nav -> 事物世界

这里的“世界”转换很重要。

datafy或nav中任意一项都可以执行一些复杂的转换以转换“世界”。

例如,(datafy (java.net.URL. "..."))可以将Java对象转换成URL指定的内容,以数据的形式呈现。

事物世界 -> datafy -> Clojure数据世界。

在这个数据中的Clojure导航可以让你访问该页面上的每个链接(作为一个Clojure数据结构表示它,如{:link "..."})。

Clojure数据世界 -> get等 -> Clojure数据世界

然后可以将nav应用到相同的各种路径上,将{:link "..."}转换为java.net.URL对象。

Clojure数据世界 -> nav -> 事物世界

现在我们回到了事物世界,有一个java.net.URL对象...,我们可以将其数据化以获取引用内容作为数据结构,并返回Clojure数据世界。

如果你还没有尝试REBL,我强烈推荐你试试——它真的会使这一切更加清晰(至少,我希望如此)。
+1
by

nav是一个通用的导航框架。给定一个“容器”(集合)和容器的某些选择,导航到该选择。对于容器,k是有意义的(比如映射),对于某些情况则不需要,选择值本身就足够。作为一个通用框架,两者都提供,因为你可能需要两者来进行选择。

关于输入和输出的具体内容,这是一个完全基于上下文的答案。nav 是一种适合当前目的的工具,如果不了解特定的目标,就无法具体说明。你通常是 nav 的调用者和实现者(通过实例元数据),最重要的是它们应该匹配。

在 REBL 中,nav 用于浏览操作,当你左边的面板中有某个内容被选中时,你可以“浏览”进入它。其他用途可能做不同的事情(序列化对象图,等等)。

by
我原本以为在我拥有的东西中添加对 datafy/nav 的支持,将会在 REBL 中添加对其的支持。是这样吗?因为为此,我假设应该有一种“钻入”的约定,以便当你在内容面板中选择一个索引时,可以调用 nav,例如,当你评估某个表达式时,datafy 被应用于它,并在内容面板中显示结果,如果它是一个 REBL 可以选择进入的已知的类型,例如地图或向量,那么选择集合中的 idx 然后正向前移将调用 nav 对 datafy expr 进行调用,其中 `k` 是 idx 而 `v` 是 val,然后这个结果将成为新的 expr,并且它会重复。

我可以看到 datafy/nav 可以非常通用,基本上可以按照你自己的约定在内部使用,但在 REBL 的上下文中,是否有可以遵循的约定呢?

再次感谢!
by
编辑了 by
我实际上在 REBL 中试了试,看起来是这样的

1. 内容面板调用 datafy 对选定的 expr
2. 正向前移调用 nav,其中 `coll` 是从第 1 步返回的数据fy
3. `k` 是从内容面板选择的 `idx`
4. `v` 是从内容面板选择的 `val`

从这些和他回答里的,我得出结论,这个 https://gist.github.com/didibus/2a2a62d365f93d55db4fb27f46ecef89 是一个对 datafy/nav 合理使用?
在您的示例中不需要使用nav: https://github.com/seancorfield/datafy-nav-example/blob/master/src/datafy_test/alt.clj

这样做的结果与实现nav完全相同(因为没有实现nav, nav在哈希表上的默认行为就是只返回值v,这相当于你在当前上下文中如何调用nav。)
...