見出し画像

「プログラミング的思考」という幻想

「プログラミング的思考」って,なんだっけ。
すぐ忘れてしまうので,その都度,文科省のわかりにくい文書を探すことになる。
そういえば,以前まとめたな,と思い,note をさかのぼる。
「プログラミング教育を考える」を5回シリーズで書いた。
プログラミング教育を考える(1) では

~小学校プログラミング教育の手引(文科省H30.3.)より抜粋引用~
プログラミング的思考(①~④)(丸数字を使っています。環境によっては文字化けするかも)
意図した一連の活動をさせるために
 ① 必要な動きを分けて考える
 ② 動きに対応した命令(記号)にする
 ③ 組み合わせる
 ④ ①②③の中で試行錯誤しながら継続的に改善することで問題が解決する 
~引用終わり~

を引用した。

プログラミング教育を考える(4) では,この中の④について,プログラミングは試行錯誤でやるものではない,ということを書いた。
プログラミング教育を考える(5) それで「プログラミング」ができますか では,この「試行錯誤」に関連した内容になっている。

 ところで,文科省が「プログラミング的思考」を持ち出してきているのは,プログラマの養成が目的ではなく,「プログラミングができるようになること」もその目標ではない,ということに関しては,共通理解ということでよいだろうか。
世の中にだいぶでてきた「プログラミング教室」は,それを「共通理解」としていないようだが。
 つまり,「プログラミング的思考」の育成は,プログラミング教育ではなく,「プログラミング」という語を使わなくてもいいことがらに,わざわざ「プログラミング」という言葉をつけて,いかにも新しい時代の教育であるかのような幻想をいだかせているにすぎない,ということだ。

 なぜか。

 断言していい。文科省のいう「プログラミング的思考」だけでは,プログラミングはできないからだ。

 その一つの例を,「コンピュータの文字コードの勉強をしましょう」「結局,「わからない」がわからない」で書いた。これは,文字コードの意味を高校生が理解できていないという例である。
 プログラミングができるためには,アルゴリズムの理解や構築力だけではだめだということだ。
 たとえば,C言語でつまづくことがらに「ポインタ」がある。なぜつまづくか。そのひとつに,メモリにどのように情報が格納されるかを理解できていないということはないか。整数は2バイト,浮動小数点数は32バイト,ASCII文字は1バイト,UTF-8の漢字は3バイト,画面に表示する情報はあるエリアに格納されているといったことが理解できていなければプログラミングできない。これはアルゴリズムとは別のことだ。

 前置きが長くなった。授業実践例を示そう。
2年生の情報の授業でプログラミングを始めた。教科書にある,モデル化とシミュレーションをやるためだ。
 プログラミングは,CindyScriptという言語を用いるが,そのスクリプトエディタの使い方と,プログラムの書式(行末にセミコロンつける,など),上記の事柄について33行分のコード例をつけて,B5判8ページのテキストを作った。授業は65分で,説明を読みながら33行分を入力するのにそこまで時間はかからないだろうと思われたので,課題も用意した。
 始めの2ページはコードの書き方で,ここまでは説明をしながら同時進行。遅い生徒がいても待つ。そのあと,6ページ分は各自ペースで,45分前後(クラスにより差がある)。
内容は,次のようなプログラムの基本。

・変数の概念と,=による値の代入,四則演算 テキスト2ページ コード11行
・制御構造 繰り返しと条件分岐       テキスト2ページ コード10行
・リストの考え方              テキスト1ページ半 コード12行

 さて,実際にやってみると,1コマでは終わらなかった。どこまで行けたかを,大きく3つに分けた。
 四則演算まで    30%
 条件分岐まで    56%
 リストの考え方まで 14%
このあと,課題に取り組めた者は若干名。

45分前後かけて,テキストを2ページしか読めず,コード11行しか打ち込めない者が30%いるのだ。実習は相談可である。わからなければ,近くの生徒と相談してよい。

1コマで終わる予定がとんでもなかった。
次の時間。もう一コマ使った。このとき,課題に対して,解法ガイドを新たに印刷して配布した。
もとの課題は


(1) 初項1 , 公差 3 の等差数列 1 , 4 , 7 , ・・・・ の,初項から第100項までの和を求めて表示しなさい。
(2) 初項2 , 公比 3 の等比数列 2 , 6 , 18 , ・・・・・ の,初項から第10項までの和を求めて表示しなさい。
(3) 漸化式 a_1=1,a_2=1,a_(n+1)=a_(n+1)+a_n  で表される数列の,初項から第10項までの各項と,その和を表示しなさい。

の3つ。数列は数学で学習済みである。(3)の漸化式は実際には n+1 などがサブスクリプトで小さく表示されている。
これに対して,(1)と(2)について,
 ① この数列の第n項(一般項)を n であらわすとどうなるか。
 ② この数列を漸化式の形で書くとどうなるか。
を考えさせ,それを用いてプログラムするというガイドだ。
これで,5題分になる。解答例として用意したコードは18行。(2+3+2+3+8)

結果はどうだったか。
前回の続きで,基本の33行分が完成していない者は,まずそれを完成させる必要がある。
それを考慮した上で,次のような結果であった。(合計が90%にならないのは,取り組んだが不正解の者がいるため)

課題に取り組めた者  90%
1問だけできた者   36%
2問できた者     45%
3問以上できた者   6%

書けたのは4行程度にすぎない生徒が80%いるのだ。

では,解答がどうなるのかを示し,その難易度を考えよう。

テキストでは,リストについて次のように説明している。

 いくつかの値をまとめて扱いたいとき,リストを用いる。
 リストは,角カッコの中に,まとめたいものをコンマで区切って表す。たとえば,1桁の自然数は int=[1,2,3,4,5,6,7,8,9] と表せる。( int という変数に代入した場合。int は他の名前でもよい)この中のものを 要素 という。この中のm番目の要素を用いたいときは,int_m とする。( int にアンダースコア(「ろ」のキー)で m)
 たとえば,print(int_4); とすると,4番目の要素 4 が表示される。
int_3=1; とすると,3番目の要素に 1 が代入される。( 3 が 1 に変わる)
 
【例】
(1) リストを使って1から10までの和を求める。
 CindyScriptでは, m..n で m から n までの整数のリストを作ることができる。合計を求めるには,リストの内容を合計する sum(list) という組み込み関数があるのでこれを利用する。
 1..10 でできるリストを 変数 int に代入し,int の内容とその合計を表示する。
   22: int=1..10;
   23: println(int);
   24: println(sum(int));
 コンソールに
   [1,2,3,4,5,6,7,8,9,10]
   55
と表示されればよい。
 
(2) リストを使って11から20までの和を求める。
 CindyScriptでは, m..n で m から n までの整数のリストを作ることができるのだから,11..20 とすれば,[11,12,13,・・・,20]というリストができる。そこで,この和を求めればよい。
    25: int=11..20;
    26: println(sum(int));
  
リストの要素に共通の処理をする apply
 リスト list の各要素に,同じ処理をするには,apply(list,処理) を用いる。ただし,これだけでは処理した結果は得られないので,list2=apply(list,処理) のように,何かの変数に代入する。処理対象の要素は # で表す。
 
【例】2 から20 までの偶数列を作る。
   27: seq=apply(1..10,#*2);
   28: println(seq);
このコードでは,まず,1..10 でリスト [1,2,3,4,5,6,7,8,9,10] が作られ,その各要素に2をかける処理がされるので,seq=[2,4,6,8,10,12,14,16,18,20] となる。

これに対する問題を再掲しておこう。

(1) 初項1 , 公差 3 の等差数列 1 , 4 , 7 , ・・・・ の,初項から第100項までの和を求めて表示しなさい。
(2) 初項2 , 公比 3 の等比数列 2 , 6 , 18 , ・・・・・ の,初項から第10項までの和を求めて表示しなさい。
(3) 漸化式 a_1=1 , a_2=1, a_(n+2)=a_(n+1)+a_n で表される数列の,初項から第10項までの各項と,その和を表示しなさい。

一般の読者には解くのが難しいだろう。数列の一般項とか漸化式なんて覚えていないだろうから。
しかし,今の対象は,数列をほんの1,2ヶ月前に習った高校生だ。
数列の一般項は,nを自然数として  (1) 3n-2  (2) 2かける3の(n-1)乗 で表される。
したがって,テキストの

   27: seq=apply(1..10,#*2);
   28: println(seq);

を参考にして

    seq=apply(1..100,3*#-2);
    println(seq);

    seq=apply(1..10,2*3^(#-1));
    println(seq);

とすればよい。ここまでできた者が半数弱しかいない。65分使って,である。前回のテキスト分を40分かけたとしても25分でこれだけ。
まあ,次の「漸化式」に比べればできたといえるだろう。
「漸化式」は,前後の項の関係を表したものだ。
等差数列は,前の項に3を足せばよい。
等比数列は,前の項に3をかければよい。
この関係は,a_(n+1)=a_n +3 , a_(n+1)= 3*a_n で表される。(* はかけ算)
しかし,これができた者は6%しかいないのである。
ここで,可能性が2つ考えられる。

その1 等差数列,等比数列を漸化式で表すことができない
その2 本文中にあるリスト処理の「この中のm番目の要素を用いたいときは,int_m とする。」が使えない。

その1は,「等差」の意味がわかっていればなんということはないのだが,彼らは一般項を公式として暗記して使おうとする。意味より公式のあてはめになっている。小中学校で誤って育まれてしまったそういう学習態度が原因ではないか。
その2については,テキストが不十分(例示が足りない)という反省はある。(そこで,1コマ分の補充練習テキストを作った)
しかし,ここができないというのは,「数学の授業で習ったことの意味がわかっていない」「テキストが読み取れない」ということであって,文科省のいう「プログラミング的思考」とはまったく別次元のことなのだ。

小中学校で養うべきは,「プログラミング的思考」などではなく,テキストの読解力,数理科目の理解力なのだ。

「プログラミング的思考」など幻想に過ぎない。

さて,生徒に正解例は渡した。これで理解ができるかどうか。
このあと,さらにプログラミング練習と,モデル化とシミュレーションを数時間やって,期末試験となる。期末試験の結果はどうだろうか。