了解 Clojure 部分

问题描述 投票:0回答:4

我正在阅读《Clojure 编程》一书。我正在看一个关于部分的示例,它是这样的:

(def only-strings (partial filter string?))

问题是,如果我写下一个函数:

(defn only-strings [x] (filter string? x))

我可以得到同样的结果:

user=> (only-strings [6 3 "hola" 45 54])
("hola")

在这里使用部分有什么好处?或者这个例子只是为了简单地展示他们?有人可以给我一个部分有用的例子吗?非常感谢。

clojure
4个回答
13
投票

在这种情况下,

partial
的好处是您可以修复第一个参数并将其绑定到
string?

这就是

partial
所做的一切。预定义第一个参数,如您在您的示例和 Arthur 的示例中所示。

(def foo (partial + 1 2))

(foo 3 4)    ;; same as (+ 1 2 3 4)
;; > 10

在这种情况下,我将部分前两个参数绑定到

1
2

为什么这会有用?

您可能想在带有两个参数的函数上使用

map
apply
。这将是非常糟糕的,因为 map 和 apply 采用一个函数,而该函数需要一个参数。因此,您可以修复第一个参数并使用
partial
来实现此目的,您将得到一个只需要一个参数的新函数。所以可以和map或者apply一起使用。

在我的一个项目中,我遇到了这种情况。我考虑过使用

partial
或匿名函数。因为我只在一种情况下需要它,所以我使用了 lambda。但如果您多次需要它,那么使用partial 定义一个新函数将非常有用。而且它更具可读性。


11
投票

这最终归结为个人风格问题,任何你用partial做的事情都可以用匿名函数来做,尽管有时

partial
会让它更漂亮。将前几个参数应用于可变参数函数就是一个例子:

user> (def bigger+ (partial + 7 42)) 
#'user/bigger+
user> (bigger+ 1 2)
52

相比:

user> (def bigger+ (fn [& nums] (apply + 7 42 nums)))
#'user/bigger+
user> (bigger+ 1 2)
52

当然,如果您觉得第二个更好的话,您可以自由选择第二个。


3
投票

这是一个例子: (参见DEFN和DEF的区别)

(defn addDomain [domain user] ( str user domain))   
(def buildEmail (partial addDomain "@domain.com"))
(buildEmail "info")  

;; "[email protected]"

2
投票

如果您想要一个关于偏函数如何有用的示例,这里有一个在 Java 世界中非常常见的真实示例,其中 Java 和 Spring 重新创建了偏函数应用程序(尽管方式很笨拙)。

假设你有一个在 Spring 中配置的单例组件 FooService,它配置了单例的范围,并且像 BarDao 一样注入了一些东西。 FooService 有很多业务方法,例如retrieveBarsForSomeReason()。

当应用程序启动时,它会读取实例化 FooService 的应用程序上下文,并将 BarDao 作为实例变量注入其中。随后,应用程序调用 FooService 上的方法,并且这些方法调用 BarDao 上的方法作为其工作的一部分。

所以这不是一个真正的对象,这里没有发生任何面向对象的事情,服务对象上的方法基本上都是函数。注入状态(在此示例中为 BarDao)相当于使用部分绑定对象,这样您就不必在以后的调用中包含它。

© www.soinside.com 2019 - 2024. All rights reserved.