Clojure的让VS多参数数量
思考功能类似,但在Clojure中,这是更好,更performatic,少重于JVMClojure的让VS多参数数量
(defn- on-message
([options ch {:keys [headers delivery-tag]} ^bytes payload ^CompanyProto$Company$Builder company]
(check-id company)
(save company options)
(basic/ack ch delivery-tag))
([options ch ^PersistentHashMap kwargs ^bytes payload]
(on-message options
ch
kwargs
payload
(-> (CompanyProto$Company/newBuilder)
(.mergeFrom payload)))))
或
(defn- on-message [options ch {:keys [headers delivery-tag] ^bytes payload}]
(let [company (-> (CompanyProto$Company/newBuilder) (.mergeFrom payload))]
(check-id company)
(save company options)
(basic/ack ch delivery-tag)))
您的直接问题的答案是,函数调用中没有引入开销,只是因为该函数碰巧具有多个元素。在Clojure中,所有的函数调用都被编译成一个方法调用。调用的确切方法取决于参数的数量 - 就JVM而言,每个元素都被编译为不同的方法。确定调用哪个方法是在编译时进行的,所以在运行时没有开销。
这就是说,嵌套函数调用有一些开销。具体而言,每次调用都会使调用堆栈增长一个常量,直到该调用返回。但是,这种开销很小,在这种情况下不可能对性能产生可衡量的影响。
@ToniVanhala我做了让第一,但朋友说,让坏 ,而不是功能性的(他是一个Erlang的开发者),我在功能 LANGS新......另一件事是他说是奇怪,那个clojure是 没有堆叠
这似乎是真正的问题。所以这是值得解决的。
let
只是一个表达式,它允许我们将值绑定到变量。这些绑定是不可变的。此外,众所周知,let
可以实现为lambda上的宏抽象(或者,在Clojure的词汇表中,fn
)。所以let
肯定没有任何关于它“不起作用”的东西。
Clojure没有堆叠也没有什么“奇怪”或令人费解。 Clojure是一种JVM语言,并且调用堆栈深深嵌入JVM的抽象计算模型中。虽然有办法解决这个问题(例如,continuation-passing风格),但这些方法要么放弃深层JVM互操作性和/或支付性能损失。 Clojure首先是一种务实的语言,这是一种务实的让步。
此外,Clojure(作为一个Lisp)是一个真正的语言框架,您可以用它来伪造您想要的语言。你的语言可能会做出不同的折衷。例如,您的语言可能是"stackless"。或者它可能有first-class continuations(免责声明:我是pulley.cps
的作者)。或者它可能有completely different paradigm(即逻辑vs功能)。但它也可以非常简单。使用Clojure,您可以选择您支付的费用。具有讽刺意味的是,你的朋友是正确的代码不能正常工作。但是,这不是因为let
。相反,几乎所有的东西除了let
不起作用。例如,(save company options)
显然是一个副作用的操作。然而,这并不意味着你的代码是坏的 - 即使是最纯粹的功能程序,在某种程度上,如果它具有任何实际价值,它们也必须与真实世界相互作用。
这是一个完整的答案,谢谢你,我想知道你是否可以展示一些例子,正如我所说我是功能性的新手,我真的想学习它,我不明白如何保存在那里功能... –
@RafaelCustódio,“纯”功能编程编程没有副作用。如果你仔细想想,“保存”/必须是副作用,或者这个调用是完全多余的,应该被消除。原因很简单(但不一定非常明显) - 由'save'返回的值永远不会被使用。因此,对'save'的调用只有在执行一些副作用(例如在数据库中存储某些内容)时才有意义。 (续) –
再次(我不能强调这足够),我不是说你的代码是坏的是任何方式。事实上,我认为它看起来相当合理 - 没有办法可以写入没有副作用的数据库。但它确实意味着你的代码在技术上不是“功能”(从最纯粹的意义上说)。希望有所帮助。 –
如果您在使用Java进行开发互操作,将*warn-on-reflection*
设置为true
。如果有警告,您需要用提示消除它。然后你就可以得到“有代表性的,对JVM不太重的”代码。
P.S.数学计算具有可变性,简单的JVM类型和未检查的溢出是另一回事,如果这是您的情况,您也需要检查这一点。
感谢您的提示,因为我正在使用一些Java类,我会这样做,但是在哪里?在Core.clj中? –
@RafaelCustódio,'(set!* warn-on-reflection * true)'在具有这些功能的源文件中。也可以用'(:gen-class)'来创建这个命名空间。 – fevgenym
感谢@fevgenym –
有没有理由为什么你正在考虑多元化的第一个选项?除非该方法是从其他地方同时使用两个签名调用的,否则第二个(使用绑定)肯定不那么混乱。我相信你也可以在堆栈中保存一个呼叫,这看起来像是一个多层次的呼叫。 –
@ToniVanhala @ToniVanhala我首先做了,但一位朋友说let是坏的并且没有功能(他是一个erlang开发者),我是功能性的新郎......他说的另一件事就是那个clojure很奇怪不是无堆栈 –
[“let”表达式可能被认为是应用于值的lambda抽象](https://en.wikipedia.org/wiki/Let_expression),所以它适合函数式编程。 –