Gimp2.6で使える関数
- プログラム制御 -

 主にプログラム制御で使用する関数を集めました。
 一覧にある関数はとりあえず、使えそうな関数です。
 現在のところ、確認は、2.6.10で行っています。


プログラム制御
let ( let ( [(id expr)]* ) [body]* )---
ローカル変数のバインディング。

最初の()内に(変数名 初期値)の形でローカル変数を記述する。以降のbodyを順次実行。最後のbodyの戻り値がletの戻り値となる。
後述のlet*と異なり、変数が有効になるのは body の実行のときなので、ローカル変数の定義部では互いに変数を引用することができない。

>(let ( (a 1 ) (b 2) ) (+ a b))
3
let ( let procid ( [(id expr)]* ) [body]* )---
ローカル変数のバインディング。

最初の()内に(変数名 初期値)の形でローカル変数を記述する。以降のbodyを順次実行。最後のbodyの戻り値がletの戻り値となる。
後述のlet*と異なり、変数が有効になるのは body の実行のときなので、ローカル変数の定義部では互いに変数を引用することができない。
 procidはbody以降の処理に名前をつけた関数となり、ローカル変数の並びが引数となる。再帰処理に便利。

>(let proc ( (i 10) ) (if (zero? i) 0 (+ i (proc (- i 1)))))
55
let* ( let* ( [(id expr)]* ) [body]* )---
ローカル変数のバインディング

最初の()内に(変数名 初期値)の形でローカル変数を記述する。以降のbodyを順次実行。最後のbodyの戻り値がlet*の戻り値となる。
前述のletと異なり、変数の初期値は記述されたときに代入されるので、変数定義内で以前に定義した変数を引用できる。

>(let* ( (x 1) (y (+ x 2) ) ) (list x y))
(1 3)
letrec ( let* ( [(id expr)]* ) [body]* )---
ローカル変数のバインディング

最初の()内に(変数名 初期値)の形でローカル変数を記述する。以降のbodyを順次実行。最後のbodyの戻り値がletrecの戻り値となる。
 ローカル変数の記述の最初に記述されたすべての変数が#に初期化されてから(存在するけれど引用できない)、ローカル変数の記述が順次実行される。

>(letrec ( (a 1) (b a) ) (list a b))
	error

上の例では、ローカル変数定義内でbにaを入れようとしたところでエラーとなる。

>(letrec ((is-even? (lambda (n) 
                         (or (zero? n) 
                             (is-odd? (- n 1)))))
             (is-odd? (lambda (n) 
                        (and (not (zero? n)) 
                             (is-even? (- n 1)))))) 
      (is-odd? 11)
) 

上の例では、ラムダ式の定義内で互いに変数(ここでは関数ですが)を引用しても変数名は存在しているのでエラーとならない。letrecletに変えるとこの処理はエラーになる。

lambda ( lambda ( [arg]*) [body]*)---
無名関数の定義

最初の()の中に引数を並べる。以降bodyを順に実行し、戻り値は最後の実行の結果。

>( (lambda (x y) (list x y) ) 1 5)
(1 5)

上の例では無名関数を定義し、さらに、それをその場で実行している

lambda ( lambda ( [arg]+ . restid) [body]*)---
無名関数の定義

最初の()の中に引数を並べる。以降bodyを順に実行し、戻り値は最後の実行の結果。

不定個数の引数に対応する。引数を順にargに割り当てた後、残りの引数をリストにして restidに代入してからbody以降を実行する。

>( (lambda (x . y) (list x y) ) 1 2 3)
(1 (2 3))

上の例では無名関数を定義し、さらに、それをその場で実行している。引数yにリスト (2 3) の形で残りの引数が代入されている。

quote ( quote body )---
定数化

bodyをそのまま解釈せず返却する。
「'」での略記法がある。

>(+ 1 2)
3
>(quote (+ 1 2))
(+ 1 2)
>'(+ 1 2)
(+ 1 2)

上の最後の例が略記法。一般にはこちらの形式が用いられる

define ( define id expr)symbol
変数定義

idの変数を作成し、exprを代入する。

>(define alpha 45)
alpha
>alpha
45
define ( define (funcname [arg]*) [body]* )symbol
関数定義

funcnameの関数を定義する。argが引数ならび。関数の戻り値は最後のbodyの値。

>(define (sum a b) (+ a b))
sum
>(sum 1 2)
3
define ( define (funcname [arg]+ . restid) [body]* )symbol
関数定義

funcnameの関数を定義する。関数の戻り値は最後のbodyの値。
不定個数の引数に対応する。実引数はargに順に割り当てられ、残りはリストの形でrestidに割り当てられる。

>(define (myproc a b . u) (list a b u))
myproc
>(myproc 1 2 3 4 5 6 7)
(1 2 (3 4 5 6 7))
if ( if test-expr then-expr else-expr)----
条件判定

test-expr が真ならば、then-expr を実行、偽ならば else-exprを実行する。

>(if (> 5 3 ) "yes" "no")
"yes"
cond ( cond [(test-expr [then-expr]*) ]+ [(else [then-expr)]*])-----
条件判定

条件節 (test-expr [then-expr]*) のtest-exprが真のとき、then-exprを次々に実行し、最後の結果を戻り値とする。
最後の条件節には判定式としてelseを書ける。この条件節以外がすべて成立しない場合の実行式(then-expr)を記述する。

>(define ename "tigers")
ename
>(cond
  ( (string=? ename "giants")  "読売")
  ( (string=? ename "tigers" ) "阪神")
  ( (string=? ename "lions" )  "西武")
  ( else                       "不明")
)
"阪神"

 他の言語で言うと、if ... else if .... else if .... else ... といった使い方に近いですね。

>(cond
  ( (string=? ename "giants")  "読売")
  ( (string=? ename "tigers" ) )
  ( (string=? ename "lions" )  "西武")
  ( else                       "不明")
)
#t

 該当した条件の実行式が無ければ、真(#t)を返します。

>(define ename "whales")
ename
>(cond
  ( (string=? ename "giants")  "読売")
  ( (string=? ename "tigers" ) "阪神")
  ( (string=? ename "lions" )  "西武")
)
()

 上の例では、最後の else がなく、さらに、一致もしないので、突き抜けてしまい、結果として、'() が戻ります。(#fが戻れば使いやすかったのに!)

and ( and [expr]+)-----
論理積

exprを先頭から順に評価し、偽(#f)になったところで評価を打ち切る(戻り値は#f)。すべてが成立する場合は最後の式の結果を返す。
 C言語ならば && に相当します。処理を打ち切るというのは、不成立になった式の後ろはすべて評価(実行)されないということです。式に副作用(戻り値以外に影響を与える)があるならば、考慮すべき重大な点です。

>(define myvalue 10)
myvalue
>(and (> myvalue 5 ) (> myvalue 8) (> myvalue 10 ) (> myvalue 20))
#f

 三番目の式(> myvalue 10)が成立しないのでここで打ち切り、#fが返されます。

>(define myvalue 10)
myvalue
>(and (begin (print "1st") (> myvalue 5 ))
     (begin (print "2nd") (> myvalue 8) )
     (begin (print "3rd") (> myvalue 10 ))
     (begin (print "4th") (> myvalue 20))
)
"1st"
"2nd"
"3rd"
#f

 副作用(print)があると、上の例で途中打ち切りがはっきりわかります。(beginは、引数を評価して最後の値を返す関数です)

or ( or [expr]+)----
論理和

exprを先頭から順に実行し、偽(#f)にならなかったところで処理を打ち切る。このときの戻り値は打ち切ったexprが返す値。すべてが偽の場合は、偽(#f)を返す。
and と同様に打ち切りがあるので、副作用は考慮するべきです。

>(define myvalue 10)
myvalue
>(or (begin (print "1st") (= myvalue 5 ))
     (begin (print "2nd") (= myvalue 8) )
     (begin (print "3rd") (= myvalue 10 ))
     (begin (print "4th") (= myvalue 20))
)
"1st"
"2nd"
"3rd"
#t

 3番目の式が成立したところで打ち切りをしています。

case ( case val-expr [( ( [data]+) [then-expr]*)]+ [(else [then-expr]* )])---
条件判断

条件節の data ひとつでもval-exprと一致するとその条件節のthen-exprを実行し、最後のthen-exprの結果を返す。条件節は先頭から順に試される。すべてが不一致な場合、( else ... )を書けばそのときの実行式を指定できる。
条件節が成立したのにthen_exprが書いてなければ '()を返します。
dataは、数値や論理値、文字列、文字などのいわゆる定数を書くほうが安全です(シンボルを書いたら飛んでしまった)。
C言語の switch に似ている働きをします。

>(case 15
  ( (1 5 7)     "1st" )
  ( (15 19)     "2nd" )
  ( ( 2 4 6)    "3rd"  )
  ( ( 1 3 8)    "4th"  )
  ( else        "else" )
)
"2nd"
begin ( begin [expr]+)---
順実行

exprを順番に評価し、最後のexprを戻り値とする。ifなど、ひとつの式しか書けない場合に、複数式を書くために用いる。

>(define a 0)
a
>(define b 0)
b
>(begin
  (set! a 10)
  (set! b 15)
  (+ a b)
)
25
when ( when test-expr [expr]+)-----
条件判断(真ならば実行)

test-exprが偽(#f)のとき、何もしない('()を返すだけ )。それ以外では expr を順に評価し、最後の結果を返す。
成立時の条件だけ書ける if のようなものですが、expr をずらずらと書けるので begin のお世話にならないのがうれしい。

>(when #t (print 1) "abc")
1
"abc"
>(when #f (print 1) "abc")
()
unless ( unless test-expr [expr]+ )---
条件判断(偽ならば実行)

test-exprが偽(#f)でないとき、何もしない。それ以外では expr を順に評価し、最後の結果を返す。

不成立時の条件だけ書ける if のようなもの。
>(unless #t (print 1) "abc")
()
>(unless #f (print 1) "abc")
1
"abc"
set! ( set! id expr )---
代入

シンボル id に expr の値を代入する。代入の前にシンボルは存在していなければなりません。
代入した値を返却します。

>(define alpha "")
alpha
>(set! alpha 1.01)
1.01
do ( do ( [(id init-expr step-expr)]+ ) (stop-expr [finish-expr]+ ) [expr]+)----
繰り返し

stop-exprが偽(#f)の間、exprを繰り返し実行する。stop-exprが偽(#f)以外になるとfinish-exprを実行し、最後の式の値を返す。
ループ制御のための変数定義が行える。繰り返しの前に、変数(id)をinit-exprで初期化し、それぞれの繰り返しの最後で変数に step-expr が代入される。
 簡単に無限ループに陥るので大変です。

>(define i 100)
i
>(do ( (i 0 (+ i 1)) ) ( (> i 10 ) "end" ) (print i)  )
0
1
2
3
4
5
6
7
8
9
10
"end"
>i
100

 (i 0 (+ i 1)) ) がループ変数の記述です。ループ変数は i 、初期値が 0 、ループの終わりに i に代入されるのが (+ i 1)。ここでは i が 1 ずつ増加します。
 ( (> i 10 ) "end" ) が終了判定。ループの頭で検定((> i 10))され、偽(#f)以外になったとき、終了式("end")を返します。ここでは、i が増加して11になったとき初めて(> i 10)が真になり、"end"を返します。
 この例ではループの中身は、 (print i) のみです。
ループ変数の値はループの外側では、元の値に戻っていることに注目。ループ変数はローカル変数風に働きます。

quasiquote ( quasiquote datum )---
準定数

quoteのように、(例外を除いて)引数をそのまま評価しないで値とする。略記法では「`」を引数の前に付けて書く。
例外は、中で書かれる unquoteunquote-splicing。この二つの関数だけは評価される(実際に有効なのはその引数の評価)。
unquoteは引数を評価して返す。
unquote-splicingは引数を評価し、その要素を上位のリストの要素となるように返す。

>(quasiquote (a b c))
(a b c)
>`(a b c)
(a b c)

 quoteと同じで、引数を丸ごと返却しています。通常は上の二番目の「`」を使った略記法を使います。

>`(a (unquote (+ 2 5) ) c)
(a 7 c)

 unquoteを使うと要素の一部を評価して差し込めます。2番目の要素は (+ 2 5) の結果の 7 となります。

>`(a (unquote-splicing (list (+ 2 5) "zap") ) c)
(a 7 "zap" c)

 unquote-splicingも同様ですが、引数部分の返す値がリストの場合、その要素を上位のリストに組み込みます。上の例では (list (+ 2 5) "zap") の戻り値は ( 7 "zap" ) なので、要素 7 と 要素 "zap" が上位のリストに組み込まれています。
unquote-splicingの引数が返す値がリストで無い場合には、上位のリストには何も組み込まれないようです。

unquote ( unquote expr)---
quasiquoteの中で評価を実行

quasiquoteを参照のこと

unquote-splicing ( unquote-splicing )---
quasiquoteの中で評価を実行、要素を上位のリストの要素として返す

quasiquoteを参照のこと

eval ( eval expr)---
実行評価

exprの値をプログラムとして実行評価する。
プログラム自体をプログラムが生成して実行させる場合に便利。

>(eval '(+ 1 2))
3

 '(+ 1 2)というリストを強制的に評価しています。

load ( load filenamestring)---
プログラムの読み込み。

filenameはパス名。カレントパスがわからないので、絶対パスで記述する方が確か。
プログラムの読み込みだが、実際は、ファイルを実行する(中にdefineで関数が定義されていれば関数を追加することになる)。

procedure? ( procedure? proc)boolean
関数か?

引数が実行可能なオブジェクトなら #t 、そうでなければ #f を返す

>(procedure? list)
#t
>(procedure? 1)
#f
apply ( apply proc [v]* lst)
関数の引数にリストの要素を割り当てて実行

proc に、v と lst から作るリストの要素を引数として割り当て実行する。戻り値は proc の戻り値。
作成するリストの要素は、リスト lstの前に、vを順次入れたもの。
最も一般的な使い方では、v は使わない。

>(apply list '(a b c))
(a b c)
>(apply string-append "神奈川" '("県庁" "所在" "地"))
"神奈川県庁所在地"
call-with-current-continuation ( call-with-current-continuation proc )--
継続を作る。

「継続」を作り、引数の関数に与える。戻り値は、継続、または、引数の関数が戻す値。
引数の関数は、一つの引数をとり、その引数は「継続」関数。 「継続」関数を呼び出すと、「継続」を作った call-with-current-continuation の次へ制御を戻す。「継続」関数の引数がcall-with-current-continuationの値となる。
call-with-current-continuationの名称が長いので、略記として、call/cc が用意されている。。

>(define (a x) (+ 1 2))
a
>(call/cc a)
3

 上の例は、単純に引数の関数の戻り値を call/cc の戻り値にしている。

>(define (a ret) (begin (print "first") (ret "breaker") (print "tail")))
a
> (begin (print "begin") (print (call/cc a)) (print "end"))
"begin"
"first"
"breaker"
"end"
#t

 引数の関数の中で「継続」関数を呼び出すことで、強制中断し、call/cc の外に戻っている。

>(define pp ())
pp
>(define (a ret) (set! pp ret) 0)
a
>(begin (call/cc a) (print "abc"))
"abc"
#t
>(pp)
"abc"
#t

 (begin (call/cc a) (print "abc")) を実行すると、継続が pp に保存される。次の (pp) で継続を実行すると、継続の戻り先に制御が戻り、(print "abc") が実行されている。

この機能は、相当に強力で、通常に使えば、他の言語の中断や、例外処理に相当することができます。C で言えば setjmp ですね。
 「継続」を外に持ち出せば、どこからでも、戻れるわけですから、コルーチンやタスクスイッチングなどを書くこともできそうです。

call/cc ( call proc )--
call-with-current-continuation と同じ。


アルゴ算法堂へ戻る