2011年3月30日水曜日

Ustream から ニコストリーム を開く ブックマークレット

1. ブックマークレットの使い方

  1. ust2nst」のリンクをブラウザのブックマークに保存する。 ( D&D )
  2. Ustream において特定の配信を見ている状態で、保存したブックマークを押すとニコストリームが開く。

 

2. ニコストリームで Ustream を視聴する

ニコニコ動画 で特徴的なコメントの表示方法は、慣れてくると案外読みやすい。これに対し、Ustream は動画の横に Twitter の投稿が表示されるので今一見にくい。

これを解消してくれるのが ニコストリーム というサービス。

「ニコストリーム」はUstream動画上にTwitterのコメントをニコニコ動画風に表示して楽しめるサービスです。

( ニコストリーム - Ustream×Twitterでニコニコ風に再生 より )

Ustream 本家とニコストリーム を比較したら、コメントが流れる速さの違いに驚いた。

CropperCapture[138]

ニコストリームの方が見やすいので、これからはここで見ることに。

 

3. ブックマークレットの内容

JavaScript を圧縮する前のコードは以下の通り。

var l = location,
        url = l.protocol + "//" + l.hostname + l.pathname
        ns = "http://nicostream.info/search?key=";
l.href = ns + encodeURIComponent(url);

 

関連記事

2011年3月27日日曜日

Firefox のアドオン KeySnail で「ブックマークレット」にホットキーを設定 - Google Bookmarks への投稿するウィンドウを呼び出す

1. 「ブックマークレット」をショートカットキーで呼び出したい

Firefox 4 へ移行  したことにより、Google Bookmarks を利用するためのアドオン GMarks が使えなくなった。

その代わりに本家サイトに用意されている ブックマークレット を使い、ブックマークをすることにした。

SnapCrab_No-0953

しかし、マウスでブックマークをクリックするのは面倒。 (+_+) ブックマークレットにショートカットキーを割当てたい。

追記 (2011.3.30) : Gmarks が Firefox 4 に対応してれた。

 

2. KeySnail でショートカットキーを割当てる

ブックマークレットは、JavaScript で記述されている。

アドオン keysnail の機能は、JavaScript に対して、ショートカットキーを割り当てることができる。

あらかじめ用意されたコマンドだけでなく、 JavaScript を使ってオリジナルの関数を書き、それらを 自由なキーの組み合わせ に割り当てることが可能です。

そこで、Google Bookmarks のブックマークレットを、 keysnail を使い、ショートカットキーを割当てることにした。

 

KeySnail のインストールと初期設定

GitHub より keysnail をアドオンに D&D することによりインストール。

最初に起動したとき、設定ファイルを新しく作成する。

CropperCapture[130]

保存場所を尋ねられるので、複数の PC で設定を共有したいので、Dropbox 上を作成先に指定。

デフォルトのキーバインドは、

「とにかく Emacs」

にした。必要なければ、「キーバインドの設定なし」を選択。

CropperCapture[131]

 

キーバインドの設定

メニューより、

  • ツール > KeySnail > 設定ダイアログを開く

を選択。「キーバインド」において、「追加」ボタンを押して「オリジナルのコマンド」を選ぶ。

モードを

View

にして、コマンド名を適当に付ける。

キーは Firefox でブックマークをするときの動作を上書きするために

C-d

を割当てた。

CropperCapture[137]

 

ブックマークレットをキーバインドに設定

次に、上図の「編集」ボタンを押す。

公式のGoogle ブックマークレットの JavaScript の内容は、以下の通り。

javascript:(function(){var%20a=window,b=document,c=encodeURIComponent,d=a.open('http://www.google.com/bookmarks/mark?op=edit&output=popup&bkmk='+c(b.location)+'&title='+c(b.title),'bkmk_popup','left='+((a.screenX||a.screenLeft)+10)+',top='+((a.screenY||a.screenTop)+10)+',height=420px,width=550px,resizable=1,alwaysRaised=1');a.setTimeout(function(){d.focus()},300)})();

これをキーバインドに設定するために、 一部を修正した、以下のコードを貼り付け、「変更の反映」ボタンを押して OK 。

function (ev, arg) {
    var a = window,
        b = a.content.document,
        c = encodeURIComponent,
        d = a.open(
	    'http://www.google.com/bookmarks/mark?op=edit&output=popup&bkmk=' 
		+ c(b.location) 
		+ '&title=' 
		+ c(b.title)
	    , 'bkmk_popup'
	    , 'left=' 
		+ ((a.screenX || a.screenLeft) + 10) 
		+ ',top=' 
		+ ((a.screenY || a.screenTop) + 10) 
		+ ',height=420px,width=550px,resizable=1,alwaysRaised=1');
    a.setTimeout( 
	function () {
	    d.focus()
	}
	, 300)
}

これでブックマークをしたいページで

Ctrl + d

でブックマークできるになる。

 

ブックマークレットの修正点について

上記ブックマークレットで修正したのは、以下の点。

URL 最初の

javascript:

を削除。

decodeURIComponent により文字列をデコード。

全体を囲っている

(function(){  ...  })();

を削除。 ( cf. JavaScript の無名関数に引数を与える )

document.location

でブックマークしたいページの URL を取得できなかったので、代わりに

window.content

経由でアクセス。

 

3. Emacs 風にしたときの操作の注意点

検索をするとき、

  1. 新しくタブを開いて ( Ctrl + t ) 、
  2. 検索バーにフォーカスを移そうと Ctrl + K を押しても、

ロケーションバーにフォーカスが移ってしまう。

これを回避するには、現在閲覧しているページにおいて

  1. Ctrl + K を押し
  2. 検索したい単語を入力
  3. Alt + Enter を押す

ことにより、検索するのが効率的。

 

4. Adblock の設定

追記(2014/6/2): Adblock で特定のフィルタを利用していると、Google Bookmarks のウィンドウが閉じてしまう。

 

参考サイト

2011年3月24日木曜日

Firefox 4 へ移行するための設定

1. Firefox 4 へ移行したメリット

Firefox 3.6 から 4 への移行は、対応してないアドオンがいくつもあるので当分お預けだな。… と舌の根の乾かぬうちに、どうにも我慢できなくなり Firefox 4 へ移行した。

Firefox 4 は外観の変化も去ることながら、Google Chrome と同じように、複数のタブを開いているときに、Youtube で動画を再生しているタブを D&D してウィンドウとして独立させても、再生が止まることがない点が魅力的。自分としては新しく追加された機能、

よりも重要。

 

2. 対応してないアドオンを無理矢理動かす

Add-on Compatibility Reporter
Firefox 4 に対応していないアドオンを動かすため、「Firefox 4のアドオンの互換性チェックをスキップする方法

で紹介されていた

をインストールして再起動。

 

Configuration Mania

追記 (2011.5.10) : Configuration Mania

  • 「アドオン」タブの「アドオンの以下のバージョンとの適合確認をしない」

において、各バージョンにチェックを付けても互換チェックを回避できる。

 

3. Firefox 4 用にインストールしなおしたアドオン

  • 次のページを読みこむための AutoPagerize は Firefox 4 用をインストール。
  • Tumblr に必須の Tombloo は、GitHub にある、最新の tombloo.xpi より raw を拡張機能に D&D してインストール。 追記 (2011.3.26) : 今は普通にインストールできる。

GMarks が互換として動作してくれなかったことが痛い。 (+_+)  当面は、Google Bookmarks よりブックマークレットでブックマークするか、GBookmarks を代わりに使うことに。

( cf. Google 検索と同時に Google ブックマーク の検索結果を表示する )

追記 (2011.3.30) : Gmarks が Firefox 4 に対応してくれた。 ^^

追記 (2011.5.14) : kwout をインストールしなおした。

 

4. ツールバーとコントロールを一度無効に

ところでなぜか、「新規タブを開く」ための + ボタンが消えてしまった。

Tab Mix Plus が影響しているかと思い、色々設定を変えてもダメ。

これに対して一度、

  • Firefox ボタン > ヘルプ > アドオンを無効にして再起動...

を選択。セーフモードで起動するときに、

  • 「ツールバーとコントロールを無効にする」

にチェックを入れて起動。これにより、次回から正常に表示されるようになった。

 

追記 (2011.3.27) :  ツールバーの表示を初期状態に戻すなら、

  • 表示 > ツールバー > カスタマイズ...

より 「初期設定に戻す」 ボタン を押した方が早い。

 

+ ボタンを配置する位置

追記 (2011.3.26) : 上記のように「新規タブを開く」ための + ボタンが消えてしまう理由がわかった。自分の場合、開いているページを別のブラウザで開くために、アドオン Open With を利用している。

メニューより、

  • 表示 > ツールバー > カスタマイズ...

により、以下のように新規タブを開くボタンを OpenWith のボタンの右側に置くと、+ ボタンが消えてしまう。

CropperCapture[135]

+ ボタンを OpenWith の左側に置くと、普通に表示されるようになる。

CropperCapture[136]

+ ボタンを一番左に配置する必要があるみたい。

 

5. 表示のカスタマイズ

追記 (2011.3.26) : 以前のようにロケーションバーの右隅に RSS などのフィードを購読するためのボタンがなくなってしまったので、表示のカスタマイズにおいて、ボタンとして追加。

タブグループ」のボタンもすぐに押せるように、常に表示しておくことに。

CropperCapture[133]

以下の動画を見ると、タグのグループ化を上手く使えたら便利なのかな?

Firefox Panorama: How To from Aza Raskin on Vimeo.  
(via いよいよFirefox 4が正式リリース! 何が新しくて何がスゴイ? : ライフハッカー[日本版])

 

6. 再起動したときの動作を変更

Firefox を終了した後、再び起動したとき、以前に開いていたウェブページが開かれるようにするには、

  • オプション > 一般 > 起動

で「前回終了時のウィンドウとタブを表示する」を選択。

 

7. 無効にしたアドオン

 

8. メモリの使用量を減らす

追記 (2011.4.1) : 数日使ってみて感じることは、メモリ食い過ぎ Firefox 4 … (+_+)

当初は Memory Restart をインストールしてメモリ使用量を確認すると伴に、定期的に再起動。

しかし、面倒なので、Firefox4の「about:config」設定でメモリ使用量を軽減 : ライフハッカー[日本版] で説明がされているように

「browser.sessionstore.max_concurrent_tabs」を「0」

に設定。

必要であれば、Firefox 4のメモリ使用量を減らす方法 - Firefox更新情報Wikiブログ で述べられている

「javascript.options.mem.high_water_mark」の … 値を「32」くらいに減らす

も設定しておく。

 

9. about:config で調整

ディスクキャッシュを利用しない

追記 (2011.4.4) : Firefox 3 で行ったメモリのみを利用したキャッシュの設定をした。

アドレスバーにabout:configと入力して設定モードへ進み、browser.cache.でフィルタを実施

  • browser.cache.disk.enable を false に設定し、
  • browser.cache.memory.enable を true へ設定。
  • browser.cache.memory.capacity に -1 を指定すると物理メモリサイズに合わせて自動的に値を設定してくれる

( 【レビュー】ブラウザをメモリディスクを使って高速化する方法  より)

 

接続

about:config において、

  • connection
  • pipe

でフィルタリングして適当に値を調整。

2011年3月23日水曜日

AutoHotkey でWindows Live Writer にソースコードを貼り付ける (2) - リボンUIを採用したバージョンへの対応

1. Windows Live Writer 2011 にバージョンアップしたら、ソースコードを貼り付けるための AutoHothey のスクリプトが動かなくなった

ブログを書くための Windows Live Writer は、長らく過去のバージョンを利用してきた。リボンUI が採用される前のもの。

ブログにソースコードを載せる場合、google-code-prettify で色付けされるようにしている。このとき、AutoHotKey を利用して、Windows Live Writer にソースコードを貼り付ける処理を自動化した。

最近、Windows LiveWriter を、リボン UI を採用した、Windows Live Writer 2011 にバージョンアップした。その結果、上記スクリプトが正常に動かなくなったので、スクリプトを修正した。

 

2. 修正したスクリプトの起動と使い方

前提 : AutoHotkey ( Installer for AutoHotkey_L ) がインスールされていること。

  1. スクリプト pasteHTMLCode2Writer.ahk  をダウンロードした後、ダブルクリックして起動。
  2. タスクトレイに アイコン 081002-002 が表示される。

 

使い方
  1. Windows Live Writer で、予めソースコードを挿入したい位置にカーソルを移動。
  2. ソースコードが書かれている、アプリケーションのウィンドウをアクティブにし、対象のコードを選択。
  3. Ctrl + Shift + Q を押すと、選択したソースコードが Windows Live Writer に貼り付けられる。

 

3. スクリプトの実装

スクリプトの内容は、以下の通り。

^+Q::                      ; Ctrl + Shift + Q
Send ^c                   ; 対象のソースコードをコピー
Send !{Tab}               ; Alt + Tab でウィンドウを切り替える

; Windows Live Writer がアクティブになるのを待つ
SetTitleMatchMode, 2
WinWaitActive, Windows Live Writer, , 2

; クリップボードの内容を変更
clipboard = <pre class="prettyprint">%clipboard%</pre>

Send !+hvsh{Enter}		; Alt+h v s h Enter
return

( cf. jutememo's gist: 881589 — Gist )

以前のスクリプトは、コードを貼り付ける処理において、Sleep コマンドを利用せざる負えなかった。

今回は、Send コマンドによりキー入力を連続しても問題がなかったので、Sleep コマンドは使わなかった。

2011年3月18日金曜日

Google Chrome で USTREAM のメンテナンス画面が表示されるのでキャッシュをクリア

先日 USTREAM でメンテナンスがあって以来、Google Chrome で見ると頑固にメンテ画面が表示されたままになっている場所がある。 何度再読み込みしてもだめ。しかし、Firefox では正常に見ることができる。

そこで、一度 Chrome のキャッシュをクリアしてみることにした。

Google Chrome の設定 (右上にあるレンチの形をしたアイコン) より、

  • > オプション > 高度な設定 > プライバシー > 「閲覧履歴データの消去...」ボタン

「キャッシュ」のみチェックを付けて、「閲覧履歴データを消去する」ボタンを押す。

CropperCapture[126]

これで問題なく見ることができるようになった。

2011年3月15日火曜日

Windows 7 で 窓の手 を使いサブメニューの表示を早くする

1. サブメニューの表示がワンテンポ遅い

Windows 7 は Vista と比べ、UI を操作したときの反応が良い。XP と比べてもレスポンスが良いと感じる。待たされることが少なくなった点が 7 のいいところ。

UI 操作がとても快適になった。そのため、

  • 「右クリックしてサブメニューを表示させる」

ときの表示が遅いことに、最近まで気がつかなかった。

窓の手 を使い、サブメニューが表示されるまでの時間を短かくすることにする。

 

2. 窓の手でサブメニューの表示される時間を設定

より、「窓の手 2010 for Windows 7」 をダウンロードして、インストール。

「窓の手」を起動し、

  • 「パフォーマンス」タブの「サブメニューの表示するまでの待機時間」の値を 0 秒

に設定。

CropperCapture[115]

これにより、Windows 7 のデフォルト設定よりも、さっと表示されるようになり、快適な操作感を得られる。ただし、サブメニューの表示が早すぎると、急かされる感じがする。その場合、少しだけ表示を遅くすると良い。

2011年3月12日土曜日

Firefox の検索バーに Google インスタント検索を設定 - 入力に応じてリアルタイムに変化

1. Google インスタンス検索は、検索対象を釣り上げる

Google で検索をしていて、何かの拍子に検索フィールドの横に

Instant is on

と表示されることがあった。画面上部には薄らと灰色のメニュー。

CropperCapture[113]

変な動作になるなぁと思い、全然注目してなかったけれど、これ随分前に発表されていた「Google インスタント検索」だった。

Inside AdWords-Japan: Google インスタント検索 - 検索の新機能が登場(2010年9月9日)よると、

Google インスタント検索とは Google 検索の新機能で、検索ボックスに入力を始めると、自動的に検索結果が表示されるというものです。キーボードを打ちながらリアルタイムに検索結果が更新されるので、入力が完了しなくても、結果としてどのような情報が得られるのか瞬時にわかります。

海外SEO情報ブログ に、検索の様子が動画で紹介されている。

インスタンス検索を使ったら、割と使いやすかった。探したい対象を、何ページにも渡って探すのではなく、検索対象を釣り上げる感覚がする。

このインスタント検索をデフォルトの検索エンジンに設定することにした。

 

2. 検索バーにインスタンス検索を設定する

Ready2Search を使い、インスタンス検索用の検索プラグインを作成した。

以下の「OpenSearch プラグイン」をクリックして検索バーに追加し、

この検索エンジンを選択」にチェックを入れる。

CropperCapture[114]

※ 検索の対象言語を日本語に限定したくない場合は、こちら を追加。

 

日本語と英語から検索する

追記 (2011.3.16) : 日本語と英語から検索したい場合は、

  1. 言語を限定しない検索をする設定にしたプラグインを検索バーに追加。
  2. Google 検索において、画面右上の歯車のアイコンより、Search settings を選択。
  3. Search Language において、Japanese にチェックを入れる。

CropperCapture[117]

 

3. Google サイトでの検索を、Firefox の検索バーと同期させる

追記 (2011.3.16) : Google インスタント検索で入力した文字列を、 Firefox の検索バーにも反映させたい場合は、SearchBox Sync をインストールしておく。

入力した文字列は、インスタント検索された後、ちょっと待っていると同期が行われる。

 

4. 日本語と英語の検索を使い分ける方法

追記 (2011.4.1) : 日本語のページから検索することをメインとし、場合によって英語のページからも検索したい場合、次のような操作をする。

  1. 日本語のページから検索するプラグインを使って検索を行う。
  2. その後、検索フィールド下部にある Search Japanese pages の右にある × をクリック。

CropperCapture[139]

これにより、「すべての言語」から検索された結果が表示される。

CropperCapture[140]

2011年3月11日金曜日

表計算のセルを使った簡易グラフ - Google スプレッドシート, Excel, LibreOffice Calc で手作業による入力

専用のツールを使ったり、ドロー系のアプリを使わなくても、表計算のセルを使って簡易グラフを作成できる。原始的だけれど、正確さや厳密さを求めず、必要な情報を素早く把握するためのお手軽でコストをかけない方法。

例えば、下図のように「複数のタスクからなるプロジェクト」があり、

  • 予定していた期間
  • 実際に行なった期間

の二つを大雑把に把握したいとする。

CropperCapture[106]

( 上図、日付の連続データを作成する方法はこちら。 )

 

グラフ部分の作成

グラフを入力するには、グラフとして表示したいセルを範囲選択しておき、メニューより、

  • 表示形式 > 条件に応じて色を変更  (Google スプレッドシート)
  • 書式    > 条件付き書式          (Excel)
  • 書式    > 条件付きの書式設定     (LibreOfice Calc)

ここでは条件として「完全に一致するテキスト」を選択し、入力されるテキストとして数値の 1、2 をそれぞれ入力した。

CropperCapture[108]

グラフのように見せかけるためには、「テキスト」と「背景」を同じ色に設定する。

 

グラフの入力

赤色のバーを表示させるには、セルに`1’ を入力した後、

CropperCapture[111]

セルの右下のハンドルをつかんで右へ伸ばしていく。

CropperCapture[110]

  • LibreOffice の場合は、Ctrl キーを押しながら右へ伸ばしていく。

グラフを削除したいときは、範囲を選択して Del キーを押す。

2011年3月10日木曜日

日本語入力で「あ」を入力するつもりが「ち」となる場合 - 「かな入力」から「ローマ字入力」へ戻したい

何かの拍子に日本語入力が「ローマ字入力」から「かな入力」に切り替わってしまうことがある。切り替わった結果、

「あ」

と入力したかったものが

「ち」

と表示されてしまう。

こういうこと最近全くなかったので、「PC がトラブった!」とこの質問されても、どこで設定すればいいのか全く思い出せず。。

やり方は簡単で、CropperCapture[99]元の入力に戻したいときは、言語バーの右下にある

KANA

をクリックして、「かな入力」を解除する。

 

設定が戻ってしまう場合

再び「かな入力」に戻ってしまう場合は、言語バーを右クリック > 設定

「テキスト サービスと入力言語」ウィンドウが表示されたら、使っている IME を選択して、「プロパティ」ボタンを押す。

CropperCapture[103]

Microsoft IME の場合は、全般タブ > ローマ字入力/かな入力で、ローマ字入力を選択。

CropperCapture[104]

Google 日本語入力の場合は、一般タブ > ローマ字・かな入力で、ローマ字入力を選択する。

CropperCapture[105][4]

2011年3月9日水曜日

Google マップに登録した地点間のルートを検索する - マイマップの活用

1. 登録地点間のルートを知りたい

旅行へ行く前、Google マップで下調べをし、マイマップを作成する。

マイマップは行きたい場所を一覧するのには便利。しかし、

「地図に保存してある 2 つの地点をどうやって移動するか?」

についてルート検索する方法がちょっと面倒。

 

2. ルート検索の手順

手順の概略

ルートを検索するには、マイマップを開いた後、次の手順で行う。

  1. 出発地の設定: スタート地点のアイコンを右クリックして、「ここからのルート」を選択。
  2. ブラウザの戻るボタンを押す。
  3. 目的地の設定: 目的地で左クリック して、吹き出しに表示された「ルート」を選択。
  4. 検索ボタンを押す。

※ 登録した地点間を正確に検索する必要がなければ、以下を参照。

 

3. ルート検索の具体例

例えば、「東京タワー」から「東京スカイツリー」へ移動したい場合。


より大きな地図で 地点間のルートを検索 を表示

 

a. 出発地点の設定

予め作成したマイマップを開き、「東京タワー」の場所を示すアイコンを右クリック

ここからのルート」を選択する。

CropperCapture[103][5]

これにより、「ルート・乗換案内」の A 地点に「東京タワー」の場所が入力された状態になる。

CropperCapture[98]

 

b. 戻る

次にブラウザの「戻る」ボタンを押して、マイマップに戻る。

CropperCapture[99]

 

c. 目的地の設定

マイマップで目的地である「東京スカイツリー」を選択。

表示さた吹き出しの左下にある「ルート」のリンクを左クリックする。

CropperCapture[100]

これにより、「ルート・乗換案内」の B 地点に目的地である「東京スカイツリー」が入力された状態になる。

CropperCapture[101]

 

d. 検索結果

「検索」ボタンを押すと、ルートが表示される。

CropperCapture[102]

 

4. ルート検索の結果を示す URL を取得する

「車で行く」のアイコンをクリックした場合は、マイマップに経路を保存できる。

しかし、電車の場合はできない。

更新(2013/01/14): 探した経路を表示するためのリンクが必要な場合は、ルート検索をした後、「リンク」ボタンをクリックして URL を表示しコピーする。

SnapCrab_NoName_2013-1-14_16-21-26_No-00

 

リンク付きテキストの作成

「経路を表示する URL」と「タイトル」を取得したい場合、Firefox のアドオン Make Link を使えば簡単に行える。

次の手順を踏む。

  1. 上記のリンクをブラウザのロケーションバーに入力し、Enter キーを押す。
  2. 経路が再表示されたら、Make Link で URL とタイトルを取得する。

これにより、以下のようなリンク付きのテキストを作成できる。。

2011年3月8日火曜日

LibreOffice Calc でセルに複数行を入力

1. 表計算で改行を入力

CropperCapture[96]Excel, Google スプレッドシート でセルに複数行入力するときは、改行したい場所で

Alt + Enter

LibreOffice の場合は、

Ctrl + Enter キーを押すと、任意改行されます。

( Calc/Writing Multi-line Text/ja - LibreOffice Help より )

 

2. 特定の IME と相性が悪い

しかし、SKKIME で入力中 … あれ?押したけれど改行されない。。 (@_@;

そしてなぜか

Ctrl + Alt + Enter

で改行された。

どうやら使っている SKKIME と相性が悪いようだ。

Goolge 日本語入力では、上記のように Ctrl + Enter で改行された。

追記(2015/5/25): 直接入力モードになっていると、Ctrl + Enter で改行できる。

Scala の List クラスで map, filter, foldRight と シーケンス内包表記

1. Scala の覚えやすそうな点と、すぐに忘れそうな仕様

Scala に興味を持った理由は、「今からでも遅くない これから始めるScala(前編)」 で挙げられていた以下の特徴による。

  • オブジェクト指向と関数型言語の特徴を組み合わせています。Scalaでは、関数をオブジェクトとして扱うことができますし、高階関数も利用できるなど、関数型言語からさまざまな特徴を取り入れています。
  • Scalaは静的型付け言語ですが、型推論によって型の記述を省略することができます。変数や関数の宣言時に、コンパイラが型を推論してくれるため、型の指定をいちいち行わなくてもよいのです。
  • Trait(トレイト)という、実装を持つことができるインターフェイスを利用して、Mix-Inができます
  • 暗黙の型変換(implict conversion)などを利用して、DSL(ドメイン固有言語,Domain-Specific Language)を作成しやすくなっています。
  • マルチコア時代を意識した、分散処理ライブラリ(Actorライブラリ)が用意されています。

(太文字は引用者による)

久しぶりに本を購入して読んでいる。しかし、いつもの如く頭に入らないし、覚えたものは身に付かず抜けていく。

Scala は、統一されていて覚えやすい仕様もあれば、「何だかごちゃごちゃしていて忘れること間違いなし」と感じるところもある。結果として見やすくなるコードのために覚えておくルールの多さに圧倒されてしまったり。。 (+_+)

Guido van RossumNeopythonic: Scala? で次のように述べている。

Perhaps my biggest disappointment in Scala is that they have so many rules to make it possible to write code that looks straightforward, while being anything but -- these rules all seem to have innumerable exceptions, making it hard to know when writing simple code will work and when not.

 

a. Haskell の関数と似た名前のメソッド名

Scala は関数型の特徴を持ち合わせている。しかも型推論をしてくれる。しかし、「Haskell ではこう書けるのに、何で Scala はだめなんだろう?」と疑問を抱くことがある。例えば、

  • メソッドの引数は必ず型を指定しないといけない。

Haskell で関数を定義するとき、引数の型を省略しても型を推論してくれる。

Prelude> let add x y = x + y

Scala では引数の型を指定しなくてはならないので面倒。 (+_+)

scala> def add(x:Int, y:Int) = x + y

この辺り、オブジェクト指向と折衷しているのが理由なのだろうか?スクリプトを書くのにお手軽に使えると期待していただけにちょっと残念。

ところで、Haskell との比較で言えば、関数名が似ているのはなぜだろう?例えば、Haskell でリスト操作に不可欠な、

  • map
  • filter
  • foldr

(cf. Prelude, Data.List)

各々の言語でこれに対応した関数、メソッドを比較すると、

Python map filter reduce 2.1 組み込み関数
Ruby collect, map find_all, select inject Enumerable
Scala map filter foldRight, :\ scala.collection.immutable.List 

これを見ると Haskell の関数名に Scala が一番似ていて、次に Python 。Ruby のメソッド名はかなり異なる。

scala.collection.immutable.List  には、上記以外にも類似したメソッドが見受けられる。もちろん、Python でも関数型プログラミングを意識したモジュールには似た名前の関数が定義されているけれど。

Scala と Haskell の言語設計者は何か関係でもあるんだろうか?

Scala の設計者である Martin OderskyThe Origins of Scala で次のように述べている。

Bill Venners: How did Scala come about? What is its history?

Martin Odersky: Towards the end of my stay in Zurich, around 1988/89, I became very fond of functional programming. So I stayed in research and eventually became a university professor in Karlsruhe, Germany. I initially worked on the more theoretical side of programming, on things like call-by-need lambda calculus. That work was done together with Phil Wadler, who at the time was at the University of Glasgow. One day, Phil told me that a wired-in assistant in his group had heard that there was a new language coming out, still in alpha stage, called Java. This assistant told Phil: "Look at this Java thing. It's portable. It has bytecode. It runs on the web. It has garbage collection. This thing is going to bury you. What are you going to do about it?" Phil said, well, maybe he's got a point there.

The answer was that Phil Wadler and I decided take some of the ideas from functional programming and move them into the Java space. That effort became a language called Pizza, which had three features from functional programming: generics, higher-order functions, and pattern matching. Pizza's initial distribution was in 1996, a year after Java came out. It was moderately successful in that it showed that one could implement functional language features on the JVM platform.

(太字斜体は引用者による)

一緒に仕事したという Philip Wadler と言えば、The Haskell 98 Language Report Preface に名前があるように、Haskell の言語仕様を決める委員会の editor であり、Glasgow Haskell Compiler 発祥の University of Glasgow で教授をしていた人物。「モナドって何?」と調べていれば行き当たるであろう Monads for functional programming の著者。

… ということは、関数名が Haskell に似ていたとしても、あながち偶然でもないということだろうか?

 

b. 他によく似た名前の関数を持つ言語は?

Scala が影響を受けた言語について調べてみると、

Java, Pizza, Haskell … と順にある。

Fold (higher-order function) - Wikipedia には fold 系の関数の各言語の一覧が載せられている。この中で Scala の foldRight に似ている名前を持つ言語は Ocaml と Scheme 。それぞれ関数名は fold_rightfold-right

  • List より : map, filter, fold_right
Scheme は、

うーん、こちらの方が名前は似てるなぁ。結局、どの言語が一番影響を与えて関数名が決まったんだろう???

 

それはさておき、リスト操作における重要な関数である、

で練習した関数を Scala でも手を動かして覚えることに。 (+_+)

 

c. Meadow で Scala のスクリプトを実行

… とその前に、「オブジェクト指向プログラマが次に読む本 -Scalaで学ぶ関数脳入門」には Scala の実行方法として以下の 3 つが挙げられていた。

  • シェルで対話的に実行する
  • スクリプトを記述して実行する
  • プログラムを記述して実行する

対話的というのは REPL のことで、ちょっと試したいときに使う。それ以外は main メソッドを持つシングルトンオブジェクトを書いてコンパイルして実行しないといけない思っていた。その中間に位置する実行方法があったのに気づかず。。 (+_+)  これからはスクリプトとして書いて実行してみよう。

( cf. Getting Started with Scala の Script it! )

以前、エディタで Scala を実行する方法をいくつか見た。

やはり、Meadow を使っていこうかな。

方法は、

  1. REPL を使うときのようにエディタに書いて
  2. M-x scala-run-scala を実行
  3. C-c C-l でスクリプトを実行。

( cf. EmacsでつくるScala開発環境 前編(scala-mode) - tototoshiの日記 )

 

2. map

まずは、リストの要素を 2 倍にすることから。

Haskell で書くなら、

Prelude> let l = [1..5]
Prelude> map (\x –> x * 2) l

セクションを利用すると、

map (*2) l

 

a. map メソッドにおける型変数

map メソッドの型を見ると、(scala.collection.immutable.List)

def map [B] (f: (A) ⇒ B) : List[B]

メソッドで型変数 B が宣言されている。

なぜこの型変数 B が書かれているのかと言えば、List クラスの型変数 A

class List [+A] …

はリストの要素の型を表しており、map メソッドの引数で要素を変換する関数、

f: (A) ⇒ B

により、元の要素の型とは異なる型になる可能性があるため。(型変数の前に `+’ が付いている意味は横に置いておく。)

この辺り、Java で似たような実装を試したときを参考に。

とりあえず、map メソッドを使う分には詳細を理解する必要はない。

 

b. 無名関数と引数の型を省略

Scala で無名関数を定義するときは、以下のような形式。

(引数:型) => 式

例えば、数値が与えられたら 2 倍する関数を定義するなら、

val f = (x:Int) => x * 2

Haskell で

–>

と書くところを

=>

とすることに注意。また、面倒だけれど、無名関数の引数は型を指定しなければならない。

リストの要素を 2 倍するには、

val l = List(1,2,3,4,5)
l.map((x:Int) => x * 2)

(以下、上記変数 l を使う。)

map 関数の引数として無名関数を与えると、引数の型をしなくてもよい。

l.map((x) => x * 2)

これは変数 l が

List[Int]

という型であり、リストの要素が Int 型だとわかることを利用して、先ほどの map メソッドに当てはめると、

def map [B] (f: (Int) ⇒ B) : List[B]

となり、map メソッドの第1引数の関数の引数の型を推論できるため。

ついでに、引数が 1 つだと ( ) も省略できる。

l.map(x => x * 2)

 

c. 無名関数の引数の省略

また、Haskell のセクションに似た書き方も用意されている。無名関数の引数は、

_

で代用できるので、

l.map(_*2)

 

d. メソッド呼び出し . の省略

それから、メソッドの呼び出しである . も省略できる。

l map (_*2)

シンプルに書けたけれど、ここまでの道程が長い。。(+_+)

 

e. 変更可能なリストを利用する場合

ところで、上記のリストは変更不能な (imutable) リストを利用した。 Scala ではこの使用が推奨されている。

これに対して、変更可能なリストを使いたい場合は、

  • scala.collection.mutalble

を使う。

scala.collection.mutable.LinkedList の要素を追加するメソッド は

def :+ (elem: A) : LinkedList[A]

これを利用すると、

import scala.collection.mutable.LinkedList

var result = LinkedList[Int]()
for (e <- l){
  result = result.:+(e * 2)
}
println(result)

変更可能な変数は var を使って宣言。

result 変数を更新している箇所は、以下のように置き換えることができる。

result = result :+ e * 2

更に省略するなら、

result :+= e * 2

慣れないと、なぜこういう風に書けるのかわからなくなってしまうけれど。 ^^;

 

f. シーケンス内包表記

The Scala Language Specification には、

For Comprehension

と書かれており、A Tour of Scala では Sequence Comprehensions とある「シーケンス内包表記」。

List comprehension - Wikipedia に for と yield を使った説明がされていることより、

「リスト内包表記」

と同じような機能を持つようだ。これを使うなら、

for (e <- l) yield e * 2

Ruby の yield や、Python の yield と同じ予約語名なので頭の中が混乱してきた。。 (+_+)

 

3. filter

次に、filter メソッド。型を見ると、引数に述語 (predicate) を与えれば良いことがわかる。

(cf. scala.collection.immutable.List, Haskell の Prelude 散策 (2) - 述語)

def filter (p: (A) ⇒ Boolean) : List[A]

map メソッドと同じように徐々に省略できるところを省いていくと、

val l = List(1,2,3,4,5)
l.filter((x:Int) => x > 3)
l.filter((x) => x > 3)
l.filter(x => x > 3)
l.filter(_>3)
l filter (_>3)

シーケンス内包表記では、

for (e <- l; if e > 3) yield e

( ) を使わずに { } で書くと ; も省略できる。

for { e <- l
      if e > 3
} yield e

他の言語における for とちょっと違うので、混同しないように注意が必要。

 

4. foldRight

最後に、リストの値を集約する foldRight メソッド。(scala.collection.immutable.List)

def foldRight [B] (z: B)(f: (A, B) ⇒ B) : B

map, filter メソッドと違い引数が 2 つ。しかも、それぞれの引数が独立しているように見える括弧の書き方。

以下のようなシグニチャでないことに注意。

def foldRight [B] (z: B, f: (A, B) ⇒ B) : B

各々の引数を括弧で括る書き方は、Scala におけるカリー化の手段。引数のリストがあると言えばいいのかな?

カリー化とは、Chapter 8. Functional Programming in Scala によると、

… currying transforms a function that takes multiple parameters into a chain of functions, each taking a single parameter.

In Scala, curried functions are defined with multiple parameter lists,

def cat(s1: String)(s2: String) = s1 + s2

Of course, we could define more than two parameters on a curried function, if we like.

(太字は引用者による)

メソッドの引数が複数の括弧 ( )  で囲まれている様は、「複数の仮引数のリストを持っている」と言えば良いみたい。つまり、メソッドの引数の括弧が一つというのは、引数の書き方としては特殊な一例に過ぎないと。括弧ごとにメソッドの呼び出しを行うことができ、残りの引数を順に与えていき、最終的に全体の関数と同じ関数の連鎖が生まれる。

foldRight の場合で言えば、

リスト.foldRight(値)

により、foldRight の第 2 引数を受け取る関数が生成される。

では、foldRight を使って、要素を全て足す計算をしてみる。先ほどと同じく、徐々に省略した書き方をすると、

val l = List(1,2,3,4,5)
l.foldRight(0)((x:Int, y:Int) => x + y)
l.foldRight(0)((x,y) => x + y)
l.foldRight(0)(_+_)
(l foldRight 0)(_+_)

 

a. 別名 :\

foldRight と同じ機能のメソッドとして :\ がある。

def :\ [B] (z: B)(op: (A, B) ⇒ B) : B

なぜこんな形のメソッドがわざわざ定義してあるかと言えば、以下の foldr を説明した図を見れば一目瞭然。

http://en.wikipedia.org/wiki/Fold_(higher-order_function)

Fold (higher-order function) - Wikipedia, the free encyclopedia via kwout

上記と同じ計算をするなら、

l.:\(0)(_+_)
(l :\ 0)(_+_)

これまた慣れないと読みずらい。

 

b. foldLeft と /:

foldRight はリストを右 (末尾) から左 (先頭) へと計算を進めるのに対して、foldLeft は左 (先頭) から右 (末尾) へと計算を行なう。

(l foldRight 100)(_-_)    // (1-(2-(3-(4-(5-100))))) => -97 (l foldLeft 100)(_-_)     // (((((100-1)-2)-3)-4)-5) => 85

foldLeft の別名は /: 。foldRight の :\ とは対照的。

(l :\ 100)(_-_)
(100 /: l)(_-_)

: で終わるメソッド名は右結合なので、第1引数を左に置く。この例外的なルールにより、左から計算を畳み込んでいく様をコードから連想できるようになっている。

. によるメソッドの呼び出しで書くなら、

l./:(100)(_-_)

こういう例外的なことが存在することが良いことなのか悪いことなのか。うーん…

 

c. reduceRight とreduceLeft

Haskell では foldr の第2引数がなく、リストの要素のみに二項演算子を適用していく関数名は foldr1 。

Prelude> foldr1 (+) [1..5]
15

scala には foldRight1 というメソッドはなく、reduceRight が代わりに存在する。

l reduceRight (_+_)

当然ながら、対照的な reduceLeft もあり。

l reduceLeft (_+_)

 

d. map , filter を foldRight で書き直し

次に、map メソッドで要素を 2 倍した関数を foldRight で書き直したい。

Haskell では以下のように書ける。

Prelude> foldr ((:).(*2)) [] [1..5]
[2,4,6,8,10]

Scala では空リストを Nil で表現する。

scala.collection.immutable.Nil

object Nil extends List[Nothing] with Product

これを利用して、以下のように書けばいいのかと思いきや、エラーとなる。 (+_+)

(l foldRight Nil)(_*2::_)

エラーがでないようにするには、foldRight の第1引数の型を明示する。

(l foldRight List[Int]())(_*2::_)

理由は、Programming in Scala (p326) によると、

Generally, when tasked to infer the type parameters of a polymorphic method, the type inferencer consults the types of all value arguments in the first parameter list but no arguments beyond that.

(太字は引用者による)

メソッドの型推論は、仮引数のリストのうち、最初の実引数を調べることによって行われるようだ。

foldRight の型で言えば、

def foldRight [B] (z: B)(f: (A, B) ⇒ B) : B

引数 z を元に型推論が行われる。

Nil の型について :: メソッドを使って調べてみると、

scala> Nil
res0: scala.collection.immutable.Nil.type = List()

scala> 1::2::3::Nil
res1: List[Int] = List(1, 2, 3)

scala> "hoge"::"piyo"::"fuga"::Nil
res2: List[java.lang.String] = List(hoge, piyo, fuga)

:: メソッドに与える引数の型により、返り値の型が決まる。

ところで、foldRight の第1引数 z の型変数は B と書かれており、リストの要素から型を決めることができない。仮引数 z に Nil を与えても型が決まらない。だから、型を指定しなければならないということかな。

(l foldRight List[Int]())(_*2::_)

この場合の foldRight の型は以下のような感じ。

def foldRight(z: List[Int])(f: (Int, List[Int]) ⇒ List[Int]) : List[Int]

ごちゃごちゃしていて頭混乱するなぁ~。

 

map の定義

map 関数を foldRight メソッドを使って定義するなら、

def mymap[A,B](l: List[A], f:(A) => B) :List[B] = (l :\ List[B]())(f(_)::_)

Haskell では、型を明示しなくても推論してくれるのでシンプルに書ける。

mymap f = foldr ((:).f) []

 

filter の定義

filter メソッドを使った 3 以上要素を抽出する関数を :\ メソッドで書き直すなら、

(l :\ List[Int]())((x,y) => if (x>3) x::y else y)

filter メソッドを :\ メソッドを使って定義するなら、

def myfilter[A](l: List[A], p: (A) => Boolean) :List[A] = 
  (l :\ List[A]())((x,y) => if (p(x)) x::y else y)

Haskell なら、

myfilter p = foldr (\x y -> if p x then x:y else y) []

 

5. その他

a. Range で数値のリストを生成

ついでなので、範囲を表わす scala.collection.immutable.Range を使い、1 から 10 まで足してみる。

((1 to 10) :\ 0)(_+_)
(1 to 10) reduceRight (_+_)
(1 to 10) sum

 

b. ブロックを使って副作用

純粋関数型でないメリットは、変数の更新や副作用を簡単に書けること。( それがバグの温床にもなるけれど… )

ブロック { } を foldRight で用いると計算途中の値を出力できたりする。ブロックは最後の式の値が返されるので、以下のように書くと、計算途中の変数の値を出力可能。

((1 to 5) :\ 0){ (x,y) =>
  println(y)
  x + y
}

結果は、

0
5
9
12
14
res647: Int = 15

これは Ruby の inject メソッドを書くときに似ている。

puts (1..5).inject(0){ |x,y|
  puts x
  x + y
}

実行すると結果は、

0
1
3
6
10
15

あ~、Ruby の inject メソッドは左から右へと畳み込んでいくんだったか。つまり、Scala で書くと、

(0 /: (1 to 5)){ (x,y) =>
  println(x)
  x + y
}