Clojure: 关于 when-let 和 if-let 的文档语法

3

我一直在研究if-let和when-let宏,但我很难确定它们到底是做什么的。特别是文档中说:

clojure.core/when-let
([bindings & body])
Macro
  bindings => binding-form test

  When test is true, evaluates body with binding-form bound to the value of test

我对宏的文档方式感到有些困惑。
1)“=>”符号是什么意思?
2)“test”是指什么?
3个回答

4

当处理宏时,调用macroexpand并查看生成的代码通常很有帮助。

(macroexpand
    '(if-let [x (myfunc)]
       (foo x)
       (bar))

; expands to

(let* [temp__3695__auto__ (myfunc)] 
   (if temp__3695__auto__ (clojure.core/let [x temp__3695__auto__] 
     (foo x)) 
     (bar)))

; the generated symbols are necessary to avoid symbol 
; capture but can confuse. The above is equivalent to:

(let* [ t (myfunc)]
    (if t
       (let [x t]
           (foo x))
       (bar))

所以你可以看到,if-let是一个缩写,用于“将本地变量绑定到函数调用的结果,并且如果该变量为真值,则调用第一种形式,否则调用另一种形式。你的函数返回的值仅在“真值”分支中可用。”

wrt文档约定

bindings => binding-form test
  1. => 的意思大致是“等同于”
  2. test 是返回值的某种形式

对于大多数这些函数,clojuredocs 是您的朋友,示例用法通常可以澄清问题。如果 clojuredocs 的示例不足以满足您的需求,您可以添加自己的示例。


谢谢,这对我确实很有用。顺便说一下,我相信从其他答案中阅读到的“=>”具有精确的含义。我认为更新您的答案中的(1)和(2)以与Rafal的回答保持一致会很好。 - jayunit100

4

针对您的问题直接回答:

  1. =>表示“扩展为”,就像BNF符号一样。在这种情况下,它意味着您需要两种形式:绑定形式和测试。
  2. “测试”指任何可以作为布尔值评估的内容。

顺便说一句,我认为文档在这里不够清晰,甚至可能是错误的。很难(或不可能)推断出组成绑定的两个表单需要被包含在一个向量中。在我看来,应该是 when-let ([[bindings] & body])(参数中显示的向量)或 bindings => [binding-form test](类似BNF的扩展中显示的向量)。


谢谢...这太棒了,因为最重要的是理解文档,这样我才能理解其他方法。 - jayunit100

2

Consider the following code:

(if-let [x (a-function)]
  (do-something-with x) ;; (a-function) returned a truthy result
  (do-something-else)   ;; (a-function) returned nil or false

这类似于let,因为x将绑定到(a-function)的返回值。该函数可能返回nilfalse。在这种情况下,隐式测试失败,并且将评估(do-something-else)。如果x不是nil并且不是false,则将评估(do-something-with x)
这可能有用的一个场景:
(if-let [user (find-logged-in-user)]
  (do something with logged in user) ;; a user was found
  (redirect to login page)           ;; no user was found

我有时会使用以下类似的方法,根据条件向选项映射中添加键:

(apply merge {:username "joe"
              :email "joe@example.com"}
             (when-let [name (find-full-name)] {:name name})
             (when-let [dob (find-date-of-birth)] {:dob dob}))

这将生成一个映射,其中包含:username:email键,如果发现用户的全名,则还会有一个:name键,如果发现出生日期,则还会有一个:dob 键。

希望这样能更清楚地使用if-letwhen-let


第三个使用 merge-map 的示例非常好,谢谢。 - jayunit100

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接