clojure:如果我正在创建一个操作员楼梯,我该如何定义操作员的身份?

时间:2013-03-21 04:38:23

标签: clojure operators

我在考虑如何从*中构建+,最后从+中构建inc,然后在另一个方向上应用相同的模式使用较低的函数(f a b) b次,你会得到一个不断增加的超音速的超乘函数的阶梯。所以我决定尝试编写一个不断增加的超级运算符的无限列表。我想出了这个,非常接近! :

(defn operator-staircase
  []
  (iterate
   (fn [f]
     (fn [a b]
       (loop [bottom b
              result a]
         (if (>= 0 bottom)
           result
           (recur
            (dec bottom)
            (f a result))))))
   (fn [a b]
     (inc b))))

(def ops (operator-staircase))
((nth ops 0) 3 5) ;; -->  6  (inc is arity one so it must ignore one of the args?)
((nth ops 1) 3 5) ;; -->  8  (correct addition)
((nth ops 2) 3 5) ;; -->  18  (oops, one off!  otherwise correctly multiplies.)  
                                Basically implements (fn [a b] (* a (inc b)))
((nth ops 3) 3 5) ;; ---->  1092 (Wow)

我唯一不知道怎么做的是以一般方式定义初始result!我只是把它a因为它有用,但是例如它必须是0,而乘法应该是1.

如何在上面的循环中定义result的初始值,以便它在所有情况下都能以一般方式工作?

提前致谢!

2 个答案:

答案 0 :(得分:1)

我认为如果你想从inc开始,你只能有意义地定义一元运算符。所以第0步是“加一”;第一步是“N次:加1”,基本上是#(+ % %);第二步是“N次:加N”,即#(* % %);第三步是“N次:乘以N”,即#(pow % %) ......等等。

如果你想定义二元运算符,我认为你只是从+开始而不是从inc开始,并像你一样推导出其余运算符。

答案 1 :(得分:0)

我认为合金说的是正确的。这是我的序列版本,从amalloy建议的+开始。与您的另一个区别是,我的计数器变量从(dec b)而不是b开始。原因是如果你想到例如a*3为“a自身添加3次”,这仍然只是添加功能的2个应用(即a+a+a)。通过这些更改,我得到了我认为您期待的结果。

(def operator-staircase
  (iterate
    (fn [f]
      (fn [a b]
        (loop [acc a
               counter (dec b)]
        (if (>= 0 counter)
          acc
          (recur (f a acc) (dec counter))))))
    +))

;; in comments, * is multiplication, ** is exponentiation (chained multiplication), *** is chained exponentiation, etc
(println ((nth operator-staircase 0) 3 2)) ; 5 = 3+2 = (inc (inc 3)))
(println ((nth operator-staircase 1) 3 2)) ; 6 = 3*2 = 3+3
(println ((nth operator-staircase 2) 3 2)) ; 9 = 3**2 = 3*3 = 3+3+3
(println ((nth operator-staircase 3) 3 2)) ; 27 = 3***2 = 3**3 = 3*3*3
;(println ((nth operator-staircase 4) 3 2)) ; takes too long to compute, but presumably 7625597484987 = 3****2 = 3***3 = 3**(3**3)
(println ((nth operator-staircase 0) 2 3)) ; 5 = 2+3 = (inc (inc (inc 2)))
(println ((nth operator-staircase 1) 2 3)) ; 6 = 2*3 = 2+2+2
(println ((nth operator-staircase 2) 2 3)) ; 8 = 2**3 = 2*2*2 = 2+2+2+2
(println ((nth operator-staircase 3) 2 3)) ; 16 = 2***3 = 2**(2**2) = 2*2*2*2

让我们稍微打破前几次迭代:

(defn apply-n-times [f n arg]
  (if (= n 0) arg
    (recur f (dec n) (f arg))))

(defn plus [m n]
  (apply-n-times inc n m))

(defn times [m n]
  (apply-n-times (partial plus m) (dec n) m))

(defn exp [m n]
  (apply-n-times (partial times m) (dec n) m))

(defn expexp [m n]
  (apply-n-times (partial exp m) (dec n) m))

同样,有必要应用(dec n)次,而不是n。如果我应用了n次,则第三个arg对于times必须为0,对于exp必须为1,而不是m所有,所以会没有统一性。

apply-n-times功能允许我们更简洁地定义您的操作员楼梯:

(def os2
  (iterate
    (fn [f]
      (fn [m n]
        (apply-n-times (partial f m) (dec n) m)))
    +))

这个结果与前面的定义相同。但我仍然无法向前迈进一步,并以+的方式在同一序列中定义inc。如果您查看plus与上述其他函数(timesexpexpexp)之间的差异,我认为您可以看到结构不一样。< / p>