函数式编程和 J 编程语言 【已翻译100%】(33)

    xiaoxiao2023-07-25  122

    5.2.1 实验

    考虑一个实验,评估工作站上执行fibonacci需要多长时间。先估计fib_work 100,尽管上面已经给出递归过程的定义,但有必要给出一个迭代过程的定义以便于评估。考虑下面的函数定义:

    fib_work_iter =: monad def 'fib_iter 1 1 , y.' fib_iter =: monad define ('a' ; 'b' ; 'count') =. y. if. count = 0 do. b else. fib_iter (1 + a + b) , a , count - 1 end. )

    使用fib_work_iter可以得到与fib_work相同的统计递归次数结果:

    fib_work_iter "0 i. 11 1 1 3 5 9 15 25 41 67 109 177

    下面使用fib_work_iter 计算fib_work 100(精确的)。

    fib_iter 100x 57887932245395525494200

    最终,在工作站上执行一系列fibonacci 函数递归所使用的时间不超过20s。

    使用3500 applications/sec作为估计:

    0 3500 #: 57887932245395525494200x 16539409212970150141 700 0 100 365 24 60 60 #: 16539409212970150141x 5244612256 77 234 16 49 1

    最大结果是 5244612256 个世纪。

    解决这一问题的一种可选的实验性方法是对递归的fibonacci定义进行计时,并从成果时间的倍数中寻找模式.

    [ experiment =: (4 10 $'fibonacci ') ,. ": 4 1 $ 20 21 22 23 fibonacci 20 fibonacci 21 fibonacci 22 fibonacci 23 t =: time "1 experiment t 2.75291 4.42869 7.15818 11.5908 (1 }. t) % _1 }. t 1.60873 1.61632 1.61924

    请注意赔率大概是一样的,这意味着计算fibonacci的时间应该是指数级的。执行下面的计算,作为对事件的一个估计值:

    [ ratio =: (+/ % #) (1 }. t) % _1 }. t 1.61476 0 100 365 24 60 60 rep x: ratio^100 205174677357 86 306 9 14 40

    这一试验性质的方法产生了某种比 205174677357 更大的估计值. 同学们应该警惕任意试验性设计中的某些缺陷.

    5.3 统计

    假设我们有下面这些测试成绩.

    [ scores =: 85 79 63 91 85 69 77 64 78 93 72 66 48 76 81 79 85 79 63 91 85 69 77 64 78 93 72 66 48 76 81 79 /:~scores NB. sort the scores 48 63 64 66 69 72 76 77 78 79 79 81 85 85 91 93

    在干叶图上可以看到一条轴上有观察的单元数字值(页),还有其它轴上的更多重要的数字值(干). 这些可能是从如下这些分数中计算得来的:

    stem =: 10&* @ <. @ %&10 leaf =: 10&| sl_diagram =: ~.@stem ;"0 stem </. leaf sl_diagram /:~scores +--+-----------+ |40|8 | +--+-----------+ |60|3 4 6 9 | +--+-----------+ |70|2 6 7 8 9 9| +--+-----------+ |80|1 5 5 | +--+-----------+ |90|1 3 | +--+-----------+

    一个更加传统的频率表可以由 fr =: +/"1 @ (=/) 的定义得出. 左边的参数是一个频率的范围,而右边的参数是一个观察值的列表.

    4 5 6 7 8 9 fr <. scores 1 0 4 6 3 2

    这个频率表可以用一个使用了内置统计库的柱形图来展示(图 4).

    图 4: 分数频率的柱形图

    pd 'new' pd 'type bar' pd 'xlabel "40" "50" "60" "70" "80" "90"' pd 4 5 6 7 8 9 fr <. scores pd 'show'

    当掷硬币大量的次数,头朝上的数量比上投掷的总数应该会接近0.5. 然而,但是头朝上和底朝上的次数差的绝对值可能会非常巨大. 这可以使用下面的试验来描述, 结果显示在图 5 和 6 中.

    toss =: >: i. n =: 500 NB. 500 coin tosses heads =: +/\?n$2 ratio =: heads % toss diff =: |toss - 2*heads toss =: >: i. n =:10 NB. a small trial toss;ratio +--------------------+------------------------------------------------------------+ |1 2 3 4 5 6 7 8 9 10|1 0.5 0.666667 0.75 0.6 0.666667 0.714286 0.625 0.555556 0.5| +--------------------+------------------------------------------------------------+ toss;diff +--------------------+-------------------+ |1 2 3 4 5 6 7 8 9 10|1 0 1 2 1 2 3 2 1 0| +--------------------+-------------------+

    图 5: 头朝上的比率

    图 6: 头朝上和底朝上的差值

    5.4 Groups我们可以从数论来试验一些基本的想法来证明J的表现力.

    12 +. 5 NB. greatest common divisor 1 27 +. 3 3 1 2 3 4 5 6 7 8 9 10 11 12 +. 12 1 2 3 4 1 6 1 4 3 2 1 12 NB. The numbers <: 12 which are coprime with 12 (1 = 1 2 3 4 5 6 7 8 9 10 11 12 +. 12) # 1 2 3 4 5 6 7 8 9 10 11 12 1 5 7 11 NB. The numbers <: 12 which have common factors with 12 (-. 1 = 1 2 3 4 5 6 7 8 9 10 11 12 +. 12) # 1 2 3 4 5 6 7 8 9 10 11 12 2 3 4 6 8 9 10 12 NB. 8 9 19 have common factors but do not divide 12 ((-. 1 = 1 2 3 4 5 6 7 8 9 10 11 12 +. 12) # 1 2 3 4 5 6 7 8 9 10 11 12) | 12 0 0 0 0 4 3 2 0

    接下来,我们概括这些表达式作为函数totatives和non_totatives。

    totatives =: 3 : 0 p =. >: i. y. (1 = p +. y.) # p ) non_totatives =: 3 : 0 p =. >: i. y. (-. 1 = p +. y.) # p ) totatives 12 1 5 7 11 totatives 28 1 3 5 9 11 13 15 17 19 23 25 27 non_totatives 12 2 3 4 6 8 9 10 12 non_totatives 15 3 5 6 9 10 12 15 divisors =: 3 : 0 p =. non_totatives y. (0 = p | y.) # p ) divisors "0 (12 27 100) 2 3 4 6 12 0 0 0 3 9 27 0 0 0 0 0 2 4 5 10 20 25 50 100

    totatives 函数中n的数量被称为n的欧拉函数. 我们可以定义totient =: # @ totatives. 另一种隐形的定义是phi =: * -.@%@~.&.q:.

    (totient "0) 100 12 40 4 phi 100 12 40 4

    欧拉定理指出给定一个整数 $i$ 与$n$互质, 然后 $modulo (n,i^{totient (n))}) = 1$. 这导致了定义:

    euler =: 4 : 'x. (y.&| @ ^) totient y.' 2 euler 19 1 2 euler 35 1 3 euler 28 1 3 euler 205 1 3 euler 200005 1

    两个 totatives 中 $n$的产物 , $modulo(n)$ 是一个 totative 中 n. 我们可以使用J的表 (/) 副词看到这一点.

    totatives 12 1 5 7 11 12 | 1 5 7 11 */ 1 5 7 11 1 5 7 11 5 1 11 7 7 11 1 5 11 7 5 1

    我们注意到,我们有一组(封闭,单位元,逆,和关联性)。有一个表副词可以用来展示上述的结果。

    table 1 : 0 u.table~ y. : (' ';,.x.),.({.;}.)":y.,x.u./y. ) 12&|@* table totatives 12 +--+-----------+ | | 1 5 7 11| +--+-----------+ | 1| 1 5 7 11| | 5| 5 1 11 7| | 7| 7 11 1 5| |11|11 7 5 1| +--+-----------+

    请注意,12的totatives的另外残基12不形成一个组。

    12&|@+ table 0 , totatives 12 +--+------------+ | | 0 1 5 7 11| +--+------------+ | 0| 0 1 5 7 11| | 1| 1 2 6 8 0| | 5| 5 6 10 0 4| | 7| 7 8 0 2 6| |11|11 0 4 6 10| +--+------------+

    首先要考虑 totatives的值

    p: 6 17 totatives 17 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17&|@* table totatives 17 +--+-----------------------------------------------+ | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16| +--+-----------------------------------------------+ | 1| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16| | 2| 2 4 6 8 10 12 14 16 1 3 5 7 9 11 13 15| | 3| 3 6 9 12 15 1 4 7 10 13 16 2 5 8 11 14| | 4| 4 8 12 16 3 7 11 15 2 6 10 14 1 5 9 13| | 5| 5 10 15 3 8 13 1 6 11 16 4 9 14 2 7 12| | 6| 6 12 1 7 13 2 8 14 3 9 15 4 10 16 5 11| | 7| 7 14 4 11 1 8 15 5 12 2 9 16 6 13 3 10| | 8| 8 16 7 15 6 14 5 13 4 12 3 11 2 10 1 9| | 9| 9 1 10 2 11 3 12 4 13 5 14 6 15 7 16 8| |10|10 3 13 6 16 9 2 12 5 15 8 1 11 4 14 7| |11|11 5 16 10 4 15 9 3 14 8 2 13 7 1 12 6| |12|12 7 2 14 9 4 16 11 6 1 13 8 3 15 10 5| |13|13 9 5 1 14 10 6 2 15 11 7 3 16 12 8 4| |14|14 11 8 5 2 16 13 10 7 4 1 15 12 9 6 3| |15|15 13 11 9 7 5 3 1 16 14 12 10 8 6 4 2| |16|16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1| +--+-----------------------------------------------+ 和 17&|@+ table 0 , totatives 17 +--+--------------------------------------------------+ | | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16| +--+--------------------------------------------------+ | 0| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16| | 1| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 0| | 2| 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 0 1| | 3| 3 4 5 6 7 8 9 10 11 12 13 14 15 16 0 1 2| | 4| 4 5 6 7 8 9 10 11 12 13 14 15 16 0 1 2 3| | 5| 5 6 7 8 9 10 11 12 13 14 15 16 0 1 2 3 4| | 6| 6 7 8 9 10 11 12 13 14 15 16 0 1 2 3 4 5| | 7| 7 8 9 10 11 12 13 14 15 16 0 1 2 3 4 5 6| | 8| 8 9 10 11 12 13 14 15 16 0 1 2 3 4 5 6 7| | 9| 9 10 11 12 13 14 15 16 0 1 2 3 4 5 6 7 8| |10|10 11 12 13 14 15 16 0 1 2 3 4 5 6 7 8 9| |11|11 12 13 14 15 16 0 1 2 3 4 5 6 7 8 9 10| |12|12 13 14 15 16 0 1 2 3 4 5 6 7 8 9 10 11| |13|13 14 15 16 0 1 2 3 4 5 6 7 8 9 10 11 12| |14|14 15 16 0 1 2 3 4 5 6 7 8 9 10 11 12 13| |15|15 16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14| |16|16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15| +--+--------------------------------------------------+

    最后, 考虑到定义powers 来提高totatives到欧拉力.

    powers =: 3 : '(totatives y.) (y.&| @ ^) / i. 1 + totient y.' powers 12 1 1 1 1 1 1 5 1 5 1 1 7 1 7 1 1 11 1 11 1 powers 17 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 4 8 16 15 13 9 1 2 4 8 16 15 13 9 1 1 3 9 10 13 5 15 11 16 14 8 7 4 12 2 6 1 1 4 16 13 1 4 16 13 1 4 16 13 1 4 16 13 1 1 5 8 6 13 14 2 10 16 12 9 11 4 3 15 7 1 1 6 2 12 4 7 8 14 16 11 15 5 13 10 9 3 1 1 7 15 3 4 11 9 12 16 10 2 14 13 6 8 5 1 1 8 13 2 16 9 4 15 1 8 13 2 16 9 4 15 1 1 9 13 15 16 8 4 2 1 9 13 15 16 8 4 2 1 1 10 15 14 4 6 9 5 16 7 2 3 13 11 8 12 1 1 11 2 5 4 10 8 3 16 6 15 12 13 7 9 14 1 1 12 8 11 13 3 2 7 16 5 9 6 4 14 15 10 1 1 13 16 4 1 13 16 4 1 13 16 4 1 13 16 4 1 1 14 9 7 13 12 15 6 16 3 8 10 4 5 2 11 1 1 15 4 9 16 2 13 8 1 15 4 9 16 2 13 8 1 1 16 1 16 1 16 1 16 1 16 1 16 1 16 1 16 1

    5.5 多项式

    在这部分我们将讨论多项式的表示和操作。多项式由它的系数决定,所以我们将多项式表示成一个升序的列表而不是通常的降序。例如,多项式$x^3+2x+5$被表示为了5 2 0 1.

    多项式求值,我们采用如下表示:

    peval =: (#. |.) ~ 5 2 0 1 peval 3 38 p.用来表示多项式求值。 5 2 0 1 p. 3 38

    多项式的加减转化为针对同类项系数的加减:

    psum =: , @ (+/ @ ,: & ,:) pdif =: , @ (-/ @ ,: & ,:) 1 2 psum 1 3 1 2 5 1 3 psum 1 3 1 4 3 1 1 2 pdif 1 3 1 0 _1 _1

    下面我们考虑多项式的积和衍生的多项式。如果我们使用乘积表,同类项的系数在表的斜对角线倾斜。倾斜副词/.可以访问这些对角线上的值。

    pprod =: +/ /. @ (*/) 1 2 pprod 1 3 1 1 5 7 2 pderiv =: 1: }. ] * i. @ # pderiv 1 3 3 1 3 6 3 p.. 1 3 3 1 NB. There is a primitive for derivative 3 6 3

    为易于表示高抽象级函数,可以考虑使用元素是多项式的矩阵。我们称这个为 boxed table。例如,

    [ m =: 2 2 $ 1 2 ; 1 2 1 ; 1 3 3 1 ; 1 4 6 4 1 +-------+---------+ |1 2 |1 2 1 | +-------+---------+ |1 3 3 1|1 4 6 4 1| +-------+---------+ [ n =: 2 3 $ 1 2 3 ; 3 2 1 ; 1 0 1 ; 3 3 3 3 ; _1 _2 3; 3 4 5 +-------+-------+-----+ |1 2 3 |3 2 1 |1 0 1| +-------+-------+-----+ |3 3 3 3|_1 _2 3|3 4 5| +-------+-------+-----+

    下一步,我们将定义一个新版本的psum, pdif和pprod,假设它们的参数是boxed polynomials。

    psumb =: psum &. > pdifb =: pdif &. > pprodb =: pprod &. > 之后我们可以为了这些元素是多项式的矩阵定义一个矩阵乘积: pmp =: psumb / . pprodb m pmp n +---------------------+---------------+------------------+ |4 13 19 18 9 3 |2 4 3 6 3 |4 12 17 16 5 | +---------------------+---------------+------------------+ |4 20 45 61 56 36 15 3|2 5 5 8 14 11 3|4 19 43 60 52 25 5| +---------------------+---------------+------------------+ m pmp m +--------------------+-----------------------+ |2 9 14 10 5 1 |2 10 20 22 15 6 1 | +--------------------+-----------------------+ |2 12 30 42 37 21 7 1|2 13 38 66 75 57 28 8 1| +--------------------+-----------------------+ m pmp^:0 m +-------+---------+ |1 2 |1 2 1 | +-------+---------+ |1 3 3 1|1 4 6 4 1| +-------+---------+ m pmp^:1 m +--------------------+-----------------------+ |2 9 14 10 5 1 |2 10 20 22 15 6 1 | +--------------------+-----------------------+ |2 12 30 42 37 21 7 1|2 13 38 66 75 57 28 8 1| +--------------------+-----------------------+ m pmp^:2 m +----------------------------------------+----------------------------------------------+ |4 29 88 152 176 148 88 36 9 1 |4 31 106 217 304 309 230 123 45 10 1 | +----------------------------------------+----------------------------------------------+ |4 35 137 323 521 613 539 353 168 55 11 1|4 37 158 418 772 1055 1094 864 513 222 66 12 1| +----------------------------------------+----------------------------------------------+ m pmp^:10 x: &. > m +-------------------------------------------------... |1024 29952 424704 3899184 26124316 136500501 5803... +-------------------------------------------------... |1024 31488 471040 4577232 32551980 180983051 8205... +-------------------------------------------------...

    5.6 证明

    Iverson和其它的作者已经使用J语言写了数本关于数学计算的书。其中一个[Ive 1995]在[Gra 1989]使用J语言描述算法和证明。下面的例子是从[Ive 1995]摘录的。

    在定理声明中,一个表达式I和另外一个r相等。我们可以在J语言中使用如下方式表示两者关系:

    t=: l -: r

    这是我必须匹配r,t必须是常函数1所有输入。t有时叫做 同义反复。例如,

    l =: +/ @ i. NB. Sum of integers r =: (] * ] - 1:) % 2:

    如果我们定义n= : ],右边是一个恒等函数,我们可以转化最后一个等式:

    r =: (n * n - 1:) % 2:

    下一步,

    t =: l -: r

    注意实验上呈现的, 不管输入参数为何,t总是1.

    t 1 2 3 4 5 6 7 8 9 1 1 1 1 1 1 1 1 1

    定理证明是从l到r的一系列恒等表达式有序组合。

    l +/ @ i. Definition of l +/ @ |. i. Sum is associative and commutative (|. is reverse) ((+/ @ i.) + (+/ @ |. @ i.)) % 2: Half sum of equal values +/ @ (i. + |. @ i.) % 2: Summation distributes over addition +/ @ (n # n - 1:) % 2: Each term is n -1; there are n terms (n * n - 1:) % 2: Definition of multiplication r Definition of r

    当然,上述证明每个表达式是都是一个简单的程序,而证明是一系列有序验证可以将一个表达式转化成另一个。

    5.7 J可以作为一种数学符号

    Iverson讨论了数学符号在数学计算中的作用。在这篇文章他引用了

    A. N. Whitehead

    通过减轻大脑不必要的工作负担,一种好的数学符号可以把精力集中在更高级的问题上,事实上增加了脑力劳动的强度。

    F. Cajori

    一些诸如 $a^n$, $\sqrt{n}$, $log$ $n$的数学符号仅适用于正整数,如果应用于浮点数、负数和复数,则可能导致致命错误。

    A. de Morgan

    数学符号,就像语言一样,并没有严格的限制而得到广泛使用,它的便利性和规定得到了大多数人的认同。

    其它著名的引用是与J语言的特性有关:

    Friedrich Engels

    在科学中,每一种新的术语都会引发革命性的改变

    Bertrand Russell

    好的符号有一种一种微妙和暗示性的作用,就像一位活生生的老师一般

    A. N. Whitehead, 数学的序言作者

    这里有一个众所周知的错误,重复已出版的书籍和那些名人的演讲,我们应该富有创新精神并且思考我们可以做什么。事实的情况可能与我们想象的不同,文明的进步提升了数学运算的重要性,但我们却没有深入的思考他们

    当然,J语言符号正变得流行,让大脑从繁琐的计算中解放出来,集中精力思考运算背后的事情。它也移除了数学计算的多义性,不要被_3(十减三)和应用程序中的-3混淆。

    一种好的数学符号扩展的例子可以在Cajori的外部乘积的引用中(spelled .)找到。+/ . (矩阵乘积)被表达成一种外部的乘积推导出其它有用的外部乘积诸如+./ . 。

    很遗憾,J语言并没有被计算机科学广泛接受,在数学上接受就更少了。

    最新回复(0)