c++ boost::bind vs clojure partial function

c++ boost::bind vs clojure partial function

本文关键字:partial function clojure bind boost c++ vs      更新时间:2023-10-16

C++ Boost bind 库和 Clojure 的部分函数非常相似。例如:

int x = 8;
bind(std::less<int>(), _1, 9)(x);   // x < 9

这类似于clojure的部分函数:

((partial > 9) 8)

不同之处在于,partial只允许绑定前 n 个参数,而 boost::bind 允许占位符指示哪些参数已绑定,哪些参数未绑定。所以boost::bind实际上更通用和有用:

bind(f, _2, _1)(x, y);                 // f(y, x)
bind(g, _1, 9, _1)(x);                 // g(x, 9, x) 

我想知道在 clojure(或 clojure-contrib)中是否有类似于boost::bind的东西?为什么部分没有像boost::bind那样写得更普遍(和有用)?

这是 Clojure 的一个相当常见的问题,更常见的是线程宏 -> 和 ->> 为什么它们也不允许任意占位符。

在我看来,给出的理由在这里也适用:惯用的 Clojure 函数通常分解为适合单独提供第一个或最后一个参数的函数,而不是混合的函数。

换句话说,开发人员通常尝试对函数进行编码,以便它们适合 ->、->> 和/或部分。

给定匿名函数的读取器宏,对于不太惯用的情况,在需要时创建占位符版本相当容易:

#(f %2 %1) ;; bind(f, _2, _1)
#(g % 9 %) ;; bind(g, _1, 9, _1)

就像肖恩说的,partial解决了一个更具体的问题,一般来说,lambdas是惯用的解决方案。也就是说,如果你绝望了,你总是可以自己bind

(defmacro bind
  [bound-function & args]
  (let [; helper function to parse actual argument symbols
        get-symbols (fn [s] (map second s)),
        ; help function to get the placeholder arguments
        get-placeholders (fn [s] (filter first s))
        ; collection of arguments and whether they're placeholders
        bound-args (map (fn [arg]
                        (if (= arg '_)
                          ; for placeholders, generate a new symbol
                          [true (gensym)]
                          ; otherwise, use the provided argument as-is
                          [false arg]))
                      args)]
    `(fn [~@(get-symbols (get-placeholders bound-args))]
       (~bound-function ~@(get-symbols bound-args)))))

其用途如下:

((bind > 9 _) 8) ; true
((bind > _ _) 9 8 ) ; true

有一个瑞士箭头库,允许各种其他参数线程/绑定方案。但是,其中有很多选项,优化函数的参数以最好地使用 -> 和 ->> 宏的首选解决方案,如果不可能,请使用匿名函数作为最简单的通用解决方案。