11. Lisp(for Common Lisp)とフローチャート¶
ここでは、具体的にLispとフローチャートの対応関係について書きます。ソースコードとフローチャートを順番に書くことで、ソースコードの処理の流れを明確にします。
Common LispはCLISPと、xyzzyの二つで動作を確認しています。
Contents
11.1. goto文¶
gotoは指定した個所に処理をジャンプさせることができます。
Lispでは gotoはないが tagbodyと goを使うことで類似の処理を記述できます。
gotoの一般的な動作については VBAの goto を参照してください。
(tagbody タグ名または命令文... )
(tagbody
タグ名
命令文
(go タグ名) ;go は tagbodyの中で使う。
)
タグ名 | 処理のジャンプ先 |
命令文 | 処理全般 |
go のフローチャート
goの例
lisp_go.lisp
(tagbody
(go B)
A
(print "01")
B
(print "02")
(go D)
C
(print "03")
D)
;02を表示
goto文例のフローチャート
11.2. 変数宣言¶
変数の宣言は letを使います。
(let ((変数1 初期値1)(変数2 初期値2)...) 命令文...)
変数 | ローカル変数を宣言 |
初期値 | 変数の初期値 |
命令文 | 変数のスコープ内の処理 |
letのフローチャート
letの例
(let ((x 1) (y 2))
(print (+ x y))) ;3を表示
例のフローチャート
11.2.1. 変数の値の変更¶
変数の値を変更する。
(setq 変数 値)
変数 | 変数を指定 |
値 | 変数に代入する値 |
setqのフローチャート
setqの例
(let ((i 0))
(setq i 2)
(print i)) ;2を表示
setqのフローチャート
11.3. 三項の条件演算子¶
Lispではifを利用します。
三項の条件演算子の構文
(if 条件 Then部 Else部)
条件 | 真偽を返す式 |
Then部 | 条件が真のとき実行される |
Else部 | 条件が偽のとき実行される |
※Else部を省略することができ、このときはnilが返します。
三項の条件演算子の例
lisp_conditional_op.lisp
(let ((sum 10)(str ""))
(setq str
(if (>= sum 60) "合格" "不合格" ))
(print str))
三項の条件演算子フローチャート
11.4. if...else文¶
ifについては 3項演算子の章を参照 してください。
ここでは、類似の機能の condについて説明します。
condは elseifが使える ifと考えればよいです。
(cond (条件式1 命令文1 ... )
(条件式2 命令文2 ... )
...
(t 命令文3 ... ))
条件式 | 以下の式を実行する条件 |
命令文 | 条件で実行される命令 |
t | 条件に当てはまらないときに実行される(else節) |
condのフローチャート
condの例
lisp_if_else.lisp
(let ((age 16) (result ""))
(cond ((>= age 70) (setq result "心の欲する所に従って矩を踰えず"))
((>= age 60) (setq result "耳順う"))
((>= age 50) (setq result "天命を知る"))
((>= age 40) (setq result "惑わず"))
((>= age 30) (setq result "立つ"))
((>= age 15) (setq result "学に志す"))
(t (setq result "無し")))
(print result)) ;"学に志す" を表示する
if..elseの例のフローチャート
11.5. switch文¶
Lispではswitch文には caseを使います。
case の書式
(case 式
( 値1 命令文1 ... )
( 値2 命令文2 ... )
・・・・・
( t 命令文3 ... ))
式 | 値を返す式 |
値 | 式で返された値と同じ場合命令文を実行する |
命令文 | 実行される処理 |
t | 式が値で指定された以外場合ここになる。(else、default部) |
case のフローチャート
caseの例
lisp_switch.lisp
(let ((month 2) (result ""))
(case month
( 1 (setq result "January"))
( 2 (setq result "February"))
( 3 (setq result "March"))
( 4 (setq result "April"))
( 5 (setq result "May"))
( 6 (setq result "June"))
( 7 (setq result "July"))
( 8 (setq result "August"))
( 9 (setq result "September"))
(10 (setq result "October"))
(11 (setq result "November"))
(12 (setq result "December")))
(print result)) ;Februaryを表示
case例のフローチャート
11.6. for文¶
Lisp では for はありませんが類似の処理に do があります。
※参考までに通常の for 文については Javaのfor文を参照 してください。
do の書式
(do ((変数宣言 初期値 再初期化)...) (終了判定 終了処理...)
命令文...)
変数宣言 | カウンター用変数を宣言している |
初期値 | 宣言した変数に設定する初期値 |
終了判定 | ループ処理を終了する条件を書く |
終了処理 | ループ終了時に実行される処理。省略可能。 |
再初期化式 | 宣言した変数再設定する |
命令文 | ループで処理する本体 |
do のフローチャート
11.6.1. do を for として使う¶
do を forとして使う場合には 終了判定に not をつけて継続判定とし、終了処理を省略した以下のような書式にします。
(do ((変数宣言 初期値 再初期化)...) ((not 継続判定))
命令文...)
do を使った for のフローチャート
1~10の合計を求めるfor文の例
lisp_for.lisp
(let ((sum 0))
(do ((i 1 (+ i 1))) ((not (<= i 10)))
(setq sum (+ sum i)))
(print sum)) ;55を表示
for文例のフローチャート
11.7. for-each文¶
Lispにfor-each文はありませんが、dolist をつかって同様の処理を記載できます。
※for-each文については Javaのfor-each文を参照 してください。
dolistの書式
(dolist (変数 リスト 終了処理) 命令文 ... )
dolistはリストの要素の数だけ、変数に配列の要素を順番に格納しながら処理をを繰り返します。
変数 | ループ内で使う変数を宣言する。変数にはリストの要素が順次、格納される。 |
リスト | 変数に順次格納されるリスト |
終了処理 | ループ終了時に実行される処理。省略可能。 |
命令文 | ループ中の実行される処理 |
dolist のフローチャート
1~10の合計を求める。for-each文の例
lisp_for_each.lisp
(let ((nums '(1 2 3 4 5 6 7 8 9 10)) (sum 0))
(dolist (num nums)
(setq sum (+ sum num)))
(print sum)) ;55を表示
for-each文のフローチャート
11.8. while文¶
while文の構文
(while 継続条件式 命令文... )
継続条件式 | ループを継続する条件式を書く |
命令文 | 継続条件式が真の間、命令文を繰り返し実行する。省略可能。 |
while文のフローチャート
1~10の合計を求める。while文の例
lisp_while.lisp
(let ((i 1) (sum 0))
(while (<= i 10)
(setq sum (+ sum i))
(setq i (+ i 1)))
(print sum))
while文例のフローチャート
11.9. do..while文¶
do-while文の構文
Lispに do-whileはありません。whileと prognを組み合わせて類似の処理を書きます。
while
whileについては前節の whileを参照 してください。
progn
prognは一つしか処理を書けない場所でも、複数の命令文を書くことできます。
(progn 命令文1 命令文2...)
progn のフローチャート
do-while
whileと prognを組み合わせることで do-whileの同等の処理を実現します。
(while (progn 命令文 ... 継続条件))
do-while のフローチャート
1~10の合計を求める。do-while文の例
lisp_do_while.lisp
(let ((i 1) (sum 0))
(while (progn
(setq sum (+ i sum))
(setq i (+ i 1))
(<= i 10)))
(print sum)) ;55を表示
do-while文のフローチャート
11.10. continue文¶
Lispには continue文はないため、goと tagbodyを利用して類似処理の記述します。
※goと tagbodyは前節を 参照 してください。
continueの構文
Lispに continueはないため、goを使って類似の処理を実装します。
(ループ制御
(if 条件 (go continue01))
その後の処理
continue01
)
goを使った continue動作は while、do、dolist などのループ制御の「その後の処理」をスキップさせ、ループ処理を継続させます。
continue文の一般的な動作については Javaのcontinue文を参考 にしてください。
continueのフローチャート
continue文の例
lisp_for_continue.lisp
(let ((sum 0) (i 1))
(while (<= i 10)
(cond ((= i 3)
(go continue01)))
(setq sum (+ i sum))
continue01
(setq i (+ i 1)))
(print sum)) ;52を表示
continue文のフローチャート
11.11. break文¶
break文はLispでは returnを使います。
break → return
returnはループ制御文を抜けだします。
returnの書式
(ループ制御
(if 条件 (return)) ;break → return
その後の処理))
returnはdo、dolist、whileのループ制御を抜け出します。
returnのフローチャート
returnの例
lisp_for_break.lisp
(let ((sum 0) (i 1))
(while (<= i 10)
(setq sum (+ sum i))
(cond ((>= sum 30)
(return))) ;break → return
(setq i (+ i 1)))
(print sum)) ;36を表示
break文のフローチャート
11.12. ラベル付きcontinue文¶
Lispにはラベル付continueの構文はありません、goを利用して対応します。
Javaにはラベル付continueがありますので、どのようなものか 参考にしてください。
(ループ制御
(ループ制御
(if 条件 (go continueラベル))
その後の処理
)
その後の処理1
continueラベル
)
「continue ラベル」はdo、dolist、whileの内側の「ループ制御」の「その後の処理」、外側の「ループ制御文」の「その後の処理1」をスキップします。
continue文のフローチャート
ラベル付きのものは、主に多重ループを抜ける処理をスマートの書くために使います。
C言語同様に、Lispもラベル付き continueの構文がないため、go(goto文)を使って記述する。
ラベル付きcontinueの例
lisp_for_double_continue.lisp
(let ((sum 0)(i 1)(j 0))
(while (<= i 10)
(setq j 1)
(while (<= j 10)
(if (= i 3)
(go continue01))
(setq sum (+ sum (* i j)))
(setq j (+ j 1)))
continue01
(setq i (+ i 1)))
(print sum)) ;2860を表示
ラベル付きcontinue文のフローチャート
11.13. ラベル付きbreak¶
Lispではラベル付break構文はありません、goと tagbodyを使って同じ処理を書きます。
ラベル付breakの構文
(tagbody
(ループ制御
(ループ制御
(if 条件 (go breakラベル))
その後の処理
)
その後の処理
breakラベル
)
「breakラベル」はdo、dolist、whileなどのループ制御をすべて抜けだして終了します。
ラベル付きbreak文のフローチャート
ラベル付きのものは、主に多重ループを抜ける処理をスマートの書くために使います。
C言語同様に、Lispもラベル付き breakの構文がないため、go(goto文)を使って記述する。
ラベル付きbreak文の例
lisp_for_double_break.lisp
(let ((sum 0) (i 1) (j 0))
(tagbody
(while (<= i 10)
(setq i 1)
(while (<= j 10)
(setq sum (+ sum (* i j)))
(if (>= sum 15)
(go break01))
(setq j (+ j 1)))
(setq i (+ i 1)))
break01)
(print sum)) ;15を表示
ラベル付きbreak文のフローチャート