2013-03-21 43 views
2

我正想着如何最终构建*++以及inc,然后在另一个方向上应用相同的模式,使用较低的函数(f a b) b次,您会得到一个超乘法函数的阶梯不断增加的超度。所以我决定尝试编写一个不断增加的超级引擎的无限列表。我想出了这个,这非常接近! :clojure:如果我正在创建操作员楼梯,我如何为操作员定义一般身份?

(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的初始值,以便它在所有一般情况下的案件?

在此先感谢!

+0

我不确定它是否适合你想要达到的目标,但是你能利用'(+)'为0而'(*)'为1的事实吗? – Hugh 2013-03-21 05:06:55

+1

请参阅http://en.wikipedia.org/wiki/Hyperoperation。你必须定义几个基本情况。请注意,将定义直接转换为递归代码会使堆栈即使在较小的值下也会受到影响,即使在较小的值下,迭代实现也需要非常非常长的时间来计算。看到[价值表](http://en.wikipedia.org/wiki/Knuth%27s_up-arrow_notation#Tables_of_values)了解这种增长有多快。 – 2013-03-21 16:43:04

回答

1

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

如果你想定义二元运算符,我认为你只是从+开始,而不是从inc开始,并且像以前一样从其他元素中派生出来。

+0

将inc提升为忽略第一个arg的二元函数似乎有效,我只是不知道如何定义每个级别的基值! – prismofeverything 2013-03-21 06:13:06

0

我想amalloy说的是正确的。这是我的序列版本,从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次,那么对于times而言,第三个参数必须为0,对于exp,第一个参数将为0,而不是对所有这些参数的m,所以不会有统一性。

apply-n-times功能允许我们定义您的运营商的楼梯有点更简洁:

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

这一次给出了相同的结果以前的定义。但我仍然无法再向下一步,并以inc的顺序定义+。如果你看看plus和上面其他功能(times,exp, expexp)之间的区别,我想你可以看到结构是不一样的。