为什么在显式1上使用(*')的隐式1?

时间:2017-06-09 14:59:00

标签: clojure

clojure docs,功能*'

  

返回nums的乘积。 (*')返回1.支持任意   精确。另见:*

我理解任意精度的用例,如提供的示例中所述:

;; great so it gives the same results as *.
;; not quite check this out
(* 1234567890 9876543210)
;; ArithmeticException integer overflow
(*' 1234567890 9876543210)
;;=> 12193263111263526900N

但是,(*') returns 1似乎没有任何用处,因为您只需指定显式值即可。在提供的相同示例中:

;; there is an implicit 1
(*')
;;=> 1 

;; the implicit 1 comes into play
(*' 6)
;;=> 6

我原以为如果没有定义第二个参数,也许nil可能会有用,但是:

(*' 6 nil)

引发NullPointerException

为什么您使用(*' 6)而非6(*')而不是1

4 个答案:

答案 0 :(得分:1)

**'在这方面是等效的:

首先 - 您如何处理[]中的[x]*个案?

编写的源代码最有意义,AFAIK在数学上是正确的(身份价值等)。

user=> (source *)
(defn *
  "Returns the product of nums. (*) returns 1. Does not auto-promote
  longs, will throw on overflow. See also: *'"
  {:inline (nary-inline 'multiply 'unchecked_multiply)
   :inline-arities >1?
   :added "1.2"}
  ([] 1)
  ([x] (cast Number x))
  ([x y] (. clojure.lang.Numbers (multiply x y)))
  ([x y & more]
     (reduce1 * (* x y) more)))

第二,它使其在手动编写(* 2 4)之外的情况下更加强大。我不会写(*)来表示1

如下所示 - 请参阅位置3和4上的单个元素和emtpy向量。

user=> (map (partial apply *) [[2 2] [2 3 2] [6] []])
(4 12 6 1)

答案 1 :(得分:1)

通常,函数的0-arity对于缩减或应用于列表很有用。例如:

(apply *' (range 5))

答案 2 :(得分:0)

如果您不知道要添加多少项,则默认值(*) => 1可以避免NullPointerException。那就是:

=> (apply * [1 2 3])
6
=> (apply * [3])
3
=> (apply * [])
1
=> (apply * nil)
1
=> (* nil)
nil
=> (*)
1

哇!我很惊讶!即使我尝试了,我也无法强迫NPE!

我仍然认为这种行为提供了一种虚假的安全感。如果我希望将某些数字相乘而一个(或更多)丢失,我宁愿默认通过异常检测错误。事实上,默认情况下,Clojure会通过“有用”并尝试 猜测 来掩盖错误。

<强>更新

我终于产生了一个NPE:

> (* 5 nil)  =>  NullPointerException   clojure.lang.Numbers.ops (Numbers.java:1013)

我发现这更令人惊讶。如果(* nil) => nil,我会打赌(* 5 nil) => nil也是真的。奇怪!

答案 3 :(得分:0)

The multiplicative identity is one.

在代码和clojure方面,birdspider和Alejandro C.都回答了(apply * [])案例,其中(*)等于1确实很有用。

但是,我想指出(*)有用的另一种情况。传递给transduce作为缩减函数时。

transduce docstring:

clojure.core/transduce
[xform f coll]
[xform f init coll]
Added in 1.7
reduce with a transformation of f (xf). If init is not
supplied, (f) will be called to produce it. f should be a reducing
step function that accepts both 1 and 2 arguments, if it accepts
only 2 you can add the arity-1 with 'completing'. Returns the result
of applying (the transformed) xf to init and the first item in coll,
then applying xf to that result and the 2nd item, etc. If coll
contains no items, returns init and f is not called. Note that
certain transforms may inject or skip items.

这里的相关部分是&#34;如果没有提供init,将调用(f)来生成它。&#34;。

所以使用*作为没有init值的rf将使用init值1.这可能就是你想要的。

同样(+) ;=> 0additive identity)和(conj) ;=> []

我认为这是很好地汇总事情的一个简洁例子,因为(*)在传感器出现之前很久才被确定。