投稿者「mod_poppo」のアーカイブ

学園祭で来場者に複素関数を教えた話

11月22日から24日にかけて行われた東京大学駒場キャンパスでの第65回駒場祭で、数学科有志による「ますらぼ」企画(@UTmathlabo)に参加していました。「ますらぼ」では、数学科生・院生による発表、我々で作った冊子の配布、それから数学に関する展示が行われていました。

私は、かねてから作っていた複素関数を視覚化するWebアプリケーション “Conformality” に関する記事を書いたり、展示をしたりしていました。

冊子には、いくつかの複素関数の例・解説と、Webアプリの舞台裏に関する記事を書きました。一方、展示では、いくつかの複素関数の例・解説をポスター(というほどの紙の大きさでもない)で貼ったのと、パソコンとタブレットを用意して実際にWebアプリを動かしながら解説するのをやりました。

来場者に解説するとき、聞き手のレベルに合わせて話して、分かってもらうのは楽しかったです。実際どのぐらい理解してもらえたかは不明ですが…。あと、ふだんあまり喋らないので声が枯れました。

具体的に、レベルに応じてどんな内容を話したかというと、

小学生(!)

  • そもそも0や負の数はまだ習っていないので、まずはそこから。
  • 複素数の足し算が平行移動になることを説明できれば十分すぎるだろう。

中学生

  • 実数はOK。「数直線の数」みたいな感じ。
  • 複素数を紹介。いずれ高校で習うよ、ということで。
  • 複素数のかけ算ぐらいまでは解説しただろうか?
  • 「関数」としては \(y=ax^2\) ぐらいがいいとこだったかな?と思ったが、中学校では「関数」として「一次関数」というのが出てくるのを失念していた。

高校生

  • 現行の学習指導要領では数学IIIで複素数平面を扱う。複素数自体は、もっと前の2次方程式関連のところで出てくるはず。(高校では「複素数平面」というようだが、数学が専門の人は普通は「複素平面」と言う。私のような面倒くさがりな人には1文字少ないのはでかい)
  • 学年としては、3年生は複素数平面知っているはず。2年生の11月では複素数平面をやっている学校があるかないか、という感じ。聞いてみたところ「明日(火曜日)から複素数平面の単元に入る」という人もいた。
  • 事前に書店などに出向いて数学IIIの参考書を立ち読みしたところ、高校で扱うのは(今回関係ありそうなのは)複素数のかけ算の図形的な意味やド・モアブルの定理がせいぜいだということが分かった。
  • 今は高校で行列を教えないので、一次分数変換と行列の関係を教えにくかった。
  • 高校では実数の指数関数や三角関数を習う。

大学生

  • 複素数や複素平面はまあ知っている(1、2年生や、文系の3、4年生も含めて)。
  • 理系の3、4年生には一次分数変換の円円対応や正則関数の等角性まで知っている人もいて話が早かった。

という感じでした。

教える関数としては、当初は一次分数変換が一番単純かなあと思いましたが、高校生を視野に入れるなら複素数のかけ算(拡大縮小と回転)からやった方が学習の役にも立つだろうと思って、冊子やポスターでは最初に複素数のかけ算の例を載せました。しかし、実際に人に教えるときはもっと初歩的な、複素数の足し算の幾何学的意味(平行移動)から始めたので、他人への解説の仕方というのは自分だけで考えてもわからないものだということを認識しました。

解説内容はそのうちこのブログかどこかに載せたいと思います(時間があれば)。

余談として、「ますらぼ」の教室では学内無線LANが使えないので、Webアプリケーションを動かすには工夫が必要でした。持ち込んだ機器は

  • MacBook
    • 解説の際の主力。
    • ペアレンタルコントロールを設定したアカウントでWebブラウザを動かした。
    • セキュリティースロットにワイヤーをつけて盗まれないようにした。6年半前にこのMacBookを買ってから初めてセキュリティースロットが活躍した。
  • Nexus 7
  • AirMac Express
    • Nexus 7とMacBookを同一ネットワークにつなげた。

で、MacでWebサーバーを動かしてWebアプリケーションを動かす感じにしました。URLは本来の “https://miz-ar.info/webapp/conformality/” で動いているように見せたかったので、MacBookとNexus 7で d-poppo.nazo.cc がMacBookのIPアドレスに解決されるようにしました。

ドメイン名に対して好き勝手なIPアドレスを割り当てるためには /etc/hosts をいじるのが手軽な方法だと思います。しかし、Androidの場合は /etc/hosts をいじるにはroot権限を取る必要があり、調べてみたところ思いの外危なそう&面倒くさそうだなあと思ったので、代わりに手元でDNSサーバーを動かすことにしました。MacBookにはDNSサーバーのソフトウエア(BIND9)が搭載されていた(最新のOSXにはないらしい)のですが、駒場祭直前にBIND9の使い方なんて覚えられない…。と思っていたらWebminとかいう便利なツールがあることを知ったので軟弱者の私はそれでBIND9を設定しました。めでたしめでたし。

タブレット端末からのリモートデスクトップでWindowsのタッチ操作を試す

最近のWindowsはタッチ操作に対応している。が、タッチに対応したディスプレイなんて持っておらず、わざわざ買うほど必要性も感じない。そういう場合に、iOS/Android端末と、リモートデスクトップ接続を受け付けることができるWindowsを持っていると、Windowsのタッチ操作を試せる。

今回のWindows 8.1を買う前の下調べで、(無印とProの違いの一つである)Windowsのリモートデスクトップ機能についてググっていたところ、「iOS/AndroidタブレットからリモートデスクトップでWindowsにつなぐと、タッチ操作ができる」という情報を見かけた(このへん)。そういうことなら、リモートデスクトップができるPro版を買うしかない。と思って、無印よりも数千円高いPro版のWindows 8.1を買ったのだった。

以下、iPadからリモートデスクトップでWindows機を操作するまでの手順。

Windowsの設定でリモートデスクトップを有効にする

コントロールパネルで
システムとセキュリティ > システム > リモートアクセスの許可
とクリック。
remotedesktop-step1

リモートデスクトップのオプションで、「このコンピューターへのリモート接続を許可する」をクリック。
remotedesktop-step2

なんかメッセージが出るので「OK」を押す。
remotedesktop-step3

これで、リモートデスクトップが有効になった。
remotedesktop-step4

iOS端末/Android端末にMicrosoft純正のリモートデスクトップクライアントを入れる

インストールが終わったら、起動して適当に設定してやる。

遊ぶ

リモートデスクトップでつなぐと、画面サイズはクライアント側で指定したものになる。iPadからつなげばiPadの画面サイズになる。画面の向きは、横向きで固定のようだ。

「コンピューターの基本的な情報の表示」を見ると、「ペンとタッチ」の項目は「10タッチポイントでのタッチ(制限あり)のサポート」となっている。「制限あり」とあるがどこが制限されているのかはよく分からない。
IMG_0065

みんな大好きな「ペイント」では、ブラシツールを使って複数点同時に描くことができるようだ。IMG_0066

SVG pathの楕円を描くコマンドが使いにくい

SVGとはScalable Vector Graphicsの略で、2次元のベクター画像を記述するためのXMLベースの言語である。詳しくはググれ。

ベクター画像を構成する要素は、線分とか円とかベジエ曲線とかいろいろある。SVGでこれをどう表すかというと、例えば線分だとline要素を使い、円だとcircle要素を使う。SVGにはこの他にpath要素というものがあって、描画のコマンドを文字列で指定して複雑な曲線を描ける。線分とか円の弧のような単純なやつも描ける。

例を見てみると、

M 100 100 L 300 100 L 200 300 z

というコマンドを与えると、始点(100,100)から(300,100)に線分を描き、そこから続けて(200,300)に線分を描く。最後に、(200,300)から始点に線分を描いてパスを閉じる。この M とか L とか z とかいうのが描画コマンドで、それぞれ move to, line to, close path を意味する。2次元の描画を行うプログラムの経験がある人にはおなじみだろう。

描画コマンドには他にも2次あるいは3次のベジエ曲線を描くもの、楕円の弧を描くものがある。この楕円の弧を描くコマンド(A / a)が曲者で、楕円の指定方法が個性的だった。

このコマンドに与えるパラメーターは、楕円の形状に関する物が3つ、弧の終点(始点は current point を使うので、わざわざ指定する必要はない。指定したい場合は先に move to コマンドを実行する。)、そして、弧の端点と楕円の位置関係を指定するフラグが2つだ。楕円の中心は明示的に指定できない。

フラグが2つもある時点で嫌な予感がする。場合分けとか面倒くさそう。そんなことを感じながら、自前のSVGを出力するライブラリ(と言ったら大げさか)を実装・バグ取りしていたが、なぜか円全体が描けない。おかしい。と思ったが気が付いた。

始点と終点が一致していると、楕円の中心が一意に定まらない。つまり、SVG pathの A コマンドでは1回で楕円を描けない。SVGの楕円に類する物を描く描画コマンドは他にないのに…。

ググってみたら、Stack Overflowの質問を見つけた。
Circle drawing with SVG’s arc path – Stack Overflow
要するに、SVG pathで楕円全体を描くには、楕円の99.99%の弧を描いて満足するか、2個のコマンドで楕円を分割して描かないといけない。腐った仕様だ。

ちなみに、PostScriptの仕様をちらっと見た感じでは、PostScriptで円弧を描く arc コマンドは円の中心と半径、始点と終点の角度を指定する仕様だった。HTML5 Canvasの2D Contextも同様だ。(これらには楕円を描くコマンドはないが)

自作PCにWindows 8.1を導入した (2)

前回: 自作PCにWindows 8.1を導入した

Arch LinuxとWindowsのデュアルブート

自分がArch Linuxを入れる時に使ったブートマネージャーはrEFIndだった。そのコンピューターに追加でWindowsを入れると、Windows Boot Managerがハードディスクのどこかにインストールされてそれが使われるようになる。が、それだと起動時にOSを選択できないので、ブートマネージャーの選択をrEFIndに戻す。ブートマネージャーを選ぶには、ファームウエア(UEFI?)の側でブートデバイスを選ぶ要領でやればよい。自分が使っているGIGABYTEのマザーボードだと、電源投入直後にF12を押すとブートデバイスを選択する画面が出るので、そこでrEFIndを選択した。

rEFIndの画面には、起動できるOS(今は2種類。OSのインストールDVDを入れるとそれも選択肢に現れる)の一覧が表示されるので、それで選べばよい。

ハードウエアクロック

Arch Linuxをインストールした時、ハードウエアクロックはUTCで設定したが、Windowsではデフォルトで地方時(local time)を使う(?)ので、日本だと9時間ずれた時間がWindows上に表示される。

この問題については、Arch Wikiの記事に書いてある(日本語記事)。記事に従ってレジストリをいじればよい。Windowsによる時刻同期は、よくわからないが切った方がいいらしい。

ソフトウエアのインストール

コマンドラインで使えるWindows向けのパッケージマネージャーであるところのChocolateyを入れてみた。そうすると、管理者権限のあるコマンドプロンプトとかPowerShell上で

choco install virtualbox
choco install GoogleChrome
choco install gimp

という具合でソフトウエアを導入できる。便利。

デュアルブートじゃなくて仮想化で同時に使いたい

先に書いたように、起動時にWindowsかArch Linuxかを選択すれば、どちらか一方のOSを起動できる(デュアルブート)。が、時代は仮想化だ(?)。Windowsを立ち上げつつLinuxも使う、あるいはその逆をやりたい。それも、新しく仮想マシンにLinuxをインストールするのではなく、既に物理ハードディスクにインストールしてあるLinuxを使いたい。

普通、仮想化ソフトウエアでOSを動かすときは、ゲストOS用のハードディスクの実体はホストOSのファイルシステム上に作られる数十GBのファイルになっているが、その代わりに物理ハードディスクを直接ゲストOSに割り当てたい。

VirtualBoxの場合はこの辺の手順でそれができるらしい。が、なぜかうまくいかなかった。どういうエラーが出たかは覚えていない。

そういえば今回インストールしたのは8.1 Pro (x64)なので、Hyper-Vというやつが使えるはずだ。試してみようということで、
コントロールパネル > プログラム > プログラムと機能 > Windows の機能の有効化または無効化
でHyper-Vにチェックを入れ、再起動。この辺の記事を参考に設定しようとしたが、物理ディスクをオフラインにする手順のところで詰まった。具体的には、
コンピューターの管理 > 記憶域 > ディスクの管理
で、Arch Linuxが入っているディスク0をオフラインにしようとしたら、「現在のシステムディスクまたは BIOS ディスク 0 上のディスク属性は変更できません。 」というエラーが出た。EFIが入っているディスクだからダメなのか。よくわからん。

続きはまた今度。

IIJmioの格安SIMを1ヶ月間使ってみた感想

IIJmioの格安SIMを買ってから1ヶ月が経ったので、実際に使って生活した感想を書く。

端末

結局Pocket WifiのGL02Pで使い続けている。前の記事でも書いたように、この端末はSIMフリーで、APNを設定すればドコモのMVNOでも使える。SIMの大きさは標準SIMだが、microSIMでもアダプタなしで騙し騙し使える。自分の生活圏では、ほとんど3Gしか掴まない。LTEの表示が出る場所(つまり、ドコモのLTEの1.7GHz帯の電波が飛んでいる)も一部にはあるようだ。

OLYMPUS DIGITAL CAMERAOLYMPUS DIGITAL CAMERAOLYMPUS DIGITAL CAMERAスクリーンショット 2014-11-06 0.17.43

利用状況

家にいる時は家の固定回線があり、大学にいる時は(建物によっては)学内無線LANが使えるので、モバイル回線にお世話になるのは、このどちらでもない場所となる。駅や電車内とか。ただし、電車通学ではないので通学中は使わない。

というわけなので、普段の生活の中で、家と大学だけで過ごす日はまったくモバイル回線を使わない。そういうわけで、日によってばらつきが大きく、(b-mobileやOCNにあるような)高速通信の容量が1日あたりで決まっているプランよりも、今回選んだ、高速通信の容量が1ヶ月あたりで決まっているプランの方が向いている。

利用量は多い日で100MBを超える程度。まったく使わない日も多いので、先月は一ヶ月の利用量が2GBに届かず、700MBくらい余った。なので、常に高速通信ONで問題なさそうである。まあ、これは外出先で容量を食うサービス等を利用していないからだろう。動画の視聴や、リモートデスクトップ、VNCはやっていない。外出先でのアプリのアップデートは避けたいと思っている。

今後

これからどうするか。先の記事にも書いたように、今持っている端末がアレなので、新しい端末を入手したい。iPhoneを買うか、Android端末か、モバイルルーターか。

自分の中ではNexus 5が有力候補だったが、調べたところFOMAプラスエリアに完全対応していないようで、そこが不安要素になっている。

あと、メインのドコモ回線をどうするかも悩む。今はFOMA契約で、ガラケーで使っているが、今後どうするか。

日記終わり。

自作PCにWindows 8.1を導入した

1年半前にパソコンを自作したのだが、今まではLinux (Arch Linux)だけを入れて使ってきた。だが、何となくWindows環境の必要性を感じたので、Windows 8.1 Pro (DSP版)を買ってきてインストールすることにした。無印じゃなくてProにしたのは、リモートデスクトップを使いたいというのが主な理由だ。

そのパソコンに入っているHDDは手持ちの物の再利用(前はMacBookに入っていたが、容量が狭くなり換装したので余った)で、潤沢に容量があるというわけではなかったので、HDDも新しいのを買った。

インストールだが、特に何の問題もなかった。DVDから起動して、(新しく導入した)HDDを選択して、おわり。Microsoftアカウントの名前はローマ字にしていたので、ホームディレクトリの名前はローマ字になった。

とりあえず導入したソフトウエアは

  • Firefox
  • Dropbox
  • iCloud for Windows
    • ついでにBonjourが入るので他の端末から ホスト名.local で参照できるようになる

で、明日以降もっとほかのソフトウエアとかも入れて環境を整えたい。

…と思ったが、Arch Linuxを起動できるか確認していない。Arch Linuxの時はrEFIndを使っていたが、WindowsのUEFI事情はよく分からない。明日以降なんとかしたい。Arch Wikiのこのへんが参考になるだろうか。

GIMPとゲームパッド on Linux

フリーのペイントソフト、GIMPをゲームパッドで操作したい。いわゆる「左手デバイス」とかいうの。まあ自分はそんなにお絵描きするわけじゃないんだけど。

ここの話はLinuxでの話で、WindowsとかOS Xとかは知らん。

手持ちのハードウエア

  • パソコン(自作のLinux機)
  • USBゲームパッド(エレコムのやつ)
  • ペンタブ(Wacom Bamboo CTH-661)(今回の主役ではない)PA250017

試した手順

1. メニューの「Edit > Preferences」を選択。

GIMP: Edit > Preferences

2. Preferences ダイアログの Input Devices > Input Controllers を選択

GIMP: Preferences > Input Controllers

3. Available Controllers の Linux Input を選択し、→ボタンで Active Controllers に追加。

GIMP: Configure Input Controller

4. Configure Input Controller ダイアログが出てくるので、Deviceとして PC Game Controller を選択。

GIMP: Configure Input Controller (PC Game Controller)これで、

  1. Grab eventをクリック
  2. ゲームパッドのボタンを押す
  3. Actionを割り当て

という感じでゲームパッドのボタンにGIMPの操作を割り当てることができる…と期待したがそうはいかなかった。ゲームパッドのボタンを押しても何も起こらない。Dump events…にチェックを入れてターミナルの出力を見ると、ボタンを押した事自体は認識されてはいるようだ。なぜだ。

GIMPのソースコードをいじる

しかたがないからGIMPのソースコードを見ていじくろう。GIMP Developer WikiHacking:Building/Linuxを参考にして、ソースコードをgitでチェックアウトする。

Linux Inputに対応するソースはどこだろう。gimp/modules/ が怪しい。見てみると、gimp/modules/controller-linux-input.c というソースファイルがある。これか。

ファイルの頭の方に static const LinuxInputEvent key_events[] という変数の定義がある。Configure Input Controllerダイアログに出てきたボタンの名前はこれか。ゲームパッドのキーを押したときにターミナルに出てくるログと、<linux/input.h> で定義されている定数の値を参考にしながら、BTN_*** に対応する定義を追加する。

差分としてはこんな感じになった。

diff --git a/modules/controller-linux-input.c b/modules/controller-linux-input.c
index 8759d10..de72332 100644
--- a/modules/controller-linux-input.c
+++ b/modules/controller-linux-input.c
@@ -81,8 +81,20 @@ static const LinuxInputEvent key_events[] =
{ BTN_GEAR_DOWN, "button-gear-down", N_("Button Gear Down") },
#endif
#ifdef BTN_GEAR_UP
-  { BTN_GEAR_UP,   "button-gear-up",   N_("Button Gear Up")   }
+  { BTN_GEAR_UP,   "button-gear-up",   N_("Button Gear Up")   },
#endif
+  { BTN_TRIGGER,   "button-trigger",   N_("Button Trigger")   },
+  { BTN_THUMB,     "button-thumb",     N_("Button Thumb")     },
+  { BTN_THUMB2,    "button-thumb2",    N_("Button Thumb 2")   },
+  { BTN_TOP,       "button-top",       N_("Button Top")       },
+  { BTN_TOP2,      "button-top2",      N_("Button Top 2")     },
+  { BTN_PINKIE,    "button-pinkie",    N_("Button Pinkie")    },
+  { BTN_BASE,      "button-base",      N_("Button Base")      },
+  { BTN_BASE2,     "button-base2",     N_("Button Base 2")    },
+  { BTN_BASE3,     "button-base3",     N_("Button Base 3")    },
+  { BTN_BASE4,     "button-base4",     N_("Button Base 4")    },
+  { BTN_BASE5,     "button-base5",     N_("Button Base 5")    },
+  { BTN_BASE6,     "button-base6",     N_("Button Base 6")    },
};

static const LinuxInputEvent rel_events[] =

あとは、さっきのWikiの手順にしたがってGIMPをビルドする。すると、さっきスクリーンショット付きで説明した手順で、ゲームパッドのボタンにGIMPの操作を割り当てることができる。

とりあえず気づいた点は、ボタンを押すときと離すときで2回操作が実行されるのと、ゲームパッドのボタンじゃなくて倒すやつには反応しないこと。既存のソースコードの見よう見まねじゃなくて、ちゃんと調べてコードを書かないといけない気がする。そもそもこのLinux Inputというやつはどのぐらい使われているんだろうか。これは意図した動作なのだろうか。

あと、自分の手持ちのゲームパッド1個で試したが、他のゲームパッドではどうなるのか。この辺の問題が解決したらパッチを投げるかもしれない。その前に開発コミュニティーの雰囲気とかつかんでおきたいが。パッチを投稿するにはBugzillaにBug(?)を登録してそれに添付する感じだろうか。この辺の手間を思うに、GitHubのPull Requestという仕組みは偉大だ。

ペンタブのパッド(ペンタブの感知するエリアの横についてるボタン)に対する操作も、Linux Inputで扱えそうな雰囲気を感じたが、Wacomのドライバと競合するのか知らないがなにかうまくいかない。

IIJmioの格安SIMを買った

いままでイーモバイル(最近Y! mobileになったけど)のLTE回線でPocket WiFiを使ってきたけど、その2年契約が切れるのを機に、最近流行の格安SIMを使ってみることにした。

ドコモのMVNOでいわゆる「格安SIM」を提供しているのはb-mobileをはじめとして数社あるが、今回選んだのはIIJmioのデータ専用プラン。これまで使ってきたイーモバイルのデータ専用回線から移行するので、音声通話やSMSは必要ないと判断した。IIJmioを選んだ理由は、

  • 最近増量されて一番安いプランの高速データ通信容量が2GBになった。他社と比べてお得?(そこまで徹底的に調べたわけではないけど)
  • 対応した端末を使えばIPv6が使える!(21世紀になって十数年も経ったんだからいい加減IPv6を使ってもいいよね?)

あたり。まあ2年縛りとかはない(IIJmioの場合は高々2ヶ月程度の最低利用期間があるけど)ので、他社のが良いと思ったら気軽に乗り換えられる。

購入方法は、家電量販店で「IIJmioウェルカムパック」を買ってウェブで登録することにした。物理的な店舗で買えば、SIMカードが送られてくるのを待つ必要がない。買って帰って登録すればすぐに使えるようになる。また、月額料金とは別に初期費用的な感じでSIMカードが3000円ちょいするが、量販店だと定価より安く買える可能性がある。ビックカメラで買えば無料でWi2の公衆無線LANが使えるらしいが、まあ別にいいかなと思って普段使っている量販店で買った。

端末は、とりあえず手持ちの端末で使うことにした。手持ちの端末は

  • ドコモの古いAndroidスマートフォン
    • 古いやつなのでLTE非対応。
    • MVNOのSIMだとテザリングができない。
    • SIMカードのサイズはmicroSIM。
  • Pocket WiFi GL02P
    • 今までよく知らなかったが、イーモバイルの端末(最近の物を除く)は基本的にSIMフリーらしい。なのでドコモのSIMカードを挿しても通信できる。
    • ただし、ドコモの一部周波数帯に非対応。山間部で強い味方となるFOMAプラスエリアも使えないらしい。
    • 他のモバイルルーターに対してこれといった優位点はない。自分の手持ちっていうだけ。
    • まるまる2年使っているわけなのでバッテリーがへたっている。モバイルブースターなしでは使えない状態。
      • SIMカードのサイズは標準SIMなので、microSIMとかnanoSIMで使う場合はアダプターが必要。

あたり。まあそのうち良さげなモバイルルーターとか買うと思う。タブレットを買う時にLTEモデルを買っておけば良かったかなあと思ったり。

IPv6を使うには、端末として

  • Nexus 5/7みたいな一部のスマートフォン・タブレット
    • SIMロックされたものを含む多くのスマートフォンが、IPv4とIPv6を選べないらしい。
  • モバイルルーターだと、NECのAterm MR03LN (および旧機種?のMR02LN)
    • Aterm MR03LNは現時点のSIMフリーなモバイルルーターとしてはトップクラスに評判がいいっぽい。
    • Aterm MR03LNはBluetooth PANによるテザリングができる。Bluetooth DUNと違って、iPad/iPod touchでも使える。(iPhoneはネットワークアクセスを提供する側の機能しか実装されていないので使えないらしい。参考
  • ドコモの一部の通信端末でも使えるらしい?参考(2年前の記事だけど)

が必要らしい。IIJmioによる接続確認端末の一覧がここにある。

下調べはこれぐらいにして、実際に使ってみた感想だが、特筆すべきところはなかった。普通に期待通りというか。GL02Pで電波の掴みが悪いのは周波数帯のせいなのか自分の家の電波環境が悪いのか。ドコモのスマートフォンでテザリングができないので、主にモバイルルーターで使うことになるだろうか。日記終わり。

Cabal sandboxのメモ

Cabalを使ってHaskellのパッケージ管理をやっていると、依存関係がもつれて酷い事になる。あるプロジェクトで使うパッケージと別のプロジェクトで使うパッケージが干渉したりとかなんかそういうアレだ。こういう時はsandboxを使うと良いらしい。マニュアル

自分のプロジェクトのディレクトリで

$ cabal sandbox init

を実行すれば、新しいsandboxができる。何かパッケージを入れようと思ったら、そのディレクトリで普通に

$ cabal install ほげほげ

を実行すればそのパッケージはそのディレクトリに入る。

sandbox内のパッケージを使ってghciを起動したい場合は、

$ cabal repl

を使う。

sandbox内のパッケージを使ってghcやrunghcなどのコマンドを叩きたい場合は、1.20.0で追加された(?)execコマンドを使うといいようだ。

$ cabal exec ghc -- --make hogehoge.hs

この記事はcabal-install 1.21.0.0の時点の情報をテキトーに調べた結果を書いたので、もしかしたらもっと正しい使い方とかあるのかもしれないが、そんなもん知らん。

(9月21日: typoを修正)

TypeScriptで組み込みオブジェクトを拡張できない

最近、自分で書くWebアプリ、ブラウザアプリには、JavaScriptの代替言語としてTypeScriptを使っている。

TypeScriptの気に入っている点は、

  • 静的型がついているので、変数名のタイポのような、初歩的だけど実行してみないとわからない面倒なバグをコンパイル時に検出できる
  • 文法やセマンティクスがほぼJavaScriptの上位互換なので、すでにJavaScriptを習得している身としては学習コストが低い
  • JavaScriptの資産を活用しやすい
  • 標準の型定義に入っていないブラウザの拡張API等にも、自分で型定義を書けば利用できる

あたりである。逆に、不満があるとすれば

  • セマンティクスがJavaScriptに沿ったものなので、演算子オーバーロードのようなJavaSciptに1:1で翻訳できない機能が使えない
  • 型クラスとかがない
  • ECMAScript 6で導入される予定の、letや分割代入やジェネレーターなどの、言語の文法に対する拡張に対応していない(新しいラムダ式のような一部の機能は既に導入されているので、将来的には入るかもしれないが)

あたりであろうか。まあ不満があったら他のaltJSを使えばいい話だが。

[2015年1月18日 追記] 以下の内容はTypeScript 1.4のリリースに伴い古くなりました。詳しくはこちら

ECMAScript 6で導入されるライブラリ関数は、一部は型宣言を書いてやることでTypeScriptからも使えるようになる。例えば、前の記事で Math.hypotMath.sinh などの関数に触れたが、それらは[sourcecode lang=”js”]
interface Math {
hypot(…values: number[]): number;
sinh(x: number): number;
}
[/sourcecode]のような宣言を書いておけば、コンパイルが通るようになる。まだこれらの関数を実装していないブラウザ用に、polyfill(shim)も書いておくか、読み込むといいだろう。

このほか、例えば、Array.prototype.find の型宣言は[sourcecode lang=”js”]
interface Array<T> {
find(callback: (element: T, index: number, array: T[]) => boolean, thisArg?: any): T;
}
[/sourcecode]というふうにできる。

ここまではいい。

JavaScriptのイディオムとして、配列ライクなオブジェクトを変換するのに、Array.prototype.slice が使われる。もちろんこのイディオムはTypeScriptでも使えるが、Array.prototype の型は Array<any> となっているので、要素の型に対する型チェックや型推論が働いてくれない。幸い、ECMAScript 6では、Array.from という関数が導入される予定なので、こいつの型を[sourcecode lang=”js”]
from<T>(arrayLike: {[n: number]: T; length: number}): T[];
[/sourcecode]のように宣言してやれば型推論とかが効いて便利なはずだ。

だがしかし。組み込みの Array オブジェクトの型は標準の lib.d.ts において[sourcecode lang=”js”]
declare var Array: {
new (arrayLength?: number): any[];

prototype: Array<any>;
}
[/sourcecode]のように宣言されている。こいつに from メソッドを追加しようとして自分のコードで[sourcecode lang=”js”]
declare var Array: {
from<T>(arrayLike: {[n: number]: T; length: number}): T[];
}
[/sourcecode]と書くとエラーが出る。既存のメソッドも書かないとダメかと思って[sourcecode lang=”js”]
declare var Array: {
new (arrayLength?: number): any[];

prototype: Array<any>;
from<T>(arrayLike: {[n: number]: T; length: number}): T[];
}
[/sourcecode]と書いてもエラーになる。モジュールならばどうかと思って[sourcecode lang=”js”]
module Array {
from<T>(arrayLike: {[n: number]: T; length: number}): T[];
}
[/sourcecode]と書いてもエラーになる。組み込みの Array オブジェクトの型は lib.d.ts で書かれたものから変更できないのだ。

だがちょっと待て。Math オブジェクトは自前で拡張できたではないか。これは何でだったかというと、Math オブジェクトは[sourcecode lang=”js”]
interface Math {

}
declare var Math: Math;
[/sourcecode]という風に定義されていて、Math インターフェースにメソッドを追加すれば Math オブジェクトを拡張できたのだ。Array も[sourcecode lang=”js”]
interface ArrayConstructor {
new (arrayLength?: number): any[];

prototype: Array<any>;
}
declare var Array: ArrayConstructor;
[/sourcecode]と定義されていれば良かったのに。Array だけではなくて、Object, Number, String 等の組み込みオブジェクトも同じ問題を抱えている。

ググってみたらすでに同じ問題で悩んでいる人がいた。

最初のStack Overflowの回答によると、「自前の lib.d.ts を用意しろ」らしい。つらい。

[2015年1月18日 追記] 以上の問題点はTypeScript 1.4のリリースにより解決しました。詳しくはこちら