期末試験 2025#
答えの表示/非表示
時間:60分,問題:25問(各4点)
SCコードとJavaバイトコードの補足資料あり
1. 関数型言語#
関数型言語に関する説明のうち,適切なものを全て選択せよ#
- 関数型の計算モデルはラムダ計算である
- 関数型では計算手順の列挙によりプログラムを表現する
- 関数型では変数への再代入は原則禁止である
- 関数型の優れた性質は命令型プログラミングでも適用できる
- ラムダ記法を用いることで関数名を持たない関数を表現できる
Note
B. 手順の列挙ではなく関数を組み合わせる.
関数aに関する説明のうち,適切なものを全て選択せよ#
- 引数
xyを束縛変数,引数fを自由変数と呼ぶ - 関数
aはカリー化済みである - 関数
aは第一級オブジェクトである - 関数
aは高階関数である - 関数
aに対する関数適用a 10 * 2の結果は23である
Note
A. 全て束縛変数である.
B. 引数が複数あるのでカリー化されていない.
C. 関数は全て第一級オブジェクトである.
D. 引数fが関数であるため高階関数である.
E. + 10 * 3 2 = 16
ラムダ式の同値関係のうち,\(\beta\)変換に該当するものを全て選択せよ#
→ の前後は同値を意味する.
λfx. f x 5 → λgx. g x 5λfx. f x 5 → λgy. g y 5(λfx. f x 5) + → λx. + x 5(λfx. f x 5) + 4 → + 4 5plus 4 5 → (λxy. + x y) 4 5
Note
A. \(\alpha\)変換.
B. \(\alpha\)変換.
E. 名前付き関数plusの単なる展開(書き換え)であり,\(\alpha\)変換でも\(\beta\)変換でもない.
次の関数xxxに対し,適切な関数名を一つ選択せよ#
なおラムダ計算において関数trueとfalseは以下のように定義される.
notandorxorif
Note
引数はp qの2項なので答えはand or xorのいずれかである(notは1項,ifは3項).そのうえで挙動を試してみると良い.
まずはxxx true trueを試す.
(λpq. p true q) true true
→ true true true ; pとqにtrueとtrueを適用
→ (λxy. x) true true ; 1つ目trueを展開
→ true ; λxyにtrueとtrueを適用
xorではない.andかorのいずれかである. 答えはorに確定する.関数適用は常に左結合である点に注意すること.
あるいは関数の意味から以下のように考えても良い.
- 前提:
- trueは2項
xyを受け取り1つ目の項xを返す関数である
falseは2項xyを受け取り2つ目の項yを返す関数である - 関数
xxxの本文p true qに着目すると: p=trueのときに1つ目の項trueを返す
p=falseのときに2つ目の項qを返す
まさにorの振る舞いである.
2. 論理型言語#
Prologに関する説明のうち,適切なものを全て列挙せよ#
- Prologは関数の組み合わせでプログラムを表現する
- Prologは処理手順の列挙でプログラムを表現する
- Prologは算術演算が可能である
- Prologの内部処理はカリー化に基づく推論の繰り返しである
- Prologでは開発者によるバックトラックの制御が可能である
Note
A. 関数ではなく論理式を組み合わせる.
B. 手順ではなく論理式を組み合わせる.
C. もちろん可能.講義中で示した最大公約数gcd/3の内部でも剰余演算を利用していた.
D. カリー化ではなく単一化である.
E. カット!/0や失敗fail/0などが存在する.
Prologにおける単一化操作のうち,成功するものを全て列挙せよ#
= は左辺と右辺の単一化を試みる命令である.
X = 5p(X, Y) = p(5, 5)p(X, Y) = ps(5, 5)p(X, Y) = p(A, B)p(X, Y) = p(A, A)
Note
C. 述語が異なると単一化は全て失敗する.
E. 2つの変数XYが偶然同じ値をとっても論理としては矛盾していない.
次の述語xxxに対して,最も適切な名前を一つ選択せよ#
sum(総和)factorial(階乗)square(二乗)sqrt(平方根)power(べき乗)
先のsrc1.plの述語定義に含まれる問題点を全て選択せよ#
- 述語
xxxが2つの論理式で定義されており実行効率が悪い - カット
!/0が利用されておらず単一化が成功しない - 1つ目の述語定義
xxx(0, 1).の両方の項が定数であり単一化が成功しない - 負の整数を与えた際に無限ループが発生する
- バックトラックを発生させると無限ループが発生する
Note
A. 論理型言語では同じ述語を複数の論理式によって定義する.
B. 意味不明である.
C. 意味不明である.
D.
?- xxx(-1, X).を実行すると負の方向に発散する.
E.
?- xxx(4, X).で解24を得た後にバックトラックを発生させる,つまり別解を探索させると負の方向に発散する.
3. C言語#
C言語のメモリ領域に関する説明のうち,適切なものを全て選択せよ#
- 機械語命令列はプログラム領域に格納される
- 局所変数はスタック領域に格納される
- プログラムカウンタはプログラム領域内を指し示している
- スタックポインタはスタック領域内を指し示している
- ベースポインタはスタック領域内を指し示している
次のSCコードに関する説明のうち,適切なものを全て選択せよ#
IBS 1は変数i用セルの確保であるIBS 1は変数g用セルの確保であるENT 3の3の内訳は制御領域セル3つであるENT 3の3の内訳は制御領域セル2つと返り値用セル1つであるENT 3の3の内訳は制御領域セル2つと変数i用セル1つである
Note
A. 変数セルはENTで確保される.
B.
C. 制御領域は常に2つである.
D. 返り値セルはENTとは関係なく確保されている.
E.
次のSCコードの???として,適切なものを一つ選択せよ#
変数iのSCコードでの相対番地は3とする.
Note
逆ポーランド記法で並べれば正解である.
A. BOP +の時点で想定外の挙動が発生する.中間記法である.
B. BOP *の時点で想定外の挙動が発生する.
C. BOP +の時点で想定外の挙動が発生する.ポーランド記法である.
D. 逆ポーランド記法である.
E. 逆ポーランド記法だが被演算子の順序がおかしい.実行は可能だが結果は正しくない.610 (= 10 + 20 * 30)ではなく230 (= 10 * 20 + 30)となる.
次のSCコードの???として,適切なものを一つ選択せよ#
変数iのSCコードでの相対番地は3とする.
Note
以下の流れである.下向きの条件付きジャンプと上向き無条件ジャンプが交差する.
- iをロードして条件付きジャンプ(
LDC 3→JPZ y), - while本文を実行して(
LDC 0→STL 3), - 冒頭へ無条件ジャンプ(
JMP x)
スタックフレームに関する説明のうち,適切なものを全て選択せよ#
- main関数はスタックフレームを持たない特殊な関数である
- 関数呼び出しの度に新たなスタックフレームが生成される
- 関数リターンの度に新たなスタックフレームが生成される
- 代入処理の度に新たなスタックフレームが生成される
- スタックフレームの生成はプログラムカウンタの増加で実現される
Note
A. main関数もスタックフレームを持つ.
B.
C. 関数終了時はフレームは消える.
D. 代入はフレーム生成とは関係がない.
E. プログラムカウンタの増加は機械語の1実行と同じ意味である.
関数呼び出しに関するSCコードの説明のうち,適切なものを全て選択せよ#
★1が関数呼び出しを実現するSCコードである.LDC MST CUPの組み合わせで実現される.変数iのSCコードでの相対番地は3とする.
LDCによって呼び出し先関数fへ渡す引数を記録するMSTによって呼び出し先関数fを終了した後の戻りアドレスを記録するMSTによって呼び出し先関数fを終了した後のベースポインタを記録するCUPによって呼び出し先関数f用のスタックフレームを生成するCUPによって呼び出し先関数fへプログラムカウンタを指定させる
Note
A. LDCが記録する情報は呼び出し先関数のアドレスである.
関数のリターンに関するSCコードの説明のうち,適切なものを全て選択せよ#
先のSC言語ソースコードsrc2.scとSCコードsrc2.sccを参照せよ.★2が関数のリターンを実現するSCコードである.STL RETの組み合わせで実現される.
STLによって返り値用のメモリセルに返り値を記録する- 返り値は呼び出し元関数mainのスタックフレームの最下部に記録される
RETによって呼び出し元関数mainへプログラムカウンタを指定させるRETによって実行中関数fのスタックフレームを破棄する- 実行中関数fの返り値がない場合は
RETは不要である
Note
A. スタック最下部が返り値用の領域である.
B. 返り値は最上部に記録される.
C.
D.
E. 返り値の有無に関わらずRETは必須である.
4. Java言語#
次のJavaプログラムの★の時点で,スタック領域中の局所変数領域が取り得るレイアウトを一つ選択せよ#
はメモリの単一セルを表す.値EB..はメモリへの参照である.
A. h 3 2 1
B. EB1C 3 2 1
C. EB1C EB14 EB0C 1
D. EB1C EB14 EB0C EB04
E. EB1C EB0C EB04
Note
3つの参照型変数があるので,スタックには3つの参照が積み上げられる.
次のJavaプログラムのメソッドf()を実行した際の現象として,最も適切なものを一つ選択せよ#
- Null参照の例外が発生する
- スタック領域不足の例外が発生する
- ヒープ領域不足の例外が発生する
- メソッド領域不足の例外が発生する
- 例外は発生せず無限にプログラムが実行され続ける
Note
再帰呼び出しによりスタックフレームが無限に積み上げられる.最終的にスタック側の不足が発生する.
次のJavaプログラムのメソッドf()を実行した際の現象として,最も適切なものを一つ選択せよ#
- Null参照の例外が発生する
- スタック領域不足の例外が発生する
- ヒープ領域不足の例外が発生する
- メソッド領域不足の例外が発生する
- 例外は発生せず無限にプログラムが実行され続ける
Note
可変長配列へのaddにより,ヒープ側で不足が発生する.
次のバイトコードの???として,適切なものを一つ選択せよ#
変数iのバイトコードでの相対番地は3とする.
Note
SCコードの問題と全く同じである.
次のバイトコードの???として,適切なものを一つ選択せよ#
変数xとbのバイトコードでの相対番地は,それぞれ3と4とする.
if_icmpgeif_icmpgtif_icmpleif_icmpltgoto
Note
条件が反転する点に注意せよ.
Javaのメソッド呼び出しに関するバイトコードの説明のうち,適切なものを全て選択せよ#
new XによってクラスX用のメモリをヒープ領域に確保するnew XによってクラスX用のメモリをスタック領域に確保するinvokespecial Xによって実行中関数のスタックフレームの形状を退避させるinvokespecial XによってXのコンストラクタのスタックフレームを生成するinvokespecial XによってXのコンストラクタへプログラムカウンタを移動させる
プログラム実行をスタックフレームで表現する理由として,適切なものを全て選択せよ#
- 各メソッドの局所変数に対する自動的な初期化が可能である
- 同一メソッドであっても呼び出しごとに独立した局所変数領域を確保できる
- 不要となったヒープ領域の自動的な回収が可能である
- 再帰呼び出し時の各メソッドの状態の保持と復元が可能である
- 式や代入に対する自動的な型チェックが可能である
Note
A. 初期化は無関係である.実際C言語の変数は未初期化である.
B.
C. ヒープの自動回収はガーベージコレクションの問題であり,フレームとは無関係である.
D.
E. 型チェックは無関係である.
5. 講義全体#
プログラミング言語に関する説明として,適切なものを全て選択せよ#
- プログラミング言語の目的はプログラミング労力の軽減である
- プログラミング言語を用いることで機械語よりも高い抽象度で記述ができる
- プログラミングパラダイムとはプログラミング言語が採用する規範や哲学である
- プログラミング言語の構文規則は文脈自由文法やBNF等を用いて定義される
- 機械語の直接記述と比較すると,プログラミング言語を利用することで数多くの制約が発生する
次のテーマについて自身の考えを理由と共に記述せよ#
「複数のプログラミング言語を学ぶべきか?」
マークシート表面の記入欄Aに解答を記述せよ.
講義全体に対する改善案や感想,意見を記述せよ#
マークシート裏面の記入欄Bに解答を記述せよ.
試験問題に対する異議申立がある場合は,マークシート裏面の空欄に記述すること.
補足資料#
SCコード命令一覧#
stack[]:スタック領域,sp:スタックポインタ,bs:ベースポインタ,pc:プログラムカウンタ
| # | SCコード | 意味 | スタック領域とレジスタに対する操作 |
|---|---|---|---|
| 1 | LDC a | load constant | sp++;t[sp]=a; |
| 2 | LDL a | load local | sp++;t[sp]=t[bs+a]; |
| 3 | LDG a | load global | sp++;t[sp]=t[a]; |
| 4 | LDLA a | load local addr | sp++;t[sp]=bs+a; |
| 5 | LDGA a | load global addr | sp++;t[sp]=a; |
| 6 | STL a | store local | t[bs+a]=t[sp];sp--; |
| 7 | STG a | store global | t[a]=t[sp];sp--; |
| 8 | STI | store at indexed addr | t[t[sp-1]]=t[sp];sp--;sp--; |
| 9 | IND a | indexed fetch | t[sp]=t[t[sp]+a]; |
| 10 | JMP L | jump | pc=L; |
| 11 | JPZ L | jump if zero | if(t[sp]==0){pc=L;}sp--; |
| 12 | ENT a | enter block | sp=bs+a; |
| 13 | MST | mark stack | sp++;t[sp]=bs;sp++; |
| 14 | CUP a※1 | call user procedure | t[sp-a]=pc+1;bs=sp-a-2;pc=t[bs]; |
| 15 | RET a※2 | return from function | sp=bs-a;pc=t[bs+2];bs=t[bs+1]; |
| 16 | BOP o※3 | binary operation | sp--;t[sp]=(t[sp])o(t[sp+1]); |
| 17 | UOP o※4 | unary operation | t[sp]=o(t[sp]); |
| 18 | IBS a | increment base | bs+=a; |
| 19 | HLT | halt |
※1 aは呼び出す関数の引数の数
※2 関数の返り値がvoid型のときa=1,int型の時a=0
※3 oは二項演算子(+ - * / > >= < <= ==等)
※4 oは単項演算子(+ - !等)
Javaバイトコード命令一覧#
stack[]:スタック領域,heap[]:ヒープ領域,
optop:スタック最上部を示すレジスタ,frame:制御領域を示すレジスタ,
vars:スタック最下部を示すレジスタ,pc:プログラムカウンタレジスタ
| # | 命令 | スタック領域とレジスタに対する操作 |
|---|---|---|
| 1 | bipush c | optop++;stack[optop]=c; |
| 2 | ldc a | optop++;stack[optop]=heap[a]; |
| 3 | iload a | optop++;stack[optop]=stack[vars+a]; |
| 4 | aload a | optop++;stack[optop]=stack[vars+a]; |
| 5 | istore a | stack[vars+a]=stack[optop];optop--; |
| 6 | astore a | stack[vars+a]=stack[optop];optop--; |
| 7 | iadd | optop--;stack[optop]=stack[optop]+stack[optop+1]; |
| 8 | imul | optop--;stack[optop]=stack[optop]*stack[optop+1]; |
| 9 | goto L | pc=L; |
| 10 | if_icmpne L | if(stack[optop-1]!=stack[optop]){optop-=2;pc=L} |
| 11 | if_icmpeq L | if(stack[optop-1]==stack[optop]){optop-=2;pc=L} |
| 12 | if_icmpge L | if(stack[optop-1]>=stack[optop]){optop-=2;pc=L} |
| 13 | if_icmpgt L | if(stack[optop-1]> stack[optop]){optop-=2;pc=L} |
| 14 | if_icmple L | if(stack[optop-1]<=stack[optop]){optop-=2;pc=L} |
| 15 | if_icmplt L | if(stack[optop-1]< stack[optop]){optop-=2;pc=L} |
| 16 | new X | optop++;stack[optop]=malloc(X); |
| 17 | dup | optop++;stack[optop]=stack[optop-1]; |
| 18 | invokespecial X※1 | stack[optop+v+1]=pc;stack[optop+v+2]=vars;stack[optop+v+3]=frame;vars =optop-p;frame=optop+v+1;optop=optop+v+4;pc=X; |
※1 vはクラスXのコンストラクタの局所変数の数,pはコンストラクタの引数の数