日本ソフトウェア科学会第 33 回大会 (2016 年度) 講演論文集

学習項目を利用した
プログラミング学習用プルーフリーダの試作
蜂巣 吉成

吉田 敦

阿草 清滋

プログラミング学習において，学習者が作成したプログラムが教育者の意図に合致しているかをチェックするプルーフリーダを試作した．プログラミング学習では，学習者は課題の実行例などを参考にプログラムの動作確認をし，実行例と同じ出力が得られたら課題を終了していることが多い．しかし，学習者が作成したプログラムが冗長であるな
ど，必ずしも教育者が意図したプログラムが書けているとは限らない．プログラム評価の基準は課題毎に異なるが，本研究ではこれを学習項目として整理し，教育者が作成した模範解答プログラムと学習者のプログラムを比較して，教育意図に合っていないプログラムを発見するプルーフリーダを試作した．

We propose a prototype of program proofreader, which checks learners’ programs against learning objectives.
In programming exercises, learners sometimes tend to think that their tasks were accomplished when theirprograms were executed in the same ways as sample test cases. However, their programs sometimes include
redundant computation and unsuitable codes for exercises’ objectives. We have implemented a program
proofreader which compares learners’ programs to a model program written by a teacher from views oflearning objectives.

しくない記述を指摘することで学習効果を上げるこ1 はじめにとができるが，教育者が学習者一人ひとりに対して指大学などのプログラミング演習における課題には，導するのは負担が大きい．コーディングチェッカを用

その課題を通して教育者が学習者に学ばせたい教育いて，学習者のプログラムをチェックする方法もある

意図があり，学習者がその意図に合った記述をするこが，一般的なコーディング規約には違反していない記とによって，文法や典型的なプログラム例を学んでい述でも教育意図を満たしていない場合もある．ルー

く．演習課題では，作成すべきプログラムの仕様となルのカスタマイズ可能なコーディングチェッカを用いる課題文章と実行例を学習者に提示するのが一般的て，課題毎にルールを記述することも考えられるが，である．学習者は実行例通りに動作するプログラムが教育者の負担が大きい．

作成できれば，プログラムが完成したと考えて課題

本研究では，プログラミング演習の課題では一般を終了していることも多く，必ずしも教育意図に合っに問題作成者 (教育者) が模範解答プログラム（以下，たプログラムを作成しているとは限らない．

模範プログラムと呼ぶ) を作成することに着目し，模教育者が学習者に対して教育意図とは異なる好ま範プログラムと学習者のプログラムを比較して教育意図に合わない記述や冗長な処理をチェックする方法

A Prototype of Program Proofreader using Learning
Objectives
Yoshinari Hachisu, 南山大学理工学部, Faculty of Science and Engineering, Nanzan University.
Atsushi Yoshida, 南山大学理工学部, Faculty of Scienceand Engineering, Nanzan University.
Kiyoshi Agusa, 南山大学理工学部, Faculty of Scienceand Engineering, Nanzan University.

を提案する．どのような課題に対しても同一の基準で比較すると，教育者の負担は少なくなるが，模範プ
ログラムとほとんど同じプログラム以外は不適切と評価されたり，逆に不適切なプログラムが適切と評価される場合が多くなる．課題毎に基準を設定すれば，評価結果は妥当になるが，教育者の基準作成の負担が増える．本研究では，条件分岐や繰り返し，配列などり返しを用いて計算をする」である．なお，変数名なの学習単元が同じ課題ならば，教育意図は似たもの

どは学習者によって異なる可能性があるので，プログになると考えて，C 言語の代表的な教科書 [6] の例題

ラム例では変数名を統一していない．などを分析し，if や for などの制御文，およびその条
件式の有無，繰り返し中に計算される変数の初期化の有無などを 「学習項目」 として評価基準を設定する方法を提案する．教育者が学習項目を選択すると，


課題 配列の合計



配列に n 個の整数を入力し，合計を求めなさい．


課題 配列の最大値それに対応した評価基準で模範プログラムと学習者

配列に n(>= 1) 個の整数を入力し，最大値を求のプログラムを比較・評価する．

めなさい．



提案方法に基づいて，学習者のプログラムを評価するツールを試作した．ツールは学習者が完成したと考実行例:

えたプログラムの評価を行うので，ツールの入力となデータ数? 10

るプログラムはコンパイルエラーがなく，課題に提示10 個のデータ? 45 74 89 5 32 68 95 70 82 0

された実行例通りに動作するものとする．最低限の動作確認がなされたプログラムに対して，より良い最大値 = 95
課題 累乗


記述を，コーディングスタイルだけでなく，教育意図という意味的な観点からもチェックを行うので，本研
究ではこのツールをプルーフリーダと呼ぶ．本研究では C 言語のプログラミング初学者を対象に条件分岐，繰り返し，配列までの学習単元の学習項目を整理し，それらを評価するプルーフリーダを設計・試作した．学習者が課題のプログラムを提出すると，プルーフリーダがそれを評価して，結果を学習者にフィードバックすることを想定しているが，試作したプルーフリーダはプログラム評価方法の確認に重点を置いた
ので，フィードバック機能は未実装である．プルーフリーダにより，事前には想定していなかった好ましくない記述も発見できることを確認した．

2 動機
本節では，プログラミング演習の課題例として，配列の合計，配列の最大値，累乗を求めるプログラムを取り上げ，それらの模範プログラムと学習者のプログラムを示し，プルーフリーダの必要性について述べる．それぞれの課題の教育意図は，「繰り返しで計算していく変数を適切に初期化し，配列の先頭要素から最後の要素まで繰り返し処理を行う」，「配列の先頭要素について処理した後に，配列の次の要素から最後の要素まで繰り返し，条件判定をして処理を行う」，「繰り返しで計算していく変数を適切に初期化し，繰

実数 x の n 乗 (n は 0 以上の整数) を求めなさい．



ソースコード 1 は配列の合計を求める課題の模範プログラムである．合計を 0 に初期化した後，配列の先頭要素から最後の要素まで繰り返し，合計に加えていく．学習者はこの課題を通し，配列を先頭から最後まで順次処理をしていく典型的な処理を学ぶ．
ソースコード 2 は配列の最大値を求める課題の模範プログラムである (変数宣言や入出力部分は紙面の都合上，省略している)．配列の先頭要素 (ar[0]) を最大値と仮定し，i=1 から i<n まで繰り返し，それまでの最大値と比較していく．
この課題では 0 から 95 までの整数値に対する実行例が載せてあるが，これを読んだ学習者は入力データがその範囲の整数と思い込み，最初に最大値を-1に初期化したソースコード 3 を作成する場合がある．
この実行例は 100 点満点のテストの点数のように見えるが，そのような制約はない．他の実行例を提示したとしても，その入力データの範囲から勝手に制約を設けてプログラミングする学習者は経験上存在する．
ソースコード 4 は配列の先頭要素 (ar[0]) を最大値と仮定しているが，i=0 から i<n まで繰り返し，それまでの最大値と比較しており，i=0 のときが冗長な繰り返し処理となっている．ソースコード 1 のよう

に，配列は先頭要素から最後の要素まで順に処理する

い．例えば，累乗を求めるプログラムでは x を n 回ことが多く，プログラムの処理の細部まで考えずにプ繰り返しかければよいので，模範プログラムがソースログラミングするとこのような記述に陥りやすい．

コード 7 のとき，学習者がソースコード 8 の記述を

ソースコード 5 も配列の先頭要素から最後の要素していても適切である．学習用にプログラム記述をまで順に処理し，繰り返しの中で配列の先頭要素か判チェックするには，課題毎に異なる基準が必要となる．

定している．繰り返し中に毎回行われる i==0 の条件判定が冗長で好ましくない．繰り返しの条件判定もわかりにくい．
学習者が，ソースコード 2 が配列の最大値を求め

ソースコード 1 配列の合計 模範プログラム
sum = 0;for (i = 0; i < n; i++)sum = sum + array[i];る模範プログラムとして理解した後に，配列の合計を求めるプログラムを作成するとソースコード 6 のように記述する場合がある．要素数が 1 以上ならば合ソースコード 2 配列の最大値 模範プログラム
max = array[0];for (i = 1; i < n; i++)if (array[i] > max) max = array[i];計が正しく求まるが，要素数が 0 の場合の結果は不定となる (この課題文章中には要素数が 1 以上である記述はない)．
われわれのプログラミング演習におけるこれらの経ソースコード 3 配列の最大値 学習者のプログラム 1
ans = -1;
for (i = 0; i < n; i++)if (a[i] > ans) ans = a[i];験から，実行結果は実行例通りであり，プログラムの制御構造も大まかには記述できているものの，詳細に見ると教育意図に合わない記述や可読性の低い記述，冗長な処理をしている場合があり，それらをチェック

ソースコード 4 配列の最大値 学習者のプログラム 2
max = ar[0];for (i = 0; i < n; i++)if (ar[i] > max) max = ar[i];するためのプルーフリーダが必要であるとの考えに至った．学習者は単に動くプログラムを「なんとなく」作るのではなく，課題を通じて何を学ぶのかを理解し，計算手順や処理内容について論理的に考えて，よりよいプログラムを作成できるようになることは重要であり，プルーフリーダはその助けとなる．
ソースコード 2 と 6 は処理が類似しているが，一方

ソースコード 5 配列の最大値 学習者のプログラム 3for (i = 0; i <= n-1; i++)
if (i == 0) max = a[0];else if (a[i] > max) max = a[i];ソースコード 6 配列の合計 学習者のプログラム
s = a[0];for (i = 1; i < n; i++)s = s + a[i];は適切で，もう一方は不適切なコードであり，一般的なコーディングチェッカでこれらを区別してチェックするのは難しい．配列の最大値の課題について，カスタマイズ可能なコーディングチェッカを用いて，ソーソースコード 7 累乗 模範プログラム
pow = 1;for (i = 1; i <= n; i++)pow = pow * x;

スコード 3，4，5 に対するルールを記述すればチェックできる可能性があるが，教育者が課題毎にこれらのルールを記述するのは手間である．さらに，ルールとして記述するのは学習者の好ましくないプログラム

ソースコード 8 累乗 学習者のプログラム
ans = 1;for (i = 0; i < n; i++)ans = ans * x;

であり，これらを事前に考えるのも難しい．
これまでの例では，繰り返しの範囲を学習者のプログラムと模範プログラムとで比較することでチェックが行えるが，すべての課題について，繰り返しの範囲が模範プログラム通りでないといけないわけではな

3 関連研究
コーディングチェッカや学習者向きのフィードバックを行うツールはいくつか提案されている.

CX-Checker [4] は，C 言語プログラムを解析してコーディング規約を満たしているかをチェックするコーダを提案する．制御構造のような文単位のチェックだ

ディングチェッカであり，検査するルールを XPath な

けではなく，繰り返しの範囲や初期化の値などの式単どを用いてカスタマイズすることが出来る．MISRA-位でのチェックも行う．課題の教育意図が反映された

C や実際の企業で用いられているコーディング規約

プログラム箇所を抽象化した記述を「意図パターン」の 80%弱をルールとして記述できたことが報告されと呼ぶ．模範プログラムと学習者のプログラムから，ている．しかし，プログラミング演習に用いるには，意図パターンにマッチしたコード断片を抽出し，変数教育者が課題毎に学習者の好ましくないプログラム名などの抽象化を行う．このようにして得られたコーを考えて，ルールをカスタマイズする必要があり，負ド断片を 「評価コード」 と呼び，模範プログラムと担が大きい．checkstyle [1] などのルールがカスタマ

学習者のプログラムの評価コードを比較することで，イズ可能なコーディングチェッカ一般に対して同様の教育意図に合った記述をしているかをチェックする．

ことが言える．

教育者の負担を減らすために，課題毎に教育者が意図

Truong らは初学者の Java プログラムを静的解析パターンを記述するのではなく，次節で述べる学習項して，フィードバックをするシステムを提案している

目毎に意図パターンをあらかじめ記述しておき，教育[2]．プログラムの循環的複雑度などのソフトウェアメ者がそれを選択する方法を採用した．

トリクスを計測したり，模範プログラムとの制御構造の比較を行い，その結果からよりよいコードを指摘し4. 2 学習項目たりすることができる．本研究の目的と近いが，“fill条件分岐 (if と switch)，繰り返し (while, for, do-in the gap” 形式の演習課題，すなわち，プログラムwhile)，配列の学習単元に対して，C 言語の代表的なの入出力部分や変数宣言などがあらかじめ記述されて教科書 [6] の例題や演習問題などから教育意図を分析いてコードの一部を記述する課題を対象としている．

し，次の観点から整理した．

制御構造の比較では繰り返し文の中に代入文が 2 つ

条件式の有無 if 文や while 文の条件式，for 文のあるなどの文単位で模範プログラムと学習者のプロ

3 つの式が教育意図に該当するかどうかを表す．

グラムを比較している．本研究での対象は C 言語で繰り返しの範囲などが教育意図に含まれるならプログラム全体を記述する課題であり，文よりも粒度ば「有」となる．
「無」の場合は，if 文や for 文なの細かい式などについても評価を行う (文単位では，どの制御文が模範プログラムと同じように記述ソースコード 2，3，4 は違いがない)．

されているかのみのチェックとなる．

C-Helper [3] は C 言語初学者向けの静的解析ツール

初期化の有無 繰り返し中に計算される変数の初である．プログラム作成で試行錯誤している学習者に期化式 (例えば，配列の最大値や合計の初期化式

対して，ソースコードから初学者が陥りやすいミスをなど) が教育意図に含まれるかどうかを表す．

認識し，分かりやすい言葉で指摘し，可能ならばその本研究では，(学習単元，条件式の有無，初期化の解決策を提案する．本研究のプルーフリーダは完成し有無) の 3 つの組み合わせを学習項目と呼ぶ．学習単たプログラムに対して，教育意図に合わない記述など

元が if や while, for などの文単位でチェックすべきのチェックを行うツールであり，目的が異なる．

制御構造を表し，条件式や初期化の有無が式単位でチェックすべき値などを表す．

4 学習項目を利用したプルーフリーダ
4. 1 概要

4. 3 意図パターンと評価コード

本研究では，演習課題の模範プログラムは教育意図

4. 2 節の学習項目毎に意図パターンを定義した．例に従って作成されていることを前提とし，課題毎に学えば，ソースコード 9 は (配列，条件式有，初期化有)

習者のプログラムを模範プログラムと比較して，教の学習項目に対応する意図パターンであり，繰り返し育意図に合致しているかをチェックするプルーフリーの範囲，繰り返し中に計算される変数の初期値を表している．ソースコード 10 は (繰り返し (for)，条件習項目を選択して，ソースコード 10 の意図パターン

式無，初期化有) の学習項目に対応する意図パターンを用いると，ソースコード 7 と 8 の評価コードはとである．意図パターン中の$VAL，$REL_OP，$OP は，もにソースコード 17 で同じものになる．

それぞれ値 (リテラル)，関係演算子，演算子を表すメタ記号であり，プログラム中の該当する字句にマッチし，その字句が評価コードとして抽出される．ORは「または」である．[] は配列参照を表すメタ記号で，マッチすると [] が評価コードとして抽出されソースコード 11 ソースコード 1 の評価コード$var=0; for(=0;<;++){$var=}

ソースコード 12 ソースコード 6 の評価コード$var=[]; for(=1;<;++){$var=}

る．$var は変数参照を表すメタ記号で，マッチすると$var が評価コードとして抽出される．
ソースコード 9 意図パターンの例 1 (配列，条有，初有)$var=$VAL OR [];for(=$VAL; $REL_OP; $OP) {$var=}

ソースコード 10$var=$VAL;
for(;;) {$var=}

意図パターンの例 2 (for，条無，初有)

ソースコード 13 ソースコード 2 の評価コード$var=[]; for(=1;<;++){if(){$var=}}

ソースコード 14 ソースコード 3 の評価コード$var=-1; for(=0;<;++){if(){$var=}}

ソースコード 15 ソースコード 4 の評価コード$var=[]; for(=0;<;++){if(){$var=}}

ソースコード 16 ソースコード 5 の評価コード
for(=0;<=;++){if(){}elseif(){}}

教育者が学習項目を選択すると，意図パターンが決まり，プルーフリーダは模範プログラムと学習者のプ
ログラムに意図パターンを適用し，評価コードを抽出

ソースコード 17 ソースコード 7 と 8 の評価コード$var=1; for(;;){$var=}

する．繰り返し中に条件判定を行う課題などは，複数の学習項目を選択することで，それらの意図パターン

4. 4 設計と実現にマッチした箇所が評価コードとして抽出される．

条件分岐，繰り返し，配列の学習単元についてチェッ

例えば，2 節の配列の合計では変数の初期値と繰りクを行うプルーフリーダを試作した．プルーフリーダ

返しの範囲を調べたいので，(配列，条件式有，初期はプログラムと学習項目を入力として，評価コードを化有) の学習項目を選択して，ソースコード 9 の意図出力する．模範プログラムと学習者のプログラムの評パターンをソースコード 1，6 に適用すると，ソース価コードを diﬀ コマンドで比較することで，学習者コード 11，12 が得られ，模範プログラムと学習者ののプログラムが教育意図に合っているかをチェックでプログラムの評価コードが異なることがわかる．配列

きる．C プログラムの構文解析やパターンマッチングの最大値では，変数の初期値と繰り返しの範囲に加には，属性付き字句系列に基づく書換え処理系である

えて条件分岐を調べたいので，(配列，条件式有，初TEBA [5] を利用した．

期化有) と (条件分岐，条件式無, 初期化無) の学習項

評価コードの抽出処理は，プログラムの正規化，意目を選択して，ソースコード 2，3，4，5 に適用する

図パターンにマッチした字句のマーキング，マーキンと，ソースコード 13，14，15，16 が得られ，模範プ

グされていない字句の削除の 3 つの処理で構成されログラムと学習者のプログラムの評価コードが異なる．図 1 に評価コード抽出の処理の概略を示す．各処ることがわかる．累乗の課題については，繰り返しの理を TEBA の書換えルールを用いて実現した．正規範囲は不要で，計算に使われる変数の初期値を調べた化ではコーディングスタイルの差異を統一する．例えいので，(繰り返し (for)，条件式無，初期化有) の学

ば，初期化式のある変数宣言を初期化式のない変数

正規化処理プログラム正規化ルール

学習項目

マーキング処理マーキング
ルール

せない学習者が多いと経験的に感じる．例えば，「2 つ削除処理
削除ルール

意図パターン

評価コード抽出処理
図1の整数値の大きい値を返す関数 max2 を呼び出して，評価コード3 つの整数値の最大値を返す関数 max3 を定義しなさ

凡例
入出力
内部処理

い」という課題に対し，ソースコード 18 のようなプ

ファイル

意図パターンでは不十分で，同じ実引数の関数呼び出

評価コード抽出処理の概略

宣言と代入文に分離する，制御文の本体が 1 文の場ログラムがありうる．これをチェックするには今回のしを調べたり，データフロー解析などが必要となる．
また，教育者が必要に応じて意図パターンをカスタマイズできるような仕組みも検討している．

合にブロック化のための波括弧を追加する，などが行われる．1 つの意図パターンは TEBA の複数の書換えルールで記述されており，マーキングではそれらのルールを順次適用して字句をマーキングする．学習項

ソースコード 18 3 変数の最大値 学習者のプログラム
int max3(int x, int y, int z) {if (max2(x, y) < z) return z;
else return max2(x, y);}

目はコマンドラインから対話的にメニュー形式で選択して，入力する．プログラムの規模は TEBA のルールファイルが 44 個，約 660 行で，それらを順次適用して評価コードを抽出して，比較をするためのシェルスクリプトが約 500 行である．

6 おわりに
本研究では，模範プログラムと学習者のプログラムを比較して，教育意図に合っていないプログラムを発見するプルーフリーダを試作した．実際の演習問題について適用し，事前に想定していなかった好ましくな

4. 5 評価
試作したプルーフリーダを実際の演習課題で提出された学習者のプログラムに適用したところ，課題作い記述が発見できた．
今後の課題として，より多くの演習課題にプルーフリーダを適用して評価を行うことなどがあげられる．

成時には想定していなかった冗長な処理や好ましくない記述が見つかった．3 変数が等しいかを調べる課題

謝辞 本研究の一部は，JSPS 科研費 26350344，2016

で，条件式を a==b && b==c && c==a のように冗長

年度南山大学パッへ奨励金 I-A-2 の助成を受けた．に記述している例や，入力された値を 60 を閾値として判定する課題で，条件式を p<=59 のように閾値を参 考 文 献

変更した可読性の低い記述をしている例などが発見[1] Checkstyle: http://checkstyle.sourceforge.net.
[2] Truong, N., Roe, P., and Bancroft, P.: StaticAnalysis of Students’ Java Programs, Proceedingsof the Sixth Australasian Conference on Computing Education - Volume 30, ACE ’04, AustralianComputer Society, Inc., 2004, pp. 317–325.
[3] 内 田 公 太, 権 藤 克 彦: C 言 語 初 学 者 向 け ツ ー ルC-Helper の 予 備 評 価, 電 子 情 報 通 信 学 会 技 術 研
究 報 告. KBSE, 知 能 ソ フ ト ウェア 工 学, Vol. 113,No. 160(2013), pp. 67–72.
[4] 大須賀俊憲, 小林隆志, 渥美紀寿, 間瀬順一, 山本晋一郎, 鈴村延保, 阿草清滋: CX-Checker：柔軟にカスタマ
イズ可能な C 言語プログラムのコーディングチェッカ, 情報処理学会論文誌, Vol. 53, No. 2(2012), pp. 590–600.
[5] 吉田敦, 蜂巣吉成, 沢田篤史, 張漢明, 野呂昌満: 属性付
き字句系列に基づくソースコード書き換え支援環境, 情報処理学会論文誌, Vol. 53, No. 7(2012), pp. 1832–1849.
[6] 柴田望洋: 新・明解 C 言語 入門編, SB クリエイティブ, 2014.

できた．

5 考察
本研究の今後の展開について考察する．
今回試作したプルーフリーダは，模範プログラムと学習者のプログラムの評価コードを単純に diﬀ コマンドで比較しているだけである．評価コードの差分として得られた字句と学習者に表示するメッセージを対応づけるなどして，効果的にフィードバックする方法を今後検討する必要がある．
関数や構造体などの他の単元に対するチェックも必要である．関数は定義できても，それを適切に呼び出