複数の式や処理のブロック化、局所変数の宣言、評価順序を制御できる構造をもった特殊フォームである。
(prog (変数名1 変数名2 …) 式(または処理) : 式(または処理) )
第2引数以降の「式(または処理)」の部分で、特殊フォーム return と go を用いることで、評価の流れを変えることができる。
return
特殊フォーム prog 中のみで使える特殊フォーム。return に遭遇すると、prog の処理はその時点で中断され、return の引数として与えられた式の評価値を、prog 全体の評価値として返す。もちろん単体で使うこともできるが、when や unless などと併用することが多い。
(prog (局所変数名1 局所変数名2 …) 処理 : (when 条件 (return 式)) 処理 : )
; (例)
(prog (fip)
(setq fip (inport "address.csv"))
(unless fip ; ファイルを開けなった場合
(println "Couldn't open a file: address.csv")
(return nil)
)
:
)
C言語の break文 に相当する機能を実現できる。
(prog ()
(while ~
~
(when 条件 (return nil)) ; 「break」に相当する
~
)
)
条件が成立すると、while文から脱出する。※ return に指定する式は何でもよい。(上コードの nil は一例である)
C言語の continue文 に相当する機能も実現できる。
(while ~
(prog ()
~
(when 条件 (return nil)) ; 「continue」に相当する
~
)
)
go
特殊フォーム prog 中のみで使える特殊フォーム。処理系が go に遭遇すると、prog の処理はその時点で中断され、go の引数として与えられたラベル(記号)が付された箇所に評価を移す。go の引数として指定できるラベルは、その go を内包している prog 内にあるラベルに限られる。
下の例では、リスト values の要素を順に表示するのに、go を使って繰り返しを実現している。
(prog () printValues ; ラベル (unless values (return nil)) (println (car values)) (setq values (cdr values)) (go printValues) ; printValues の位置に評価を移す )
go を用いるプログラミングスタイルは可読性や保守性が良くない場合が多い。その場合には for、while、foreach などの構造化プログラミングのスタイルで表現すると良いかもしれない。たとえば、上の例の場合、foreach を用いて書くことができる。
(foreach v values (println v) ) (setq values nil) ; 必要なら
何重にも入れ子された while 文の内側から抜け出す場合など、go を使う方が可読性が良い場合もある。