add(complex(a,b), complex(c,d)) = complex(a+c, b+d)
mul(complex(a,b), complex(a,b)) = complex(a c - b d, a d + b c)
im(complex(a,b)) = a
re(complex(a,b)) = b
abs(complex(a,b)) = sqr(a^2 + b^2)
複素数型の演算の定義。addは演算子'+'の関数としての別名で、
これを定義すれば+演算子が使えるようになる。mulについても同様。
ones(n)=map(x->1, #n)
長さnの1がつまった配列を作る関数を定義する。
#nの#は0から始まってn-1までの配列をつくり出す演算子。
dp(x,y) = map(z->z y, x)
長さnの配列と長さmの配列を作って、
要素がそれぞれの積であるn*mの二次元配列を作る関数を定義する。
image(dp(#20,#20)/400)
imageは二次元配列をとってimage型を返す関数。
read-eval-printループの中では画面にそのままimageが現われる。
n=50
x = dp(ones(n), darr(2#n/n-1))
y = dp(2#n/n-1, darr(ones(n)))
repeat(fn, n, x) = if(n==0) x else fn repeat(fn, n-1, x)
関数のオペレーションをくり返す関数。
c = complex(x,y)
fm = z->z*z+c
t = repeat(fm,9,c)
image(abs t<2)
マンデルブロ集合を描くプログラム。
近々、より数学に近い t = fm^9 c という表記を可能にする予定。
以下が実行時のスクリーンキャプチャ。
ごちゃごちゃ出ているのは、デバグ用に構文木の内部表現を出したもの。
gcd(m, n) = if(m==0) n else gcd(mod(n,m), m)
ユークリッドの互除法により最大公約数を求めるプログラム
fib(n)=if(n==0) 1
else if(n==1) 1
else fib(n-1)+fib(n-2)
フィボナッチ数列のn番目を求めるプログラム。
このままでは、とても遅い。
define Memo(fn){
mem=assoc()
x -> if( inassoc(mem, x) ) return mem[x]
else mem[x] = fn(x)
}
関数を受け取り、その関数をmemoizeにした関数を返す高階関数。
fib = Memo(fib)
こうやって、fibを改良するととても速くなる。
syntax for((a, b, c) sts){
a
while(b){
sts
c
}
}
今の所cipherにはwhileだけでfor文はないが
このようにマクロで定義すれば、ほぼC風の文法が使えるようになる。
つまりCの文法と同等の能力がcipherマクロにはある。
N=5
for(i=0, i< N, i=i+1){
for(j=1, j<=N, j=j+1){
if(gcd(i,j)==1 & i< j) print {i,j}
}
}
結城さんの「既約分数パズル」をわざとimperativeでかつドン臭い
アルゴリズムでやってみたところ。
define sb(n, a, b) {
m = a+b
if(m[1] > n) return
sb(n, a, m)
print m
sb(n, m, b)
}
define sbt(n){
print( {0,1} )
sb(n, {0,1}, {1,1})
print( {1,1} )
}
sbt 7
imperativeでエレガントなアルゴリズムで解いてみたところ。
define sb(n, a, b, s) {
m = a+b
if(m[1] > n) s
else sb(n, a, m, cons(m, sb(n, m, b, s)))
}
sblist(n) = cons({0,1}, sb(n, {0,1}, {1,1}, {{1,1}}))
エレガントなアルゴリズムを関数的にしてみたところ。
syntax enumerate((i, I) ex) {
merge(map(i->ex, I))
}
rr(N) = enumerate(p,#N) enumerate(q, 1+#N) (if(gcd(p,q)==1 & p< q) {{{p,q}}} else {{}})
関数的でbrute forceな方法。
最上 嗣生
|
Home |
e-mailはmogami@yugiri.bnf.brain.riken.go.jpヘ