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

欢迎!请参见关于页面获取有关本站运行方式的一些更多信息。

+4
Clojure

在代码中有一些地方,我需要只定义并使用一次的函数,在定义的地方使用。定义此类函数主要有两种方法,一种是无名函数:
(map #(blepify-with blep (:blop %)) xs)
另一种是高阶函数:
(map (comp (partial blepify-with blep) :blop) xs)

我个人的需求中不使用partial,总是选择匿名函数,因为

  • 匿名函数在调用时会经过变量解引用,这意味着我可以重新定义blepify-with,并且新的定义会自动使用。这极大地帮助了开发过程,并且在生产环境下,直接链接的性能也相当良好;
  • partial通过隐藏函数的arity减少了代码的可读性。明确比隐晦好,Cursive可以立即显示我是否传入了错误的参数数量给函数

我也很少使用comp。除了关于变量解引用的相同理由,它还让我从右向左阅读代码。在提供的简单实例中这没有什么关系,但随着例子的增大,线程宏大大增强了可读性。
我发现comp有用的唯一时机是当函数应用的逆序由数据处理逆序取消时,例如transducers:(comp (filter even?) (map inc))的目的是从左到右读取。即使(map inc)首先调用,此transducer处理的数据首先会通过even?谓词,然后通过inc转换。

我的问题是,我错过的关于partialcomp的还有什么?也许这只是品味问题,我只是还没有习惯它们,它们同样具有可读性,并且不需要再次定义使用位置被高估了?我应该何时首选comppartial而不是匿名函数?

2 个回答

+7

在我看来,你应该优先选择匿名函数,而不是optinal和comp,这是Clojure的惯用解决方案。

我唯一使用comp的时候是组合transducer链。我几乎从不使用partial。

我发现我倾向于将comp和partial重构为fn、letfn或#()语句。结果可能更复杂,但更容易推理和调试。

调试比最初编写代码要难两倍。
因此,如果你尽可能地写聪明代码,你就肯定
根据定义,不够聪明来调试它。

— Kernighan的定律

我的偏好是避免过于聪明或者对代码简洁的关注超过其他考虑因素。

正如别人说的,匿名函数更常见,但我也偶尔使用partial。我很少使用comp,通常只有transducer,因为它使应用顺序更容易理解;否则,我使用threading宏。只有在应用非常简单的情况下,我会使用partial,那时我已经几乎拥有了函数应用的最后一个参数,并且在需要将其用于高阶函数时我会使用它。让它简单直接。
...