【问题标题】:What does -> do in clojure?-> 在 clojure 中做什么?
【发布时间】:2011-01-02 16:13:39
【问题描述】:

我在很多地方看到过 clojure 符号 -> ,但我不确定这个符号的名称和作用,甚至不确定它是否是标准 clojure 的一部分。有人可以向我解释一下吗?

【问题讨论】:

    标签: clojure


    【解决方案1】:

    -> 使用函数调用的结果并将其按顺序发送到下一个函数调用。

    所以,更简单的例子是:

     (-> 2 (+ 3))
    

    返回 5,因为它将 2 发送到下一个函数调用 (+ 3)

    以此为基础,

    (-> 2 
      (+ 3) 
      (- 7))
    

    返回 -2。我们保留第一次调用的结果 (+ 3) 并将其发送到第二次调用 (- 7)。

    正如@bending 所指出的,接受的答案会更好地显示 doto 宏。

    (doto person
      (.setFName "Joe")
      (.setLName "Bob")
      (.setHeight [6 2]))
    

    【讨论】:

    • 这是不准确的。 2 不会发送到(+ 3) 的函数调用...而是宏将代码从(-> a b c) 重新排列为(c (b a))
    • 主要是玩文字游戏,但我接受批评。感谢您的澄清。
    • @nicolas 从提交之日起,我就一直想更新我的答案,因为它令人困惑,但网站不允许我这样做。我对答案进行了姗姗来迟的更新。如果它仍然具有误导性,请告诉我。
    【解决方案2】:

    这是一种从左到右编写代码的方式,而不是由内而外,例如

    (reduce (map (map xs bar) foo) baz)
    

    变成

    (-> xs (map bar) (map foo) (reduce baz))
    

    您可能想阅读源代码,它是here

    编辑:由于 amalloy,修复了我对 ->->> 的混淆。遗憾的是,我的例子现在不太可能出现在实践中。

    【讨论】:

    • 我最喜欢 Clojure 中关于画眉运算符的解释:debasishg.blogspot.com/2010/04/thrush-in-clojure.html
    • 这在一般情况下是正确的,但在细节上是错误的。您描述了->> 的行为,而不是->。您提供的示例将扩展到(reduce (map (map xs bar) foo) baz),因为-> 穿过second 位置,而不是last(这是->> 所做的)。
    • 对不起,我会修正我的答案。
    • @amalloy 该死的 Clojure;第三个答案,被访者又错了! :-)
    【解决方案3】:

    直到我把它想象成这样,我才完全明白 ->(画眉或线)做了什么:

    (-> expr f1 f2 f3)  ;same as (f3 (f2 (f1 expr)))
    
    (-> expr            ;same as form above
        f1              ;just a different visual layout
        f2
        f3)
    
    ;this form is equivalant and shows the lists for f1, f2, f3.
    (->         expr     ; expr treaded into first form
            (f1     )    ;  |   result threaded into next form
        (f2          )   ;  |   and so on...
    (f3               )) ;  V   the lists (f1
    
    (f3 (f2 (f1 expr)))  ;the result is the same as this  
    

    这里有一些例子:

    (-> 41 inc dec inc)   ;same as (inc (dec (inc 41)))
    42
    
    (->            41     ;same as above but more readable
              (inc   )
         (dec         )
    (inc               ))
    42
    
    (inc (dec (inc 41)))  ;easier to see equivalence with above form.
    42
    
    (-> 4 (* 4 3) (- 6))  ;same as (- (* 4 3 4) 6)
    42 
    
    (->   4               ;      4
       (*   3 4)          ;   (* 4 3 4)
    (-           6))      ;(- (* 4 3 4) 6)
    42
    
    (- (* 4 3 4) 6)       ;easier to see equivalence with above form.
    42
    

    【讨论】:

    • 嘿,我对你的解释有疑问,你写了(-> expr f1 f2 f3) ;same as (f3 (f2 (f1 expr)))(-> 2 (+ 3) ( - 7)) 不等于( - 7 (+ 3 2)) 第一个结果是-2 但第二个是2 你能帮我解决我的误解?
    【解决方案4】:

    '->' 是一个宏。我认为,描述它的最佳方式是“点特殊形式”的示例,它的目的是使代码更简洁易读,如 clojure.org 网站对The Dot special form 的解释所示

    (.. System (getProperties) (get "os.name"))
    

    扩展到:

    (. (. System (getProperties)) (get "os.name"))
    

    但更易于编写、阅读和理解。另请参阅 -> 可以类似使用的宏:

    (-> (System/getProperties) (.get "os.name"))
    

    还有“doto”。假设您有一个对象,您想在其上调用多个连续的 setter。你可以使用“doto”。

    (doto person
      (.setFName "Joe")
      (.setLName "Bob")
      (.setHeight [6 2]))
    

    在上面的示例中,setter 不返回任何内容,因此 'doto' 是合适的选择。除非设置器返回 'this',否则 -> 将无法代替 'doto'。

    所以,这些是与 -> 宏相关的一些技术。我希望这不仅有助于解释它们的作用,还有助于解释它们存在的原因。

    【讨论】:

    • 你的二传手都返回这个?如果没有,那么您将希望使用 (doto ...)
    【解决方案5】:

    你可以自己看看:

    (macroexpand `(-> 42 inc dec))
    

    【讨论】:

      【解决方案6】:

      它被称为画眉运算符。最好解释一下here

      【讨论】:

      • 这不是真的。 Thrush 是一个函数,其行为类似于->->->> 是宏,我通常听到它们被称为“线程”宏,因为它们将第一个表单“穿过”其余的表单,从而形成一个缝合在一起的表单。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-18
      • 1970-01-01
      • 2014-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多