2021年2月25日木曜日

ブダペストで平和を考えた話

2018年のICWI(International Conference on WWW and Internet)に参加したときの想い出話である.

学会の楽しみといえばエクスカーションに参加して土地のことを学ぶ社会勉強もそのひとつ.修学旅行みたいなものかな.まあ,研究者の人的ネットワークを構築するために,こういう交流も重要ということでご容赦いただきたい.今回は,ローカルのお姉さんによる案内で,ブダペスト市内の主要なポイントを見て回りつつ,中世から現代に至るハンガリーの歴史について学んだ.

自由広場のモニュメント

で,この写真なんだけど,これは自由広場という歴史的な場所にあるこれまた象徴的なモニュメントである.逆光気味で少し分かりづらいが,下のエンジェルが手にしているのはハンガリーの平和を象徴しており,いまにも手からこぼれそう,さらに上のイーグルはドイツを表しているとのこと.すなわち,WWII以前のハンガリーはずっとドイツの脅威に晒されていたということを表しているわけね.

モニュメントの下には,各地から持ち込まれた写真や手紙のコピー,カバンなど遺物が並べられている.右下に掲示されている文言をみればおわかりだろう.わたくしのたいへん浅い歴史観では「ひめゆりの塔みたいなもんかな」くらいにしか感じなかったが,まあ,多くを語るのはやめておこう.

この広場の反対側には,その後ソビエトの影響が強くなった時代のモニュメントがあり,さらに,広場から国会議事堂に続く道の途中には Ronald Reagan の銅像(なぜ彼が?と聞いたら,ゴルビーとの対話に尽力したからなんだとか)やその後の革命で有名になった人(もうこの辺なるとだいぶお腹いっぱいになっていて名前は上の空で聞いていた)の銅像があったりと,さりげなく平和を象徴する道になっていて,まあ,地元の人にいろいろと聞きながら歴史を学びつつ社会勉強するという意味ではいい体験をした.

感想など

で,思ったこと.

  1. 案内してくれた彼女,たいへんわかりやすい英語で丁寧に歴史の説明をしてくれた.自分だったら日本の歴史をあれだけわかりやすく外国人のゲストに説明できるかなあ…「もう少し,専門外のこともいろいろ勉強せんといかんな」と反省.
  2. 一連のモニュメント,さすがに「地球の歩き方」みたいな日本語ガイドブックには載っていないようで,こういうことを学ぶための情報源ってなかなか難しいよね.人的ネットワークがいかに重要か,あらためて気がついた次第.
  3. 昨年は日本人研究者をほとんど見なかったこの学会だったが,今年はなぜか日本人の参加者が,発表件数でいうと1/4も居るらしい.日本のプレゼンスを示すのはたいへんよいことではあるけれど,エクスカーションに参加していた日本人が少なかったのはなぜだろう?もったいないなあ.上記の社会勉強なんかだけじゃなく,こういうところで人的ネットワークが拡がるのに…(ディナーではUAEの先生といろいろ情報交換.酒席の与太話とはいえ,共同研究?みたいな話まで発展した,とかね)


2021年2月24日水曜日

ChromeOSは黒船OSとなるか苦労夢OSとなるか

「教育IT『GIGAスクール』の“実質勝者”Googleの衝撃データ……『対象自治体の半数を獲得』はなぜできた?」という記事を読んだ.今からもう20年ちかく前の昔話になるが,Windows一辺倒だった初等教育現場にLinuxの楔を打ち込もうとしたプロジェクトに参加していたことを思い出し,いろいろと感慨深く感じている.

日本のITベンダーにしてみれば,あるいは実際の教育現場で小中学生の教育に携わっている先生方にしてみれば,MicrosoftがGoogleに代わっただけではないか,という見方もできよう.その是非については本稿では触れない.しかし,私にとって朗報なのは,ChromeOSがLinuxベースであるということだ.

「Chromebookがlinux対応!ChromeOSのターミナルを動かしてみた!」というタイトルに若干の違和感を覚えないこともないが(なぜならば,そもそもLinuxを改造して作られたものがChromeOSだから),使おうと思えばLinuxマシン,あるいはUnixマシンとして利用できるという点はありがたい(正確にはUnixクローンであるが,細かいことは気にしない).ちょっと情報処理に興味を持った児童や生徒,学生が,自然とUnixに触れることができる,そんな環境が増えるのは大歓迎.

なぜUnixであるべきなのか

2004年に出版した拙書「リブレソフトウェアの利用と開発―IT技術者のためのオープンソース活用ガイド」の77〜78ページで,あるBBSでたまたま目にした名前も知らぬ人のコメントを紹介した.目からウロコというか,私自身が感じていたことをよくぞ言語化してくださったと感心したものだ.その本は残念ながらあまり売れなかったが,そのコメントをここでも紹介しておきたい(言葉遣いや漢字の使い方などいろいろ添削したい文章だが句読点以外は「ママ」で引用する).

UNIXには愛されて然るべき理由が有ります.
UNIX程「計算機はいかにあるべきか」が議論されるシステムは無い.そもそも生まれたのが「コンピュータ分野への進出を禁じられていたAT&T」だったことにも由来していると言える.そういう状況で作っているなら,売れるかどうかを考える必要は一切無い.コンピュータシステムとはどう有るのが正しい姿なのか.それを開発者は真剣に悩み,悟りに近いものを得た.その答えがUNIXの前身……Unicsだと言って良い.
そして,大学ではUNIXに触れた事もない情報系学生などいないだろう.多感な時期に人間の悟りのたまものをいじるのである.自分でも「計算機はどうあるべきなのか」を真剣に考えるはずだ.
このように,UNIXを使う者にとって「計算機はいかに有るべきか」は一度は考えるものだ.その結果,そこには思想なり,文化が生まれる.そして,ユーザーインターフェイスも統一され,分かりやすくなる.UNIXのユーザーインターフェイスを学ぶと言う事は,その思想,文化を追体験し,理解していくことでもある.UNIXを作った人間の思想は「OSを使うと言う事は,結局プログラミングをする事に他ならない」というものである.OSはAPIセットであるのだから,プログラミングをする以外にOSを使う術などあるわけはない.そう,これらは真理なのだ.この真理にしたがってUNIXはプログラミングをしやすい様に作られている.それしか考えていない(だから最初はunicsだった)と言っても良い.
そして,その構成は直感的ではないが秩序と論理に導かれている.使えば使う程,システムに対し理解が深まり,楽しくなるのだ.
優れたシステムとは直観的に動かなくてはならないが,コンピュータの豊富な機能をCRTの中の限られた面積,マウスの登場以前の当時の貧弱な入力機器で直観的に扱える訳が無い.次善の策としては論理的に動作する事である.
UNIXのコマンドライン環境はそれを体現していると言えるだろう.

いずれにしても,ITに興味を持つ優秀な次世代が育つきっかけになってくれると嬉しいな.

抽象的思考力を鍛えるべし

やれ三項演算子は分かりにくいだの,ラムダ式は必要ないだの,なんだかそんなプログラマの皆さん,情けなくないか?オジサンは日本の凋落原因を間近に見ているような気がして,淋しくなってきたぞ?

三項演算子や再帰的定義を説明するのにmax(a, b)だのfib(n)だの,そういう易しい例を引き合いに出しているのは,「なるたけ易しい事例をもって分かりやすく説明しよう」という親心であって,別に,これらの概念がそういう易しい事例でしか適用できないっていうわけじゃない.

hilbert = (n, m) =>

  (n > 0) ? tm.forEach(mm => hilbert(n-1, mat_mul(m, mm)))

  : [ [0.25, 0.25], [0.25, 0.75], [0.75, 0.75], [0.75, 0.25] ]

        .map(p => affine_transform(m, p))

        .map(p => [p[0]*cs.width, p[1]*cs.height])

        .forEach(p => ctx.lineTo(p[0],p[1]))

たとえばこのコード.ヒルベルト曲線を描く関数の定義である.再帰的定義,三項演算子,写像(map)とラムダ式,メソッドチェーンなど,「知ってると役立つ」プログラミングの知識がてんこ盛りになっている.ここでラムダ式は陽には出てこないけれど,map()のカッコの中って実はラムダ式の概念以外のナニモノでもない.旧態依然とした手続き型の書き方からは大きく乖離した表現なので,一見して何をやっているのかよく分からない人もいるかもしれない. 実は(詳しく説明しないが)map()とforEach()を使い分けている点にも意味があるのだ(最後に線で繋ぐときに順番が重要になってくるからである).

さらにこのヒルベルト曲線のプログラムは,フラクタルの考え方(再帰と親和性が高い),アフィン変換,行列の掛け算で連続した座標変換を表現できること(数学!)を理解していないと全体像を掴むことはできない.しかし,そのような概念をきちんと理解できていれば,実に短いコードで複雑なヒルベルト曲線を描くことができる点に驚くはずだ.

まあ,三項演算子はif…else…で置き換えても構わない.先の関数定義ではそのほうが読みやすいという人もいるだろう.しかし,それ以外の知識は,「必要ない」じゃ済まされないのではなかろうか.それらを使わずヒルベルト曲線を描くプログラムを書けと言われたら,まあ,苦労して書けないことはないかもしれないけれど,私は,そんな苦労はしたくないなあ.

つまり,本稿で何を言いたいかというと,ちょっとした学習は負担に思うかもしれないが,結局は問題解決の近道になっているはずだということである.これまで様々な先人たちが切り拓いてきた道なのだから.急がば回れというやつか.まあ,ヒルベルト曲線が描けたところでどうだという話ではあるが,世の中のシステムトラブル事例なんかを見聞きしていると,老婆心ながら,こういうちょっとした努力を避けている連中が自ら墓穴を掘っているのではないかと思ってしまう.余計なお世話かな.

2021年2月23日火曜日

Pythonの三項演算子は気持ち悪い

三項演算子の話である.簡単な例題として,2つの引数のうち大きいほうを返す関数max(a, b)を考えよう.

CやRubyなどの場合

まずは基準としてCで三項演算子を使った実装を考える.データ型は便宜上intとしよう.

int max(int a, int b) {

  return (a > b) ? a : b;

}

まあ,こんな感じかな? 

Rubyだとこんな感じになる.

def max(a, b)

  return (a > b) ? a : b

end

RubyにもCと同じ三項演算子が用意されているので,こんな形で書ける.動的型付け言語なのでデータ型が陽には出てこない点に注意されたい.

そして,JavaScriptだとこんなに簡潔に書ける.ワンライナーだ.JavaScriptも型はいらない.

max = (a, b) => (a > b) ? a : b

実はRubyだと次のようにも書ける.if文自体が値を持つので,少し気持ち悪いがこんな書き方ができる.

def max(a, b)

  return (if (a > b) then a else b end)

end

return文の次の,if文全体を括るカッコは必須である.このカッコがないと文法エラーになる.

Pythonの場合

さてPythonである.Pythonにも三項演算子があることはある.ただし,ここで示したような形ではない.Pythonで三項演算子を用いて同様の関数を定義すると,次のようなものとなる.

def max(a, b):

  return a if (a > b) else b

ああ,なんてこったぃ!/(^o^)\

Pythonの三項演算子は,「(Trueの値)if (条件式)else(Falseの値)」という実に気持ちの悪いフォーマットで定義されているのだ.

いわゆる後置の条件式と考えると,Rubyでも似たような書き方をすることができる.こんな感じで.

def max(a, b)

  return a if (a > b); b

end

ただし,Rubyにおける後置のif文でelse節は書けないので,この場合はたまたまそこでreturnしてしまうことを利用して,elseに相当する処理を次の文として書くことで類似のコードにしているのである.そして,関数の最後にreturn文を明示しなくても最後に評価した値を返すという性質を利用して,なんとなくそれっぽく書いているだけなのである(※).

しかし,これは出口が2つになってしまうため,厳密には構造化プログラミングの定義から外れてしまう問題が生じている.なによりトリッキーな書き方であり,バグの温床となりそうなこんな書き方をしてはいけない.

というわけで結論

Pythonの三項演算子は気持ち悪い.

※の説明

def max(a, b)

  return a if (a > b); b

end

このコードは次のコードと同じである.

def max(a, b)

  return a if (a > b)

  b

end

そして,このコードはさらに次のコードと同じである.Pythonの三項演算子と似ているが全く違うことを理解できるだろう.

def max(a, b)

  return a if (a > b)

  return b

end


2021年2月22日月曜日

「プログラミング言語」2021版

その昔,先輩エンジニアから「IT技術者たるもの1年にひとつくらいは新しいプログラミング言語を覚えなければダメだ」という指導を受けた.その話をいまでもときどき講義で紹介する.すると「飯尾はいったいいくつくらいのプログラミング言語を使えるのか?」という質問を受けることも. というわけで,いま私はどんなプログラミング言語を使えるようになったのだろう?と,自問自答してみた.

  1.  C
    • まずは何をさておきコレは外せない.本まで出しているくらいだから(おっと… 宣伝すみません) 
    • 日本語,英語に続いて3番目に使いこなしている言語である
  2. C++
    • これも昔は仕事でバリバリと使いこなしていた
    • C++のコードを直接コンパイルできなくて,cfrontというツールでいったんCに変換してからCのコンパイラで処理していた時代
    • ただしC++は現場を離れてから10年以上経ってしまったので,最新の状況はまったく分からない
    • テンプレートを活用したいかにもモダンC++らしいプログラムは… 書けない orz 
  3. Java
    • これも昔は(…以下同じ)
    • Javaがまだアルファ版とかベータ版とか言っていたころからのお付き合い
    • プログラミングコンテストで優勝したこともある(過去の栄光)
    • 最新動向を追えていないのはC++と同じ(さらに反省)
  4. JavaScript
    • 出てきた当時は「Javaのパチもん?」と軽んじていたものだが……
    • まさかここまで成長するとは予想だにしてなかった.ちょっと遊ぶ程度には,活用している(講義でも使っている)
  5. Shell(sed, awk等のスクリプティングを含む)
    • ちょっとしたバッチ処理に欠かせない
    • データ処理もたいがいコマンドをパイプでつないでやっちゃう
    • 少しずつ試しながらできるので作業が捗る.もっとも複雑なプログラムは書かない
    • そもそも構文からして怪しい(「[」(test)コマンドって何だよ!って,これは酷いと思いつつ使っている) 
  6. Perl
    • Shellで対応できないときはPerlの登場(だった).ただし,もっぱら使い捨てプログラム
    • あの可読性の悪さ,なんとかして!一週間前の自分は他人だよね
    • 最近はもう使ってないなあ
  7. Ruby
    • Perlの可読性が悪いことに辟易してPerlの代わりに使い始めた
    • Pythonはインデントでスコープを表すというやり方が嫌なので
    • 開発フレームワークの講義やネットワーク技術の講義でも,ちょっとしたサーバサイドプログラミングに使わせてもらっていた
    • こんどRails開発の本出します!(宣伝すみません)
  8. PHP
    • サーバサイドといえば,これか……
    • ペチパーといえるほど使いこなせてはいないかな
    • 2000年前後にとあるプロジェクトで使ったのがきっかけで,それ以来は付かず離れずといった感じ
    • 使い捨てのWebアプリ作るときにときどき使う.それなりに重宝してる
  9. Python
    • 嫌い嫌いといいつつ,便利なので使っている
    • とうとう雑誌に連載記事まで書くようになってしまった
  10. Elm
    • いま個人的に注目の言語で勉強中
    • なにか一つくらいちゃんとしたアプリ作ってみたいところ
  11. LISP
    • 私の卒論はコレ(utilisp)で書いた(本文は日本語!卒論で扱ったプログラムはLISPだったということね)
    • Emacsを使っていた時代はemacs lispなんかもよく使ってた
    • 最近はとんとご無沙汰で……人工知能論の講義でちょっと紹介してただけ(これも今はしてない)
  12. Prolog
    • まさか自分が教えることになるとは(人工知能論で扱っていた)
    • というか文学部PC教室のコンピュータにインストールされていたという事実が驚きだった
    • 論理プログラミング,これはこれで楽しいものだ
  13. R
    • プログラミング言語に入れて良いのだろうか
    • データの統計処理が必要なときに使う
    • まあ,あまりプログラミング言語らしい使い方はしてないかも
  14. Matlab
    • これも同様.データ処理でたまに使う程度
    • 実際に使う処理系はOctaveだけど
    • StanfordのAndrew Ng先生の機械学習コース(MOOCs)で多用されてた.あれは凄い
  15. Pascal
    • 大学で最初に勉強したプログラミング言語がコレだった
    • いま利用できる処理系あるのかな
  16. BASIC
    • 人生でいちばん最初に親しんだプログラミング言語
    • 懐かしくて涙が出そう……
  17. Assembler
    • これを忘れてた.短歌は読めないけど
    • DSP(Digital Signal Processor)のボードなんかも弄った経験があるので,一時期はそれなりにやってた
    • いまはもうすっかり忘れたが,昔取った杵柄で,対応はできるはず
  18. SQL
    • SQLをプログラミング言語に入れてよいものかどうか
    • まあSQLで数独を解くなんていう荒業もあるくらいなので入れさせてもらう
  19. Tcl/Tk
    • 忘れてた
    • いままだ使える処理系あるのかな.Perl/Tkでシステム書いたこともある
  20. PostScript
    • ヒルベルト曲線を描くプログラムを学生時代の演習で書いた
    • WebサーバをPSで書いた変態がいるというタレコミをいただいたのでプログラム言語として認める
  21. LaTeX
    • これをプログラム言語とするのもどうかと思うがライフゲーム書いたという記事があったので認めることにする

ちょっと怪しいのも含めて21個あった.1年にひとつ……は残念ながら達成できておらず(苦笑). あとは,ちょっとだけ齧った程度ならDだのObjective-CだのProcessing(これはJavaなのか)だのいくつか.それに,GoとかSwiftとか大手が出してくる新しい言語はチェックしとかなきゃなーという気持ちは忘れていない(なかなか時間をとれないけれど).HaskellとかScala,Lua,TypeScriptあたりも身につけておきたいところ.

そしてHTMLはプログラム言語じゃない(という見解)

FORTRAN?COBOL?これまで縁がなかった.たぶん今後も.



2021年2月20日土曜日

ElmにおけるMVCと入出力インタフェース

The Elm Architectureというものを教えてもらった.Webアプリのフロントエンド開発でよく利用されているReduxやVuexというライブラリに影響を与えたものだそうで,ふむふむ,なかなかよくできている.

Model-View-Update

まずは簡単なプログラミングの例を見てほしい.適当な文を入力してもらい,処理を実施するとその文を反転したものを出力するというシンプルなものだ.

The Elm Architectureは,モデル(Model)とビュー(View)を定義して,ビューから発するメッセージに応じてモデルを更新するというイベント・ドリブンなプログラミングモデルである.イベントに相当するものをメッセージと呼び,更新する処理をアップデート(Update)として定義する.

MVCモデルを理解している人は,このアーキテクチャもMVCモデルに非常に似ているということに気付くだろう.Controllerの代わりにUpdateと表現されているにすぎない.ほとんど同じような立て付けである.

モデルが変更されると自動でビューも更新されるので,DOMを操作してアップデートしてというような低レベルな処理をプログラマが意識する必要のない点もありがたい.このあたりの抽象化が上手に実装されている点は,イマ風のアーキテクチャだなと感心する.

具体例

この例では,Modelとして{ input : String, output : String }を与えている.2つの文字列型変数inputoutputを持つ.前者は入力された文字列,後者は処理後の結果として出力されるべき文字列である.

Viewも関数で定義されるのは面白い.中身がそれぞれHTMLのタグと対応しているので,HTMLをきちんと理解しているプログラマであれば読みこなすことは容易であろう.しかもDOMの知識を持っていなくても理解できそうだという点も興味深い.

onInputonClickというキーワードがユーザ操作とメッセージ発生を結びつけているものである.前者は文字が入力/削除される毎に発生し,その都度,モデルのinputが書き換えられているが,今回の例ではそれを意識する必要はない.メッセージが発生するとUpdate関数がそれを受け取り,受け取ったメッセージに応じた処理(case文で分岐している)を行う.メッセージがChange(テキストエリアの編集で,都度,発生する)だったらinputの書き換えを,メッセージがReverse(「reverse」ボタンのクリックで発生する)だったら文字列の反転処理を行いoutputに格納する,という処理が定義されている.

入出力インタフェースの抽象化問題

このプログラム,実質的な処理に相当する部分は「String.reverse model.input」という部分だけである.その意味では,この程度のプログラムであれば実行するために準備しなければならない部分のオーバヘッドが大きすぎるといえなくもない.

ElmはいわゆるAltJS,すなわち,JavaScriptにコンパイルされて実施される処理系である.一方,今回のような小さなプログラムならば,JavaScriptをコマンドラインで実行するjscという処理系を使えば,次のような極めてシンプルなプログラムで表現できる.

#!/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Helpers/jsc

let input, output;

input = this.readline();

output = input.split("").reverse().join("");

print(output);

このファイルをreverse.jsという名前で保存し,実行属性を付けて実際に動作させてみた例が次の例である(なお,入力するデータは日本語文字列だと文字化けしてしまうため,英文データとした).

echoコマンドを用いてパイプで流し込んだ文字列が,適切に反転されて出力されていることを確認されたい.

しかし,これをきちんと理解するためには,標準入出力の概念を理解しなければならない. readline()とprint()がプログラム側からのインタフェースになっていることの学習も必要だ.一度,理解してしまえばシンプルで分かりやすいものだが,抽象度が高いため初学者には若干難しいという問題もある.

Elmにおける実装

対してElmの場合は次のようなものとなる(余分な記述は排除した).

textarea [ value model.input, onInput Change ] []

textarea [ value model.output ] []

その実装はGUI部品として目に見えるため,ある程度は抽象化されているとはいえ具体的に理解しやすいのではなかろうか.

Webブラウザで動作させる素のJavaScript実装においてもTextArea等を用いた入出力の実装を具体的に理解することができるが,具体的すぎてDOMの理解が必要という課題が生じる.Elmが提供するインタフェースは,抽象度と具体化の度合いがちょうどよいのではないか,初学者にもすんなりと受け入れられるのではないかと考える次第である.


2021年2月18日木曜日

くじらベーコン万歳

杉浦日向子の「ごくらくちんみ」を読んだ.本書は,様々な珍味を題材とした短篇集.ていうか,ショートショート.

余談だがショートショートっていうとSFのイメージが強いのは星新一のせいだろうな.本書のような私小説に近い感じの掌編小説をショートショートと呼ぶのには,いささか違和感がないわけでもない.

ま,それはそれとして.

なかでも印象的だったストーリーが「くじらベーコン」と題したお話.短いお話なのでまるっと紹介したいところだが,全文引用すると,それって引用なのか?ってことになるので,後半をちょいとばかり引用しよう.

薄いスライスが五枚.大半を占める脂身に,先細の竹箸で切れ目を入れると,むちむちっとした手応え.胡椒を多めにつけ,醤油へ,ほんのちょびっと浸し,食べる.

「んんー.サカナじゃない,まさしく,ケモノなんだよね.あったかい血と胎生の鼓動を,感じるー」

「大袈裟だなあ.ガツンと度合いの高い原酒もらおうか.マスター,ほんっと,このベーコン,ウマー」

「わたしもおいしいとおもいます.鯨は,日本の食文化の華です」

「だよねー.残さず使い切るもんねえ.なんで鯨捕っちゃダメなん.世界の大勢が,家畜っきゃ喰わないから,鯨の恩恵を知らないんだ」

「わたし,肉の脂けっこう苦手だけど,これはイケるんだ.なんか,ひと噛みで,うわっとコクがひろがって,お口が鯨.鯨まみれのマクを張るのよ.すっごいインパクト.殴られても気持ちいいみたいな」

以上,引用終わり.

まあ杉浦日向子って「お江戸でござる」に出てきてたくらいしか実は知らなかったんだけど,実に素敵な感性の持ち主だったんだなぁと,あらためて感服した次第.享年46歳.惜しい.実に惜しい.

「ごくらくちんみ」ぜひ読んでみてください.





初学者にやさしいデータ入出力の抽象化とは

かなり昔の話になるが,SSS2015という学会で「初学者向けプログラミング教育に関する意識調査 ― GUIとCUIのどちらがよいか? ―」という発表をした.これは2つのプログラムについてGUIベースのものとCUIで提示したものとどちらが教育的であるかを検証したものであった.


その議論はかなり盛り上がり,示唆に富む意見もいろいろと頂戴することができた.SSS2015での発表と議論,皆さんから寄せられた自由回答でのコメントを踏まえてじっくり考えてみたところ,結局,GUIとCUIという対立軸はややミスリーディングであり,本質的な違いはもっと別のところにあるのではないかという結論に至った.すなわち,提示した2つのプログラム,その違いはGUIとCUIではなく,プログラム実行環境の違いにすぎないというものである.

さらにいえば,この実行環境の違いをどう捉えるか,そして,どちらを先に教示したほうが理解が進むか,という問題設定と理解すべきであった.もちろん,近年のWebシステムエンジニアになるのであれば比較的初期の段階でいずれも理解しておくべき概念であり,実際のWebシステムを実装するためにはいずれも求められる知識である(前者はフロントエンジニア,後者はサーバサイドエンジニア,という大まかな役割分担はあるかもしれないとはいえ).

インタフェースの違いをどう教えるか

ある処理X(先の論文で提示した例では「文字列の反転」)という処理を考える.プログラミング教育のごく初期段階では,プログラム内部にハードコードして変数に値を与える例で説明しても問題はなかろう.しかし,実際のシステムでは,外部とのデータ入出力が不可欠である.そこで,古いタイプ(ここでは便宜上,UNIXerを「古いタイプ」と類型する)は「標準入力」「標準出力」というインタフェースの理解を求めた.

これらのインタフェースは,データを全て文字列のストリームとして表現するという抽象化をひとたび理解すれば,ごく自然に理解できると信じられているインタフェースである.しかし,「|」(パイプ)でコマンドを結びつけることやリダイレクトの概念,あるいは,キーボードからの入力やシェルが動作している端末エミュレータへの出力が暗黙のうちに標準入出力に結び付けられているといった抽象化を理解しなければならないというハードルが存在する.

一方,Webインタフェースで示されたプログラム(新しいタイプ)では,その部分はHTMLで表現されたGUI部品で,若干ではあるが具体化されている.なぜなら,テキストエリアという目に見える「入力する場所」「出力される場所」があり,それらがプログラムの中に示されているからである.

しかし,処理Xには本質的には関係ないはずのHTMLを理解しなければならず,また.JavaScriptで記述された処理Xの本体部分とそれらのGUI部品とを結びつけるためには,DOMの概念も正しく理解していなければならない.やはり,ここにもHTMLやDOMで表された入出力インタフェースの理解が求められるているだけであり,結局のところ新しいタイプでも入出力インタフェースの理解が不可欠ということである.

まとめ

以上を整理すると,この問題は,以下の3つの観点からの比較という側面を持つといえよう.

  • 入出力インタフェースに関する抽象化レベルが,1. 高いか,2. 低いか
  • ブラックボックス化されている入出力機構は,1.「標準入出力(Unix技術)」か,2.「HTML/DOM(Web技術)」か
  • プログラムから入出力インタフェースに関する記述を,1. 極力排除するか,2. ある程度明示的に示すか

いずれも前者が古いタイプ,後者が新しいタイプである.以上を踏まえたうえで,改めて皆さんのご意見を伺いたいところ.なお,上記2つの他に,データベースに対するデータの入出力なんかも考えられるかもしれないが,いきなりそれはちょっと難しいだろう.皆さんはどうお考えになるだろうか?

参考文献

飯尾 (2015) 初学者向けプログラミング教育に関する意識調査 ― GUIとCUIのどちらがよいか? ―, 情報処理学会 コンピュータと教育研究会 情報教育シンポジウム Summer Symposium in Sakaiminato 2015 (SSS2015), IPSJ Symposium Series Vol. 2015, pp. 17-22, 鳥取 境港

2021年2月14日日曜日

無名関数とラムダ式

Excelにラムダ式が導入されたというニュースが少し話題になった.ラムダ式,よく分からない,という人のために,ラムダ式の分かりやすい活用例である無名関数を用いて説明してみよう.この記事で,少しでもラムダ式に親しみを持ってもらえれば本望である.

無名関数

いきなりだが,Wikipediaの「無名関数」からその説明を引用する(太字は筆者による).

プログラミング言語における無名関数(英語: anonymous functionあるいはnameless function)とは,名前付けされずに定義された関数のことである.無名関数を表現するための方法には様々なものがあるが,近年主流となっているのはラムダ式による記法である.

このように,ラムダ式とは無名関数,すなわち「ひとまとまりの処理だが名前が付けられていないもの」であると考えれば分かりやすい.なお,それに対して「ひとまとまりの処理でそれに名前が付けられているもの」は,皆さんおなじみの,関数とかメソッドとかサブルーチンなどと呼ばれるものである.

具体例

たとえば,単純な例だが次の関数定義を考えよう(言語はPythonとする).これは,2乗するだけの極めてシンプルなものなので,説明は不要だろう.

def square(x):
  return x * x

さて,ここで,0から4までの数字が入った配列を考える.

A = list(range(5))

この結果,変数 A には [0, 1, 2, 3, 4] という値が格納される.ここで,全ての要素を2乗したい,つまり,先の square() を配列の各要素に全部適用したいということを考えよう.数学でいえば集合Bを集合Aの各要素が2乗されたものと考えて,集合Aから集合Bに対応させる各要素を2乗する写像 A → を考えるということになる.これをそのままプログラミングとして表現するということだ.

Pythonでは map() が使える.map操作によってAsquareを適用する.結果がmapオブジェクトになるため再びlist化してやる必要があるのが若干面倒ではあるが,上の写像は次の簡単なプログラミング(square()の定義を除けば1行)で表現できる.

B = list(map(square, A))

この処理の結果,変数 B には [0, 1, 4, 9, 16] という値が入る.Pythonインタプリタを用いて確認してみよう.

ラムダ登場

ところで,ここでAだのBだのという変数を使っているが,これって後でそれらを再利用することがなければ本来は不必要だということは,明らかだろう.すなわち,list(map(square, A))は,変数名Aを陽に用いることなしに,次のように書けばよいということである.

list(map(square, list(range(5)))

または

list(map(square, [0, 1, 2, 3, 4]))

でもよい.インタプリタで確かめてみれば,これでも先ほどと同様の結果が得られることを確認できる.では,square() はどうか?これもその関数を別のところで利用することがないのであれば,名前を付けるだけ無駄である.ここでラムダ式の出番である.名前が付いた関数を無名関数で置き換えるのがラムダである.Pythonのラムダ式は

lambda (引数): 処理

と書く.これを使うと,上記の式は次のように書ける.square()の定義も不要なので,ワンライナーになってしまった.スッキリ!

list(map(lambda (x): x*x, [0, 1, 2, 3, 4]))

以上の過程をインタプリタで試してみた結果がこちらである.確認されたい.

無名関数のメリット・デメリット

本稿では,map操作を用いてラムダ式のメリットを説明した.その他にも,Cのsort系関数に渡す4つめの引数,関数ポインタで渡している比較関数のような使い方でもその効果を発揮するだろう.本来,それらの処理でも名前の付いた「関数」を渡す必要はないのだ.その処理へのアドレスが渡せれば十分のはず.しかしCにはラムダ式が用意されていないので,仕方がなく関数ポインタでコードへのアクセスを渡しているにすぎない.

冒頭で紹介したWikipediaの記事には,無名関数のメリットとして名前の衝突が起こらないという点が指摘されていた.そりゃそうだろう.名前を付けないわけだから,衝突の起こりようがない.コードをシンプルに書けるだけでなく,このようなメリットもあるということだ.デメリットとしては名前が付いていないので再帰を書くには何らかの工夫が要るとあった.それもそうだが,再帰を書くときは,素直に普通の関数をかけば良いだろう.

mapとリスト内包表記

集合への写像をプログラミングで表現する方法としてmapを紹介したが,Pythonだと「リスト内包表記」という書き方で似たようなことができる.さきほど述べた配列Aの要素を全て2乗した配列Bを求めるコードは,次のように書ける.

B = [ x*x for x in A ]

これは関数square() を用いて次のように書いても同じ結果になる.

B = [ square(x) for x in A ]

ラムダ式の構文こそ陽に出てこないものの,考え方は同じであるということを理解できるだろうか.これらの比較から,「名前は付いていないけれど,一連の処理のまとまりですよ」ということを明示的に示すものがラムダ式であると考えることもできよう.



オンラインセミナーの新しいチャレンジ

横浜ユーラシア文化館の高橋健研究員による「土偶マイムで土偶を学ぶ」という講演を聴いた.オンライン講演である.今回,ちょっと変わった試みだったのは,ZoomやWebexなどのオンライン会議ツールによるウェビナーではなく,ClusterというVR的なSNSツールを利用したものだったということだ.

図はそのスクリーンショットである.中心にいる黄色い服を来ているのが私のアバター,ステージバックには3つのスクリーンがあり,正面がプレゼンテーション用,左側にチャットが表示され,右側は,うーん何に使われたんだろう,よく分からなかった.

ステージ上,端にいる鳥?みたいなアバターが講演者の高橋氏,その他,ロボットのようなキャラクターが他の参加者(受講者)のアバターである.アバターを切替えなければデフォルトではこのロボットが現れるらしい.この画面にはたまたま映っていないが,アバターを切り替えていた参加者は私以外にも数人いた.

参加してみての感想,メリットとデメリット

さて,率直な感想は「Zoomとかでやればよかったのに.ちょっとこのプラットフォームは残念だったなあ」というものである.講演者が操作に慣れておらずいろいろと待たされる時間が多かったという点は,まあ,割り引いてあげるとして,Clusterを使わんがためのオンラインイベントだったという感想は否めない.

プレゼン内容の表現としても画面の一部しか使えてないのが残念.スクリーンショットに示されているように,プレゼン内容の画面はデバイスの1/4ほどの面積しか使えていない.ステージに近づけばもう少し大きくすることはできそうだが,中央にいる自分のアバターが邪魔になる.また,左側のチャット画面はほぼ見えなかった.さらに,他の観客のアバターが邪魔になることもあった.それを考えると,自分も他人の迷惑になっていたんじゃないかという心配もしないでもない.あえて3DのVR世界に固執せず,講演が始まったら,画面いっぱいにプレゼン画面が拡がるモードがあったほうが良かったんじゃないかなあ.

あえてこのプラットフォームを使ったオンライン講演のメリットを指摘するなら,3DのVR操作で,イベント会場をぐるりと見渡すことができるという点だろう.講演してる人にとっては観客を一望できて「どれだけの人数が来てるかな?」ってのが分かってよいかも.リアル会場で,今日はいっぱい参加してくれて嬉しいな,会場が温まっているな,とか,あー,あまり参加してないのは残念だけど,足を運んでくれた人のためにしっかり喋ろう,というような気持ちになる.まあ,オンライン講義と同じで,ネットの向こうで「本当に聞いてくれているのか」っていうのは分からないわけだけれども.