[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7. 関数定義

7.1 関数定義について  
7.2 関数  
7.3 マクロ  
7.4 最適化  
7.5 関数定義に関する諸定義  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.1 関数定義について


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.2 関数

- MACSYMAで関数を定義する時は、:=演算子を用いる。

例えば、
 
F(X):=SIN(X)
で関数Fを定義する。LAMBDA式を使って(LISPの)無名関数を生成しても良い。

 
例えば、

lambda([i,j], ... )
 
F(I,J):=BLOCK([], ... );
の代りに使う事が可能である。

 
例えば、

MAP(LAMBDA([I],I+1),L)
はリストLの各項に1を加えたリストを返す。
 
(*訳者注:

上記の例の実行結果を以下に示す。

(C1) map(lambda([i],i+1),[1,2,3]);

(D1)                              [2, 3, 4]

この様にlambda([i],i+1)で引数iに1を加える無名関数を構築し、それをmap関数で
リスト[1,2,3]に作用させている。lambda関数に関してはLISPの本を参照されたい。

*)

引数の個数が可変な関数では、最後の引数を特別な引数リストとして割当てて定義して も良い。

 
(C8) f([u]):=u;
(C9) f(1,2,3,4);
(D9) 				 [1, 2, 3, 4]
(C11) f(a,b,[u]):=[a,b,u];
(C12) f(1,2,3,4,5,6);
(D12) 			     [1, 2, [3, 4, 5, 6]]

関数の右手側は式である。それ故、式の列が欲しければ次の様にする。

 
f(x):=(expr1,expr2,....,exprn);
すると、exprnの値が関数によって返される値となる。

 
(* 訳者注:

(C1) f(x):=(2*x,3*x,10,x^3);
(D1)                      f(x) := (2 x, 3 x, 10, x )
(C2) f(1);
(D2)                                   1
(C3) f(10);
(D3)                                 1000
(C4) f(x);
                                       3
(D4)                                  x
(C5) f(2*x);
                                        3
(D5)                                 8 x
(C6) 
(C6) f(0);
(D6)                                   0
(C7) f(x):=(1,2,3,4,5,6,7,8,9,10);
(D7)                f(x) := (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
(C8) f(a);
(D8)                                  10
(C9) f([1,2,3,4]);
(D9)                                  10
(C10) map(f,[1,2,3,4]);
(D10)                          [10, 10, 10, 10]

*)
関数内部のある式からの返却値が欲しければ、blockreturn を用いなければならない。
 
block([],expr1,...,if(a>10) then return(a),...exprn)
これはそれ自身が式であって、関数定義でもある右側が実行される。ここで returnによる値の返却は最後の式よりも先に処理されても良い。

BLOCKの中の最初にある[]は、変数リストや[a:3,b,c:[]と云った変数 の指定を含んでいて良い。ここで、[a:3,b,c:[]の3個の変数abcBLOCKの内部か、BLOCKの内部から呼び出された 内部関数でプログラムが実行される限り、大域変数の値を参照せずにそれらの特定の 値を持つ。

これは動的束縛と呼ばれる。何故なら、BLOCKの開始から終了まで変数が存在し 続ける為である。

一旦、BLOCKから値を戻したり、外に放り出しても、(任意の)変数の古い値は 保たれている。この方法で値を守る事は確実に良い考えである。そのBLOCK変数の 割当ては並行して行われる事に注意する。これは、上のc:acの値は、 そのBLOCKに入った時点で値aとなっている。しかし、以前はaが束縛 されていた。そこで、以下の様に実行する。

 
block([a:a],expr1,... a:a+3,...exprn)
この例ではaの外部の値が変更される事を妨げるが、その値が何であるかを 参照する事が可能である。そして、代入の右辺は任意の束縛が生じる前に属する文脈 (context)内で評価される。

BLOCK([x],..を使うと、Xをそれ自身の値とみなし、あたかも新規に立ち上げ たMAXIMAセッションに入った状態になる。

関数の実際の引数はBLOCKの中の変数と丁度同じ方法で扱われる。

 
つまり、
f(x):=(expr1,...exprn);
と
f(1);
では、あたかも
 
block([x:1],expr1,...exprn)
を実行したかの様な、それらの式評価に対する文脈と似た文脈を持つ。

関数内部では、定義の右辺が実行時に計算される時、defineと可能であれば buildqを用いれば便利である。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.3 マクロ

関数: BUILDQ([varlist],expression);

EXPRESSIONは任意の単一のMAXIMAの式で、VARLISTは<原子><原子>:<値>の書式の要素のリスト。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.3.1 語義

<varlist>の中の<値>は左から右に評価される(構文<原子>は<原子>:<原子>と同値 である)。そして、これらの変数は並行して<expression>に代入される。任意の<原子> が単一の引数として<expression>の内側で特別な形式SPLICE(つまり、 SPLICE(<原子>)に対して現われるのであれば、<原子>と関連する値はMACSYMAリスト でなければならず、代入の代りに<expression>に結合(SPLICE)されねばならない。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.3.2 簡易化

BUILDQの引数は代入が実行される迄、簡易化を防ぐ必要がある。これは' を利用する事で行える。

buildqはさっさと関数を構成するのに便利である。MAXIMAが強力な事の 一つに、問題を解く手助けとなる他の関数を定義する関数が作られる事である。以下、 級数の解法に関して、再帰的な関数の構成について議論する。この関数内部での関数 定義は通常defineを用いる。このdefineはその引数を評価する。 幾つかの例が以下のspliceに含まれている。

関数: SPLICE (atom)
これはbuildqでリストの生成を行う為に用いる。BUILDQとの組合せで引数リストの 作成が簡易になる。

 
例えば、

MPRINT([X]) ::= BUILDQ([U : x],
  if (debuglevel > 3) then print(splice(u)));

とし、

呼出しが以下であれば、
 
MPRINT("matrix is ",MAT,"with length",LENGTH(MAT))

これは次の行と同値である。

 
IF DEBUGLEVEL > 3
  THEN PRINT("matrix is ",MAT,"with length",
              LENGTH(MAT))

次の非自明な例は変数の値とそれらの名前を表示するものである。

 
MSHOW(A,B,C) 
は値をプログラムの中で行として表示する事が出来る様に

 
PRINT('A,"=",A,",",'B,"=",B,", and",'C,"=",C)
となる。

 
(C101) foo(x,y,z):=mshow(x,y,z);
(C102) foo(1,2,3);
X = 1 , Y = 2 , and Z = 3

実際のmshowの定義は以下の通りである。BUILDQがどうやって'uがその変数名 を与える様に'引用された'構造を組み立てるかに注意せよ。マクロに含まれるRESULT は、そのマクロに対して代入と評価されるコードの一片である事に注意せよ。

 
MSHOW([lis])::=BLOCK([ans:[],N:LENGTH(lis)],
	   FOR i THRU N DO
	       (ans:APPEND(ans,
			   BUILDQ([u:lis[i]],
				  ['u,"=",u])),
		IF i < N
		    THEN ans
		    :APPEND(ans,
			    IF i < N-1 THEN [","]
			        ELSE [", and"])),
	   BUILDQ([U:ans],PRINT(SPLICE(u))))

Spliceは代数的操作に引数を与えたりする。

 
(C108) BUILDQ([A:'[B,C,D]],+SPLICE(A));
(D108) D+C+B

代入後にのみ簡易化がどのよう行なわれるかを注意せよ。最初の場合では、 spliceに対して適応されるのは+で、第二の場合は*である。 そこで、論理的にsplice(a)+sploce(A)2*spliceで置換えられると 思うかもしれないが、如何なる簡易化もbuildqでは実行されない。SPLICEが代数で 何を実行するかを理解する為に、A+B+Cの様な公式操作がMAXIMA内部で +(A,B,C)と非常に類似しており、積についても類似している事を理解して いなければならない。それ故、*(2,B,C,D2*B*C*Dとなる。

 
(C114) BUILDQ([A:'[B,C,D]],+SPLICE(A));
(D114) D+C+B
 
(C111) BUILDQ([A:'[B,C,D]],SPLICE(A)+SPLICE(A));
(D111) 2*D+2*C+2*B
しかし、
(C112) BUILDQ([A:'[B,C,D]],2*SPLICE(A));
(D112) 2*B*C*D

最後に、BUILDQは再帰的な関数の構築で計り知れない価値がある。ここで、ある微分 方程式を級数を用いた方法で解くプログラムがあり、その方程式で次の再帰的な関係 を構築する必要があったとする。
 
F[N]:=(-((N^2-2*N+1)*F[N-1]+F[N-2]+F[N-3])/(N^2-N))
そして、プログラムの内部で直接これを実行しなければならないとする。 ここで、expandを実際に付け足したければ、
 
F[N]:=EXPAND((-((N^2-2*N+1)*F[N-1]+F[N-2]+F[N-3])
  /(N^2-N)));
とするが、このコードをどの様にして構築するのだろう。先ず、expandが 動作するのが、その関数が動作する各時点であって、その以前でない事を望めば、
 
kill(f),
val:(-((n^2-2*n+1)*f[n-1]+f[n-2]+f[n-3])/(n^2-n)),
define(f[n],buildq([u:val],expand(u))),

(*訳者注:
この例ではMaximaのプログラムに入れる事を考えているので、末尾が";"では無い。
*)
とすると希望する処理を行う。これは便利だろう。と云うのも、EXPAND付きで実行 れば、
 
(C28) f[6];
(D28) -AA1/8-13*AA0/180
となるが、簡易化しないままだと第6項でさえもこうなる:
 
(C25) f[6];
(D25) (5*(-4*(-3*(-2*(AA1+AA0)+AA1+AA0)/2
	    -(AA1+AA0)/2+AA1)
	/3
	-(-2*(AA1+AA0)+AA1+AA0)/6+(-AA1-AA0)/2)
      /4
      +(-3*(-2*(AA1+AA0)+AA1+AA0)/2
       -(AA1+AA0)/2+AA1)
       /12-(2*(AA1+AA0)-AA1-AA0)/6)
      /30
各段階で簡易化を実行しなければ、この式は即座に複雑になる。そこで、簡易化は その定義の一部でなければならない。この様にBUILDQはその形式を構築する のに便利である。

 
(*訳者注:

上記のfを決める為には勿論f[0],f[1],f[2]が必要。ここでは上記の例に沿って
macsymaに式を入れて行く。尚、f[0]:0,f[1]:aa0,f[2]:aa1とする。

(C1) val:(-((n^2-2*n+1)*f[n-1]+f[n-2]+f[n-3])/(n^2-n));
                       2
                   - (n  - 2 n + 1) f      - f      - f
                                     n - 1    n - 2    n - 3
(D1)               -----------------------------------------
                                     2
                                    n  - n
(C2) define(f[n],buildq([u:val],expand(u)));
                             2
                         - (n  - 2 n + 1) f      - f      - f
                                           n - 1    n - 2    n - 3
(D2)        f  := EXPAND(-----------------------------------------)
             n                             2
                                          n  - n
(C3) f[0]:0;f[1]:aa0;f[2]:aa1;
(D3)                                   0
(C4) 
(D4)                                  aa0
(C5) 
(D5)                                  aa1
(C6) f[6];
                                  3 aa1   aa0
(D6)                              ----- + ---
                                   10     40

この例では簡易化された答が返却される。それに対し、define内部のbuildqでexpandを
抜いた場合を以下に示す。

(C1)  val:(-((n^2-2*n+1)*f[n-1]+f[n-2]+f[n-3])/(n^2-n));
                       2
                   - (n  - 2 n + 1) f      - f      - f
                                     n - 1    n - 2    n - 3
(D1)               -----------------------------------------
                                     2
                                    n  - n
(C2) define(f[n],buildq([u:val],u));
                          2
                      - (n  - 2 n + 1) f      - f      - f
                                        n - 1    n - 2    n - 3
(D2)            f  := -----------------------------------------
                 n                      2
                                       n  - n
(C3) f[0]:0;f[1]:aa0;f[2]:aa1;
(D3)                                   0
(C4) 
(D4)                                  aa0
(C5) 
(D5)                                  aa1
(C6) f[6];
                              3 (- 4 aa1 - aa0)
                   4 (- aa1 - ----------------- - aa0)
                                      2                  - 4 aa1 - aa0
        5 (- aa1 - ----------------------------------- - -------------)
                                    3                          6
(D6) (- ---------------------------------------------------------------
                                       4

                                    3 (- 4 aa1 - aa0)
                            - aa1 - ----------------- - aa0
                                            2                 - 4 aa1 - aa0
                          - ------------------------------- - -------------)/30
                                          12                        6

展開されない為に複雑なままである。

*)


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.4 最適化

TRANSLATEを用いてMACSYMAでコードの生成を行う時、時間の節約が可能で、便利な 幾つかの技法がある。デモはDEMO("optimu.dem")を実行せよ。 特に、TRANSL;OPTIMU FASLからの関数FLOATDEFUNKは関数定義を数学風の式から生成 するが、それを(OPTIMIZEで)最適化し、正確にCOMPILEを行うのに必要なMODE_DECLARE によるモードの宣言を行う(勿論、これは手動で実行しなければならない)。デモは MACSYMAを新規に起動した状態のみで動作する。

 
(* 訳者注:
optimu.demはmaxima-5.6に含まれていない様である。
*)


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.5 関数定義に関する諸定義

関数: APPLY (function, list)
関数functionを引数リストに適用した結果を与える。関数を適用する前に、その関数 の引数を計算したい時に便利である。例えば、Lがリスト[1,5,-10.2,4,3]なら、 APPLY(MIN,L)は-10.2となる。関数の呼出しで、それらの引数が評価されておらず、 それらの評価を希望する場合もAPPLYは便利である。例えば、FILESPECがリスト [TEST,CASE]であれば、APPLY(CLOSEFILE,FILESPEC)はCLOSEFILE(TEST,CASE)と同値で ある。一般的に、APPLYで評価させる為には、'を最初の引数の先頭に置くべきである。 幾つかの原子変数が、ある関数と同じ名前を持っていれば、関数としてではなく、 その変数値が利用される。何故なら、APPLYそれ自身が第二の引数と同様に 第一の引数をも評価する為である。

 
(*  訳者注:

先頭に'を付けると云う意味は、名詞型を評価するのが本来と云う事。

(C17) apply('expand,[(x+1)^2]);
                                  2
(D17)                            x  + 2 x + 1
(C18) apply('apply,['expand,[(x+1)^2]]);
                                  2
(D18)                            x  + 2 x + 1
(C19) 

この様にする理由は、以下の馬鹿馬鹿しい例から明確になるだろう。

(C30) neko(x):=2*x;
(D30)                           neko(x) := 2 x
(C31) neko:-128;
(D31)                                - 128
(C32) neko(10);
(D32)                                 20
(C33) apply('neko,[20]);
(D33)                                 40
(C34) appply(neko,[20]);
(D34)                         appply(- 128, [20])

この例では、nekoを関数として定義したが、同時に、変数として-128を束縛している。
その為、applyでは'が無ければ変数として評価されてしまっている。

*)

関数: BINDTEST (ai)
計算でaiが無束縛のままで用いられていれば、エラーを出す。

関数: BLOCK ([v1,...,vk], statement1,...,statementj)
MAXSYMAのBLOCKはFORTRANのSUBROUTINE、ALGOLやPL/IのPROCEDUREに多少類似したもの である。BLOCKは文の集合体であるが、BLOCK内部の文にラベル付けが行え、"ダミー" 変数にBLOCKの局所的な値の割当てを行う事が出来る。viはBLOCKでの局所変数であり、 statementiは任意のMACSYMAの式である。もし、局所的な変数が無ければ、そのリスト を省略しても良い。BLOCKはこれらの局所変数を同じ名前を持つBLOCKの外側の変数 (つまり、BLOCKにとっては大域変数)との衝突を避ける為に用いる。この場合、BLOCK に入ると、大域変数がスタックに保存され、BLOCKが実行されている間はそれに アクセス出来ない。そして、局所変数はそれ自体を評価する様に無束縛である。 BLOCK内部でそれらに任意の値を束縛しても良いが、BLOCK文が終了した時に、保存さ れた値がそれらの変数に再度設定される。これらの局所変数向けにBLOCK内部で生成 された値は失われる。ここで、BLOCK内部で用いられているものの、BLOCKの局所変数 リストに無い変数は、BLOCK文の外側で用いられる変数と同じものとなる。

例えば、ARRAY(完全な配列を除く),FUNCTION,DEPENDENCIES,ATVALUE,MATCHDECLARE, ATOMGRAD, CONSTANTとNONSCALARと云った、VALUE(値)を除く、局所的な属性の保存と 復旧が望ましければ、関数LOCALはBLOCK内部で変数の名前となる引数を用いなければ ならない。

BLOCKの値は、最後の文の値やBLOCKから明示的に抜ける為に用いられる関数RETURNに 渡された引数の値である。関数GOは制御をGOの引数でラベル付けされたBLOCK内の文に 移す事に用いる。文のラベル付けは、BLOCKで原子引数を別の文として、その文の 先頭に置く事で行う。例えば、BLOCK([X],X:1,LOOP,X:X+1,...,GO(LOOP),...)の様に する。GOの引数はBLOCK内部に現われるラベル名でなければならない。ここで、GOを 含まないBLOCK中のラベルにGOで移動する事は出来ない。BLOCKは通常、関数定義の 右側に現われるが、他の場所に置く事も同様に可能である。

関数: BREAK (arg1, ...)
引数評価と表示を行い、(MACSYMA-BREAK)にて利用者がその環境を調べ、変更する事が 出来る様にする。そして、EXIT;を入力すると計算が再開される。Control-A(^A)で MACSYMA-BREAKに任意の点から会話的に入る事が可能で、EXIT;で計算を続行する。 Control-XはMACSYMA-BREAK内部で、本体側の処理を終了せずに、局所的に計算を止め る事に用いても良い。

マクロ: BUILDQ
- DESCRIBE(MACROS);を見よ。

関数: CATCH (exp1,...,expn)
一つ一つ、その引数を評価する。expiの構造がTHROW(arg)形式の式の評価を導けば、 CATCHの値はTHROW(arg)の値となる。

この"非局所的回帰"(non-local return)は、任意の(構文の)入れ子の深さを通過して 最も近いTHROWに対応するCATCHに行く。THROWに対応するCATCHがなければならず、 そうでなければエラーとなる。もし、expiの評価が何らのTHROWの評価に至らなかった 場合、CATCHの値はexpnの値となる。
 
(C1) G(L):=CATCH(MAP(LAMBDA([X],
       IF X<0 THEN THROW(X) ELSE F(X)),L));
(C2) G([1,2,3,7]);
(D2)                     [F(1), F(2), F(3), F(7)]
(C3) G([1,2,-3,7]);
(D3)                                - 3

この関数Gは、Lが非負の数のみであればLの各要素に対するFのリストを返す。 それ以外では、GはLの最初の負の要素を"捉え(catch)"、それを"放擲する(throw)"。

関数: COMPFILE ([filespec], f1, f2, ..., fn)
関数fiの翻訳(compile)を行い、ファイル"filespec"に書き込む。詳しくは、 COMPILE関数を見よ。

変数: COMPGRIND
デフォルト値:[FALSE] TRUEであれば、COMPILEによる関数定義の出力が整形表示 される。

関数: COMPILE (f)
COMPILE命令はMACSYMAの便利な機能である。これはMacsyma関数をlispに変換する COMPFILE関数の呼出、そのCOMPFILE関数で生成されたファイルに対するlisp コンパイラの呼出、それから、FASLファイルとして知られるコンパイラ出力の Macsymaへの読込を実行する。コンパイラが出力した註釈を含む出力ファイルの ある共通のエラーに対する検証も行う。より詳細はPRINTFILE(MCOMPI,DOC,MAXDOC); を実行せよ。

関数: COMPILE_LISP_FILE ("input filename")
オプションの第二の引数を持ち、
 
TRANSLATE_FILE("filename").
と組合せて使う事が出来る。 簡便の為に、
 
Compile_and_load(FILENAME):=
    LOAD(COMPILE_LISP_FILE(TRANSLATE_FILE(FILENAME)[2]))[2]);
と定義しても良い。

これらのファイル操作の命令ではCOMPILE、COMPFILEとTRANSLATE SAVEの組合せで利用 すると良い。

関数: DEFINE (f(x1, ...), body)
f(x1,...):="bodyと同値となるが、関数内部で用いられていれば、同値となるのは 実行時であり、それを含む関数定義の時点では無い。

関数: DEFINE_VARIABLE (name,default-binding,mode,optional-documentation)
MACSYMA環境に大域変数を導入する。これは利用者記述のパッケージ向けで、それらは しばしば、(TRANSLATE等で)変換や(COMPILE等で)翻訳されたものである。

ここで、
 
DEFINE_VARIABLE(FOO,TRUE,BOOLEAN);
は以下の事を実行する:

可能な"モード"のリストについてはDESCRIBE(MODE_DECLARE);を見よ。 オプションの第四の引数は文書文字列である。TRANSLATE_FILEが文書文字列を含む パッケージに用いられた時、第二のファイルはマニュアル、用例ファイルや (例えば)DESCRIBE向けに適した書式の文書文字列を含むLISPのファイル出力である。 ANY以外のモードでDEFINE_VARIABLEとされた任意の変数でVALUE_CHECK属性を与える 事が可能であり、この属性は、利用者がその変数に設定しようとする値に関して 呼出された1引数の関数である。

 
PUT('G5,LAMBDA([U],IF U#'G5 THEN ERROR("Don't set G5")),
       'VALUE_CHECK);

DEFINE_VARIABLE(G5,'G5,ANY_CHECK, "this ain't supposed to be set by anyone but me.")を用いると、ANYY_CHECKはANYと同じモードであるが、DEFINE_VARIABLEを 最適化せずに、割当てた属性のままとなる事を意味する。

関数: DISPFUN (f1, f2, ...)
利用者定義の関数f1,f2,...の定義を、これらの関数が定義された時に使われている ものと同じ名前で、関連する関数、下添字された関数や定数の下添字を持つ関数で 表示する。

DISPFUN(ALL)は全ての下添字された関数で定数の下添字を持つもの除いたFUNCTIONS とARRAYSリストで与えられる利用者定義関数を表示する。例えば、利用者が関数F(X) を定義していれば、DISPFUN(F);で、その定義内容を表示する。

変数: FUNCTIONS
デフォルト値:[] - 全ての利用者定義関数(f(x):=...で設定されたもの)のリスト。

 
(* 訳者注:

(C2) neko(x):=block(local(a),a:abs(x),if x<1 then a:x,return(a));
(D2) neko(x) := BLOCK(LOCAL(a), a : ABS(x), IF x < 1 THEN a : x, RETURN(a))
(C3) f(x):=x^2+1;
                                         2
(D3)                            f(x) := x  + 1
(C4) mike:1;
(D4)                                   1
(C5) functions;
(D5)                            [f(x), neko(x)]
(C6) 

この様に定義した関数のみがリストで表示されている。
*)

関数: FUNDEF (functionname)
"functionname"に対応する関数の定義を返す。FUNDEF(fnname);はDISPFUN(fnname);と 似ているが、FUNDEFはDISPLAYを呼出さない。

 
(* 訳者注:

(C8) fundef(neko);
(D8) neko(x) := BLOCK(LOCAL(a), a : ABS(x), IF x < 1 THEN a : x, RETURN(a))
(C9) dispfun(neko);
(E9) neko(x) := BLOCK(LOCAL(a), a : ABS(x), IF x < 1 THEN a : x, RETURN(a))

(D9)                                 DONE
(C10) 

この様に、fundefでは内容がD行で表示されるが、dispfunではE行で表示されている。

*)

関数: FUNMAKE (name,[arg1,...,argn])
関数nameを呼出さずに、name(arg1,...,argn)を返す。

 
(* 訳者注:

要するに、こんな事。

(C14) funmake(f,[x,y,z]);
(D14)                             f(x, y, z)
(C15) funmake(neko,[x,y,z]);
(D15)                            neko(x, y, z)
(C16) funmake(expand,[128,"うちのタマ知りませんか?"]);
(D16)                      EXPAND(128, うちのタマ知りませんか?)
(C17) a;
(D17)                                  a
(C18) funmake(a,[1,2,3]);
(D18)                             a(1, 2, 3)
(C19) a:10;
(D19)                                 10
(C20) funmake(a,[1,2,3]);
Bad first argument to FUNMAKE: 10
 -- an error.  Quitting.  To debug this try DEBUGMODE(TRUE);)
(C21) funmake('a,[1,2,3]);
(D21)                             a(1, 2, 3)

これらの例で示す様に、引数が出鱈目でも評価をしないので何も問題は無い。
又、関数名である必要は無いが、値が束縛されている時は内部で評価されるので、
この場合は、'を先頭に付けて名詞型とする必要がある。

*)

関数: LOCAL (v1, v2, ...)
この関数が使われる文中で、変数v1,v2,...を全ての属性に対して局所的なものにする。 LOCALはBLOCK、関数定義の本体、LAMBDA式、又はEV関数でのみ使え、各々で一度だけ 利用可能である。LOCALは文脈(Context)から独立している。

変数: MACROEXPANSION
デフォルト値:[FALSE] - マクロの効率性に影響を与える進んだ機能を制御する。

可能な設定は:

変数: MODE_CHECKP
デフォルト値:[TRUE] - TRUEであれば、MODE_DECLAREは定値変数のモードを検査する。

変数: MODE_CHECK_ERRORP
デフォルト値:[FALSE] - TRUEであれば、MODE_DECLAREはエラーを呼ぶ。

変数: MODE_CHECK_WARNP
デフォルト値:[TRUE] - TRUEであれば、モードエラーが記載される。

関数: MODE_DECLARE (y1, mode1, y2, mode2, ...)
MODEDECLAREが同義のものである。MODE_DECLAREは変数のモードと後に続く変換や COMPILEで翻訳する関数宣言で用いる。その引数は変数yiとBOOLEAN,FIXNUM,NUMBER, RATIONALやFLOATの中のどれか1つのモードとの対で構成されている。各yiは変数の リストで、その全ての変数はmodeiを持つと宣言されたものである。もし、yiが配列 で、参照される配列の全ての要素が値を持っていたとしても、配列の範囲を最初に 宣言する時には、
 
ARRAY(yi, dim1, dim2, ...)
よりも、ARRAY(yi, COMPLETE, dim1, dim2, ...)を用いなければならない。

もし、配列の全ての要素がFIXNUM(FLOAT)のモードであれば、COMPLETEの代りに FIXNUM(FLOAT)を用いる。又、配列の全ての要素が同じモード、例えばmであれば、

 
MODE_DECLARE(COMPLETEARRAY(yi),m))
を効率的な変換の為に使わなければならない。更に、配列を用いた数値コードは予想 される配列の大きさを宣言する事でより速く動作させる事が可能である。

例えば:

 
MODE_DECLARE(COMPLETEARRAY(A[10,10]),FLOAT)
は、10x10の浮動小数の配列向けである。加えて、関数の結果のモードを FUNCTION(F1,F2,...)を引数として宣言しても良い。ここで、F1,F2,...は関数名 である。

その式の例は、

 
MODE_DECLARE([FUNCTION(F1,F2,...),X],FIXNUM,Q,
                                COMPLETEARRAY(Q),FLOAT)
で、XとF1,F2,...によって返される値がsingle-word長の整数である事と、Qが浮動点 小数配列である事を宣言する。

MODE_DECLAREは関数定義の内部か大域変数に対するトップレベルのどちらかを用いる。 TRANSLATE(変換)とCOMPULE(翻訳)でのMODE_DECLAREの幾つかの例は PRINTFILE(MCOMPI,DOC,MAXDOC);を実行せよ。

関数: MODE_IDENTITY (arg1,arg2)
MODE_DECLAREと用いられる特殊な形式で、宣言すべきマクロ、例えば、FLONUMの リストのリストや、他のデータオブジェクトの混合物である。MODE_IDENTITYの最初の 引数はプリミティブの値のモード名で、MODE_DECLAREに与えられるもの(つまり、 [FLOAT,FIXNUM,NUMBER,LIST,ANY])で、第二の引数は式で、評価されて、 MODE_IDENTITYの値として返されるものである。しかし、もし、返された値が最初の 引数で宣言されたモードに合致しないものであれば、エラーや警告が出力される。 重要な事は、MACSYMAからLISPへの変換で決められた式のMODEが最初の引数として与え られ、第二の引数に続く全てのものから独立している事である。 例えば、X:3.3; MODE_IDENTITY(FIXNUM,X);はエラーとなる。

MODE_IDENTITY(FLONUM,X)は3.3を返す。 これは色々な使い方があり、例えば、FIRST(L)が数(NUMBER)を返す事が判っていれば、 MODE_IDENTITY(NUMBER,FIRST(L))と書いても良いだろう。しかし、より効率的な方法 は、新しいプリミティブ、
 
FIRSTNUMB(X)::=BUILDQ([X],MODE_IDENTITY(NUMBER,X));
を定義して、数のリストの最初の元を取る時は何時もFIRSTNUMBを用いる事である。

変数: TRANSBIND
デフォルト値:[FALSE] - TRUEであれば、局所的な文脈での大域的な宣言を削除する。 これをMACSYMAのコードからLISPにTRANSLATEで変換する関数の表立った助変数となる 変数に対して作用する。

変数: TRANSCOMPILE
デフォルト値:[FALSE] - TRUEであれば、TRANSLATEは可能なCOMPILE命令に必要な宣言 を生成する。COMPILE命令はTRANSCOMPILE:TRUEを用いる。

関数: TRANSLATE (f1, f2, ...)
利用者定義関数f1,f2,...をMACSYMA言語からLISPに変換する(つまり、それらをLISP のEXPRにする)。この結果として、それらが呼出された時に処理速度の向上が得られる。 予め読込まれるLISP変換器にmacsymaを用いたmacsyma版が今ではある。それはDDT レベルで、:TM(TranslateMacsyma向け)と入力すれば使える。例えば、 :TM GJC;TMTEST>の様にファイル名が与えられると、関数TRANSLATE_FILEに そのファイルを引渡し、利用者はそれ以上の操作をせずに処理が実行される。 ファイル名が与えられていなければ、:TMは通常のMACSYMAの"(C1)"行を出す。 尚、第二の名前が"TM"の利用者初期ファイルが存在していれば読込まれる。これを 貴方のMACSYMA初期化ファイルにリンクしても良い。変換される関数は、より効率的な コードの生成の為に可能ならばその先頭にMODE_DECLAREの呼出しを入れるべきである。

 
例えば:
F(X1,X2,...):=BLOCK([v1,v2,...],
        MODE_DECLARE(v1,mode1,v2,mode2,...),...)

とし、ここで、X1,X2,...は関数の引数で、v1,v2,...は局所変数である。変換された 関数の名前は、SAVEDEFがFALSE(以下を見よ)であればFUNCTIONリストから削除され、 PROPSリストに追加される。関数は虫取りが完遂されるまで変換すべきではない。 更に、式は簡易化されていると仮定されている。そうでなければ、動作は正しい ものの、最適化されていないコードが生成されてしまう。それ故、利用者はSIMP スイッチをFALSEに設定して変換されるべき式の簡易化を禁じてはならない。

ファイル指定の引数をTRANSLATEに与える事で、ファイルに保管された関数の変換が 可能である。これは[fn1,fn2,DSK,dir]の形式のリストで、ここで、fn1,fn2は MACSYMA関数のファイル名、dirはファイルのディレクトリ名である。TRANSLATEに よって返される結果はTRANSLATEで変換された関数の名前のリストである。ファイル 変換の場合、そのリストに対応する変換結果のLISPのコードを含んでいる第一と 第二の新しいファイル名のリストになる。これはfn1 LISPで、 ディスクディレクトリのdirにある。LISPのコードはMACYSMAにてLOADFILE関数を 用いると読込める。

関数: TRANSLATE_FILE (file)
MACSYMA言語のファイルをLISPのファイルに変換する。一つか二つの引数を取る。 最初の引数はMACSYMAファイルの名前で、オプションの第二の引数は生成すべきLISP ファイル名である。第二の引数は第一引数に、TRISPのデフォルト値である TR_OUTPUT_FILEの値を第二ファイル名のデフォルト値として与える。 例えば、TRANSLATE_FILE("test.mc")); は"test.mc"を"test.LISP"に変換する。 更に、生成されるものには変換器が出力した様々な重要性の度合を持った警告 メッセージのファイルがある。第二ファイル名は常にUNLISPである。このファイルは 変数を含み、それには変換されたコードでのバグ追跡の為の情報がある。 TRスイッチ(TRANSLATEに為)のリストを得る為にAPROPOS(TR_)を実行する。纏めると、 TRANSLATE_FILE("foo.mc"), LOADFILE("foo.LISP")はBATCH("foo.mc")にある制限 (例えば、"や%を用いる)を付けたものと"="(同値)である。

変数: TRANSRUN
デフォルト値:[TRUE] - FALSEであれば、TRANSLATEで変換されたものではなく、 元のMacsymaの関数(それらが存在していれば)が実行される

変数: TR_ARRAY_AS_REF
デフォルト値: [TRUE] - TRUEであれば、実行コードは配列として変数の値を用いる。

変数: TR_BOUND_FUNCTION_APPLYP
デフォルト値:[TRUE] - 関数として用いようとする変数に値が設定されていれば警告 を出す。

変数: TR_FILE_TTY_MESSAGESP
デフォルト値:[FALSE] - TRANSLATE_FILEがファイルの変換を行う間に生成された メッセージをTTYに送るかどうかを決める。FALSE(デフォルト値)であれば、ファイル のTRANSLATEによる変換に関するメッセージはUNLISPファイルのみに挿入される。 TRUEであれば、メッセージはTTYに送られ、UNLISPファイルにも挿入される。

変数: TR_FLOAT_CAN_BRANCH_COMPLEX
デフォルト値:[TRUE] - arc関数が複素数値を返しても良いかどうかを宣言する。 arc関数はSQRT,LOG, ACOS等である。例えば、TRUEにしている時、たとえ、XがFLOAT モードであったとしても、ACOS(X)はANYモードとなる。FALSEにしている時は、Xが FLOATモードであり、その時に限って、ACOS(X)はFLOATモードとなる。

変数: TR_FUNCTION_CALL_DEFAULT
デフォルト値:[GENERAL] -FALSEであれば、中断してMEVALを呼出し、EXPRであれば、 引数固定のLISP関数を仮定する。デフォルト値のGENERALはMEXPRSとMLEXPRSに対しては 良いコードを与えるが、MACROSに対してはそうではない。GENERALでは、変数束縛が COMPILEで翻訳されたコードの中で正しい事を保証する。GENERALモードで、F(X)を変換 する時に、Fが束縛変数であれば、APPLY(F,[X])を意味していると仮定し、適切な警告 と共にその様に変換する。これをオフにする必要性は無い。デフォルト設定で、何等 の警告メッセージが無ければ、TRANSLATEで変換されたり、COMPILEで翻訳されたコード には元のMACSYMA関数と完全な互換性がある事を意味する。

変数: TR_GEN_TAGS
デフォルト値:[FALSE] - TRUEであれば、TRANSLATE_FILEはテキストエディタで用いる TAGSファイルを生成する。

変数: TR_NUMER
デフォルト値:[FALSE] - TRUEであれば、数の属性はそれらによって与えられた原子に 対して用いられる。例えば、%PI。

変数: TR_OPTIMIZE_MAX_LOOP
デフォルト値[100] - 考えられる形式で変換器のマクロ展開と最適化工程ループの 最大回数。これはMACRO展開エラーを捉える為であり、非中断の最適化属性でもある。

変数: TR_OUTPUT_FILE_DEFAULT
デフォルト値:[TRLISP] - これはLISPに変換した出力の第二ファイル名に使われる。

変数: TR_PREDICATE_BRAIN_DAMAGE
デフォルト値:[FALSE] - TRUEであれば、COMPAREパッケージに対する インターフェイスへの出力可能な複数の評価。

変数: TR_SEMICOMPILE
デフォルト値:[FALSE] - TRUEであれば、TRANSLATE_FILEとCOMPILEの出力形式は拡張 されたマクロだが、LISPコンパイラで機械コードに翻訳されたものではない。

変数: TR_STATE_VARS
デフォルト値:
 
[TRANSCOMPILE, TR_SEMICOMPILE,
TR_WARN_UNDECLARED, TR_WARN_MEVAL, TR_WARN_FEXPR, TR_WARN_MODE,
TR_WARN_UNDEFINED_VARIABLE, TR_FUNCTION_CALL_DEFAULT,
 TR_ARRAY_AS_REF,TR_NUMER]
変換された出力形式に影響を与えるスイッチのリスト。この情報は、システム管理者 にとって変換器のデバッグを行う時に便利である。変換された生成物と与えられた 状況で生成されなければならない物を比較する事で、バグを追跡する事が可能である。

変数: TR_TRUE_NAME_OF_FILE_BEING_TRANSLATED
初期値:[FALSE] TRANSLATE_FILEで変換された最新のファイルの本当の名前を引用符で 囲んだ文字列書式が束縛される。

変数: TR_VERSION
- 変換器のバージョン

関数: TR_WARNINGS_GET ()
変換中に変換器が出力する警告のリストを表示する。

変数: TR_WARN_BAD_FUNCTION_CALLS
デフォルト値:[TRUE] - 変換時に不適切な宣言が行われた為、関数の呼出しが生じた 場合に警告する。

変数: TR_WARN_FEXPR
デフォルト値:[COMPFILE] - 任意のFEXPRが与えられていれば警告する。 FEXPRは通常変換されたコード内の出力であってはならず、全ての文法的に正しい特殊 なプログラム書式に変換される。

変数: TR_WARN_MEVAL
デフォルト値:[COMPFILE] - 関数MEVALが呼び出されると警告する。もし、MEVALが 呼出されると、その変換で問題点を指定する。

変数: TR_WARN_MODE
デフォルト値:[ALL] - 変数がそれらのモードに対して適切でない値が指定されていれ ば警告する。

変数: TR_WARN_UNDECLARED
デフォルト値:[COMPILE] - 未宣言の変数に関する警告をTTYに送るべき時を決める。

変数: TR_WARN_UNDEFINED_VARIABLE
デフォルト値: [ALL] - 未宣言の大域変数があれば警告する。

変数: TR_WINDY
デフォルト値:[TRUE] - "助けになる"註釈とプログラムのヒントを生成する。

変数: UNDECLAREDWARN
デフォルト値:[COMPFILE] - 変換器のスイッチ。 四個の関連する設定がある:

 
設定        | 動作
------------------------------------------------------------
FALSE       | 警告を表示しない
COMPFILE    | COMPFILEであれば警告する
TRANSLATE   | TRANSLATEやTRANSLATE:TRUEであれば警告する
ALL         | COMPFILEやTRANSLATEであれば警告する
------------------------------------------------------------

MODE_DECLARE(<変数>,ANY)を実行して変数が一般のMACSYMAの変数である事を宣言 する(つまり、FLOAT、又はFIXNUMである事に限定されない)。COMPILEで翻訳される べきコードの中の変数を宣言する特別な動作は全て無効にしなければならない。

関数: COMPILE_FILE (filename ,&optional-outfile)
MACSYMAコードを含むファイル名(filename)を取って、これをLISPに変換し、結果を COMPILEで翻訳する。四個のファイル(元のファイル、変換ファイル、変換に関する 註釈とCOMPILEで翻訳されたコード)を返す。

関数: DECLARE_TRANSLATED (FN1,FN2..)
MacsymaコードのファイルをLISPに変換する時、そのファイルの中のどの関数が TRANSLATEで変換された関数であり、或いはCOMPILEで翻訳された関数として呼出さ れるべきか、そして、どれがMACSYMA関数であり、又、未定義のものであるかを知る 事は変換器にとって重要な事である。ファイルの先頭にこの宣言を置くと、ある記号 がたとえLISP関数の値を持っていなかったとしても、呼出された時にそれを持つ事を 教える。(MFUNCTION-CALL fn arg1 arg2.. )が生成されるのは、fnがLISP関数に変換 されるべきものであるかを変換器が知らない時である。


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Hiroshi Yokota on September, 16 2002 using texi2html