我什么时候应该使用clojure箭头宏?

ToB*_*ced 18 syntax macros clojure operators

在努力保持功能风格时,我很难理解何时应该更喜欢:

(-> [1 2 3] reverse last)
Run Code Online (Sandbox Code Playgroud)

过度:

(last (reverse [1 2 3]))
Run Code Online (Sandbox Code Playgroud)

当我在一个项目中遇到这两种风格时,我发现它打破了我的流程,因为我必须在思考函数组合和思考中间值状态之间切换.

我应该在什么时候使用哪个?

ama*_*loy 15

我主要避免使用->单参数函数; 当你有多个参数函数时它会更有用,因为它允许你将每个函数保持在它的"额外参数"旁边,而焦点对象不会遮挡它.

而且,你不必选择一个或另一个极端:我最喜欢的一件事->是它允许你以任何顺序编写函数,你可以用这种自由来以任何方式编写代码你认为最具可读性.例如,也许你想要强调你正在采用最后一个集合,而在上下文中,它首先被颠倒的事实是无趣的:

(last (-> [1 2 3] (reverse)))
Run Code Online (Sandbox Code Playgroud)

或许逆转很重要,最后很无聊:

(-> (reverse [1 2 3]) (last))
Run Code Online (Sandbox Code Playgroud)

顺便说一句,请注意,我写的(last),并(reverse)在这里,而不是仅仅lastreverse即使->如果你离开他们走出宏观隐含插入你的括号.这是有目的的:虽然它不是一种非常流行的风格,但我认为总是在给出的形式中使用括号是个好主意->.有几个原因:

  • 这意味着你在(-> (blah) (fn [x] (+ 1 (* x 5))))奇怪地扩展时并不感到惊讶,因为你习惯于认为它->采用的是形式而不是函数.
  • 它保持"这是一个开括号"和"一个函数被调用"之间的联系.很高兴能够grep调用特定函数,这也是一个很好的视觉提示.如果省略括号,则在不进行视觉信号的情况下调用函数.
  • 它在->具有一些一元函数和其他多参数函数的多行中看起来更规则.例如:

    (-> attrs
        (update :sessions inc)
        frobnicate
        save-to-disk
        (get :uuid))
    
    Run Code Online (Sandbox Code Playgroud)

    将这两件事放在中间偏移,看起来与其他一切有什么不同,这不是很严重吗?

我所见过的唯一一个省略()s的论点是它保存了两个字符的输入,这根本不是一个参数.


Art*_*ldt 9

我的简单经验法则是"哪一个更接近更具声明性的英语句子".如果你粗略地将它们翻译成描述性句子,我倾向于选择一个更接近陈述正在生成的东西而不是描述创建结果的过程的选项.有些人会想要选择其他方式.这些东西总是一个品味问题.

例如:

  • (last (reverse [1 2 3])) 几乎是"逆转1 2 3"
  • (-> [1 2 3] reverse last) 有点像"从1 2 3,反向,采取最后"

我发现第一个更具说明性,在这种情况下会选择它,其他人会选择不同的.


mik*_*era 8

由于它们在功能上是相同的,因此要考虑的主要因素是哪些代码使代码更具可读性和可维护性?

这基本上是一个判断.

-> 在以下情况下通常很有用:

  • 您希望非常清楚地表明您要按顺序执行一系列操作
  • 您可能希望将来插入新步骤.简单 - 只需添加新的线条/表格.
  • 你的步骤有一些额外的参数(这使得很明显这些参数是步骤的一部分)
  • 深深嵌套的函数调用否则会令人困惑(尽管如果这确实是一个问题,还有其他方法可以重构....)

(f (g x)) 样式在其他情况下很有用:

  • 对于数学运算/计算而言,它通常是更自然的风格,因为它更接近于数学函数符号
  • 它更灵活,因为它不要求传递的值必须始终是第一个(with ->)或last(with ->>)参数
  • 它没有必须想象额外参数的精神开销

  • "你可能想在未来插入新的步骤"是一个有趣的不可读性原因.这是一个很好的解释,为什么我在向Ring处理程序添加中间件时看到使用的宏. (2认同)