2011年9月21日水曜日

Firefox で D&D により「選択したテキストを検索」「リンクを開く先」DragIt

1. Easy DragToGo から DragIt へ乗り換えた

Easy DragToGo は、Firefox で「検索」「リンクを開く」操作を格段にやりやすくしてくれる。

「選択したテキスト」を D&D で素早く検索したり、リンク先を新しいタブとして「フォアグラウンドに開く」か「バックグラウンドで開く」かコントロールできる。

残念なことに、Easy DragToGo は Firefox の最新のバージョンに対応していない。

SnapCrab_No-0684 Configuration Mania で、互換性を無視してインストールすることはできる。しかし、Firefox の動作が不安定にならないように、できるだけ正式に対応しているアドオンだけをインストールしたい。

そこで、Easy DragToGo の代わりとなる DragIt に乗り換えることにした。

 

2. 「検索」操作の設定

最初に、「選択したテキスト」を D&D で検索する操作を設定する。

Easy DragToGo と同じ操作となるように、以下のように設定することにした。

  1. 「選択したテキスト」を上方向へドラッグすることにより、検索結果を新しいたタブとして「フォアグラウンドで開く」
  2. 「選択したテキスト」を下方向へドラックすることにより、検索結果を新しいタブとして「バックグラウンドで開く」

DragIt の設定画面より、「Gesture > Text」において、

  • Name: U, Gesture: , Action: Search in foreground tab
  • Name: D, Gesture: , Action: Search in background tab

09-20-20111[4]

 

検索時に検索エンジンを選択する

選択したテキストを検索するとき、検索エンジンを選択する設定もできる。

そのためには、上記の設定における Action の選択肢の中から、

  • Search with in foreground tab
  • Search with in background tab

を選ぶ。この Action を「選択したテキスト」を右方向、左方向へドラッグする操作に割り当てておいた。

 

3. 「リンク先を開く、画像を開く」操作の設定

次に、「リンク先を開く、画像を開く」操作の設定を行う。

設定は「選択したテキストの検索」と同じようにした。上方向へのドラッグは「フォアグラウンド」で開き、下方向へのドラッグは「バックグラウンド」で開く。

リンクをドラッグした時の設定は、「Gesture > Link」において、

  • Name: U, Gesture: , Action: Open in foreground tab
  • Name: D, Gesture: , Action: Open in background tab

09-20-20113

画像をドラッグした時の設定は、「Gesture > Image」において、

  • Name: U, Gesture: , Action: Open in foreground tab
  • Name: D, Gesture: , Action: Open in background tab

09-20-20116

 

4. 操作の反応をよくする

上記「検索」「リンク先を開く」「画像を開く」をドラッグしたときに、素早く DragIt が反応するための設定をしておく。

DragIt の設定画面の「Extra > Gesture」において、

  • Length threshold の値を 1 px

に設定。これにより少ない距離のマウス移動により DragIt が発動してくれる。

ただし、Easy DragToGo の方がレスポンス良い。

09-20-20112[5]

また、FireGestures の設定とバッティングしないために、同じ設定画面内にある、Enable page gestures のチェックを外した。

 

about:config で Length threshold を設定する

追記(2014/01/02): DragIt 3.2.1 では、デフォルトで Extra タブは表示されない。DragIt の設定画面より、

  • Options > Mode > Export

を選択する必要がある。

また、Length threshold: を設定できる下限が 6px になっている。

SnapCrab_No-0690

1px に設定したい場合、about:config で

  • extensions.dragit.gesture.threshold.length

を検索し、値 1 を入力する。設定値と動作を大雑把に比較したところ、1 xp と設定した場合が一番反応が良いようだ。

SnapCrab_No-0685-2

 

5. テキストフィールドに文字列を D&D したい

a. 一定時間で操作をキャンセル

追記(2014/3/23): DragIt をインストールすると、選択文字をドラッグした場合、必ず ジェスチャーが発動してしまう。

例えば、選択した文字列をドラッグして、テキストフィールドに入力することができなく。

これを回避するには、

  • Extra > Gesture > Timeout parameters: > Enable cancellation timeout.

にチェックを付けておく。自分の場合、すぐに操作がタイムアウトしても良いので、500ms に値を設定した

SnapCrab_No-0886

 

b. インプットフィールドに D&D できるようにする

もしくは、Gesture > Extern > Action において、”Enable Drag&Drop on input fields.” にチェックを付ける。

SnapCrab_No-0888

 

6. 操作不能になった場合

追記(2015/4/2): Firefox のアップデートなどで DragIt が操作できなくなった場合、DragIt を再インストールする。

追記(2015/4/14): Firefox で選択したテキストの検索に Super Drag - DragIt の代替

2011年9月18日日曜日

Web フォントを利用して、Web サイトで個性的な文字を使う

1. 海外のブログで、シンプルなデザインのサイトは、Blogger を使っていることが多い

海外のブログで、ファッション系のサイトを見ていると、Blogger である場合が多い。写真のサイズは大きく、綺麗な画像が載せられている。サイト全体はシンプルで、コンテンツに目が行くように配慮されている。

日本では、 Ameba を利用する人が結構いるようだが、掲載されている写真を見ると、なんだかなぁ…と。ただし、自分が知る限り、水原希子の画像は綺麗で、道端アンジェリカ の写真はでかい。

 

2. Blogger で使えるフォント

ところで、Forget*me*not... を眺めていたら、記事のタイトルの文字が、綺麗な細身のフォントであることに気がついた。Firebug でソースを見たら、使われているフォントは、

Josefin Slab

こんなフォントをウェブで使えたかな?と思い調べてみると、

の中に Josefin Slab があった。

 

3. Web フォントにより、サイトで使えるフォントの幅が広がる

なぜこのようなフォントを使えるのか、参照先を読んでみると、

A couple of months back we introduced Web Fonts to Blogger in Draft. Today we’re excited to not only launch Web Fonts to ALL Blogger users, but also announce we’ve added an additional 35 fonts to the mix, for a grand total of 77 fonts! …

Web Fonts, brought to you by our good friends at Google Fonts, let you spice up and further personalize your blog. J

Blogger Buzz: The Quick Brown Fox より)

Web フォント と言う技術が使われているようだ。

今、はやりのWeb Fontとは?:Webトレンド:ITmedia オルタナティブ・ブログ によると、

ここ1、2年、注目を集めているのがWeb Font。これは、興奮する話です。フォントを全てウェブ上に置いてしまって、誰でも同じようにサイトが見れるようにしようというアイデア。 有名どころで言えば、fonts.com Web Font , Typekit, Font Deck, そして最近Googleが開始したGoogle web fontsなどがあります。

日本語の場合、欧文フォントのように豊富ではないけれど、日本語 ”webフォント” で検索すると 幾つかサービスが見つかる。

日本語WEBフォントサービス(デコもじ&フォントプラス)を比較してみた。 | ラズル株式会社スタッフブログ によると、

英語のWEBフォントサービスが世に現れてから、ブログやニュースサイト等を中心に爆発的に広がりを見せましたが
日本語フォントのサービスはまだまだ始まったばかりで、私が知っているのは以下2つです。
デコもじ
フォントプラス

 

4. Google Web Fonts を使ってみる

上記で紹介されていた Web フォントの中で Google Web Fonts を試しに使ってみる。

Google Web Fonts を開いたら、Start choosing fonst ボタンを押す。

左側にある Search ボックスに、フォント名 `Josefin Slab’ を入力して、フォントを絞り込む。

フォントの下にある Quick-use リンクをクリックすると、使いたいサイトに埋め込むコードと、フォントを適用したい要素に対する CSS が表示される。

 

5. Tumblr で Web フォントを使う

例えば、Tumblr のタイトルのフォントを、上記で取得したものに変更したいとする。

Tumblr を表示させ、customize ボタンを押す。

メニューより、Theme において、Use custom HTML ボタンを押す。

表示された HTML 中における head 要素の中に、Google Web Fonts で取得した link 要素を貼り付ける。

次に、メニューより、Advanced > add custom CSS に、Google Web Fonts で取得した CSS をタイトルに対して適用するように記述する。自分が使っているテーマでは、以下のようにして CSS を適用した。

#header h1{
font-family: 'Josefin Slab', serif;
}

これで、タイトルのフォントが 'Josefin Slab' となった。

Google Web Fonts を使用する前。

使用後。

Google Web Fonts で、日本語フォントも使えるようになるといいなぁ。そうすれば、デザインのために文字を画像として表示する、なんてことをしなくて済む。

2011年9月13日火曜日

アイスコーヒーはティーポットと茶こしで入れる

コーヒーは、毎日の生活に欠かせない。

食後の一杯は格別。頭をすっきりさせるには最適。ただし、飲み過ぎると、コーヒーの味を想像するだけで、気持ち悪くなる。脳が拒否する。体が受け付けなくなる。ほどほどが良い。

 

コーヒープレスは濃厚な味

には、コーヒープレスを利用したコーヒーの入れ方が書かれている。

実際に、スタバのコーヒープレスを買って試した。確かに、濃厚で独特な風味となる。しかし、自分はこの味が苦手だったので、使うのをやめた。安物の粉を使っていたのがダメだったのだろうか。いつの間にか、コーヒープレスは行方知れずに。。

ちなみに、なぜ、味が違うかと言えば、

コーヒープレスはペーパーフィルターを使わない。つまりそれは、抽出された液体の中に、豆の味がそのまま閉じ込められている、ということになる。ペーパーフィルターを使用すると美味しさでもある豆の油分などがペーパーに吸収されていくが、コーヒープレスの場合、そういったことがない。

自宅でおいしいコーヒーを楽しむために (2) 後編 | マイコミジャーナルより)

 

アイスコーヒーには濃厚な味が最適

暑い時期は、アイスコーヒー。

コーヒーサーバーにドリッパーを乗せ、ペーパーフィルターでコーヒーを入れる。濃いめに淹れて、氷とミルクを注ぐ。しかし、何度やっても、いまいち美味しくない。100g で 100円という、一番安いランクの粉を使っているから、仕方ないと諦めていた。

たまたま、ペーパフィルターがなかった日。それでも、どうしてもコーヒーが飲みたかったので、代わりにお茶を淹れるための袋にコーヒーの粉を入れ、ドリッパーに乗せて、お湯を注いだ。

コーヒーサーバーには、薄くてマズそうな汁が溜まっていく。見た目で飲む気が全く失せた。仕方がないので、濃くするために、袋のまま、サーバーに溜まったコーヒーの中に突っ込み、しばらく待った。

表面には、うっすらと油分が浮き出て、液の色は濃くなった。相変わらず、不味そうな濁った焦げ茶色。

しかし、ミルクを入れ、アイスコーヒーにして飲んでみたら、濃厚でうまかった。 ^^ コーヒープレスのことは、すっかり忘れていたが、同じ味。アイスコーヒーには、この味が向いているようだ。

 

ティーポットを使った入れ方

これ以降、アイスコーヒーを作るときは、次のようにしている。
  1. ティーポットの中に、直接、コーヒーの粉を入れる。
  2. お湯を注ぐ。
  3. スプーンで、軽くかき混ぜる。
  4. 5分程度待つ。
  5. 茶こしで、コーヒーを注ぐ。

これで、コーヒープレスいらず。

DSC03375

 

カフェインをとりすぎると、頭痛が生じる

ところで、コーヒーに含まれるカフェインは、頭痛に効果があると言われる。

例えば、一般的な頭痛薬である SG顆粒 の成分には、

カフェイン..不快感や疼痛反応をやわらげます。また、血管性頭痛に対しては脳血管を収縮して鎮痛作用を示します。

これに対し、コーヒーの飲み過ぎが、頭痛を生じさせることがあるらしい。

コーヒー – Wikipedia によると、

一日に300mg以上(コーヒー3杯に相当)のカフェインを常用する人には、カフェイン禁断頭痛と呼ばれる一種の禁断症状が現れることがある。これは最後のカフェイン摂取から24時間以上経過すると偏頭痛様の症状が現れるものである。このカフェイン禁断頭痛は症状が現れてから、カフェインを摂取することで30分以内に消失するが、カフェインを摂取しない場合は2日程度継続する。

頭痛大学カフェイン禁断頭痛の国際頭痛学会定義 によると、

新基準(ICHD-Ⅱ) 8.4.1 カフェイン離脱頭痛 診断基準:

  • A. CおよびDを満たす両側性 および・または 拍動性の頭痛
  • B. 2週間を超えて、1日200mg以上のカフェイン摂取があり、それが中断または遅延されたもの
  • C. 頭痛は最後のカフェイン摂取後、24時間以内に発生し、100mgのカフェインにより1時間以内に軽快する
  • D. 頭痛はカフェインの完全離脱後、7日以内に消失する

同、カフェイン依存性頭痛 には、

  • 例えば、コーヒーを一日3杯、ドリンク剤を2本、鎮痛薬を毎日のむと
    一日500mgのカフェインをとることになります。
  • そして一日500mgを毎日のように摂るとカフェイン禁断頭痛が起こります(新基準では1日200mg以上)。

飲み過ぎには注意しませう。

2011年9月12日月曜日

Google Bookmarks を RSS で取得

XML で取得

Google Bookmarks を XML で取得するには、

特定の単語を検索したい場合は、以下を追加。

&q=単語

例えば、`hoge’ を対象にしたい場合、

( cf. Google ブックマークを XML で取得 )

 

問題点

上記のデータ取得方法は、公式なやり方ではない。そのためか、単語を検索した結果が、以前とは変わってしまったようだ。

以前は、以下に示す内容だった。

<xml_api_reply version="1">
	<bookmarks>
		<bookmark>
			<title></title>
			<url></url>
			<timestamp></timestamp>
			<id></id>
			<labels>
				<label></label>
			</labels>
		</bookmark>

これが次のようになった。

<xml_api_reply version="1">
	<bookmarks>
		<title></title>
		<url></url>
		<timestamp></timestamp>
		<id></id>
		<labels>
			<label></label>
		</labels>

比較するとわかるように、<bookmark> タグがなくなった。これにより、各ブックマークの境界が不明となった。

 

RSS で取得

これでは困るので、XML での取得をやめ、RSS で取得することに変更。

ソースを見たい場合は、Firefox ボタン > Web 開発 > ページのソースを表示。

特定の単語を検索したい場合は、

この結果は、ブックマークの境界として <item> が使われている。

<?xml version="1.0" encoding="UTF-8"?>
	<rss version="2.0" xmlns:smh="http://www.google.com/history/" xmlns:recommend="http://www.google.com/history/items">
		<channel>
			<title>Google ブックマーク</title>
			<link>http://www.google.com/bookmarks/</link>
			<description>Google - ブックマーク RSS フィード</description>
			<smh:signature></smh:signature>
			<smh:homepage_label></smh:homepage_label>
			<item>
				<title></title>
				<link></link>
				<pubDate></pubDate>
				<category></category>
				<description></description>
				<guid isPermaLink="false"></guid>
				<smh:bkmk></smh:bkmk>
				<smh:bkmk_id></smh:bkmk_id>
				<smh:bkmk_title></smh:bkmk_title>
				<smh:bkmk_label></smh:bkmk_label>
			</item>

このデータを元に、DOM に変換したい場合は、「JavaScript で XML を読み込む」を参照。

 

関連記事

2011年9月11日日曜日

Blogger の新しいインターフェイスで、改行が自動的に <br /> に変換されないようにする

1. 旧インターフェイスの改行設定

ブログを書くときは、Windows Live Writer を利用している。

WLW で書いた内容を HTML で表示させ、Blogger に貼り付けると余分な改行が入る。

このため、Blogger では、エディタに入力された改行は、<br /> タグに変換されないようにしている。Blogger のメニューより、

  • 設定 > フォーマット > 改行の変換

で「いいえ」を選択。

CropperCapture[321]

これにより、過去に投稿した記事を、ブラウザ上で編集しようとした場合、「HTMLの編集」モードで表示される。

CropperCapture[322]

 

2. 新インターフェイスの改行設定

最近、Blogger の新インターフェイスに移行した。

「新しい Blogger インターフェイスを使ってみる」

のリンクを選択。

CropperCapture[317]

新インターフェイスは、すっきりとしたデザインで、好感が持てた。ブラウザから記事を投稿するときの、エディタの表示領域が広くて使いやすい。

しかし、新しいインターフェイスで、以前に投稿した記事を修正した後、プレビューを表示させたところ、ブラウザ上で改行して見える箇所が <br /> に変換されてしまった。 (@_@; 旧インターフェイスでは、そのような設定にはしてなかったにも関わらず。

新しいインターフェイス上で、改行が <br /> に変換されない設定を探したけれど、メニューから

  • 設定 > フォーマット

がなくなっている。

CropperCapture[323]

新しいインターフェイスを使いたかったのに残念。。

…と思っていたが、記事を編集するエディタの右側に表示される

  • 投稿の設定 > オプション > 改行

に「<br> タグを使用」という選択があった。

CropperCapture[320]

一度、設定を変更したら、それ以降別の記事の編集、新規投稿でも、同じ設定になってくれた。

これで新インターフェイスに移行できる。 ^^

2011年9月6日火曜日

Haskell で特定の構造を前提としない関数 - 要素を辿る関数を必要に応じて定義

0. 概要

  1. 普通、「特定の構造に対して適用する関数」は、特定の型を前提として考える。
  2. これに対して、構造を辿る関数を与えることによって、「特定の型を前提としない関数」を定義することができる。

前者の方法と比べながら、後者について見ていく。

目次:
  • 1. 型を決めてから、関数を定義する
    • リストに適用する関数の場合
    • 木に適用する関数の場合
  • 2. 特定の構造を前提としない関数
    • treewalk 関数の引数について
    • 第4引数 walker がイメージしにくい理由
    • ノードを辿っていく関数 walker
    • treewalk 関数のまとめ
    • treewalk 関数の使い方
    • Data.Tree 型の値に対して treewalk 関数を適用
    • リストに対して treewalk 関数を適用
  • 3. 要素を辿っていく walk 関数について、はじめから再考
    • Data.Tree 型に対して、walk 関数を適用
    • リストに対して、walk 関数を適用
  • 3-1. walk 関数から、要素に適用する関数を分離
    • Data.Tree に対して、walk 関数を適用
    • リストに対して、walk 関数を適用
  • 3-2. walk 関数から、更に述語を分離
    • Data.Tree に対して、walk 関数を適用
    • リストに対して、walk 関数を適用

 

1. 型を決めてから、関数を定義する

リストに適用する関数の場合

リストの要素に、関数を適用するには、map 関数を使う。

例えば、要素を 2 倍したいなら、

*Main> map (* 2) [1..5]
[2,4,6,8,10]

map 関数は、「リスト」という構造を前提に定義されている。定義を確認すると、

map :: (a -> b) -> [a] -> [b]
map _ []     = []
map f (x:xs) = f x : map f xs

第 2 引数は関数の対象であるリスト。

第 1 引数である関数 f は、データコンストラクタ (:) を使い、リスト構造を辿っていくかのように見える。

 

木に適用する関数の場合

2 つの子を持つ「木」を、以下のように定義したとする。

data Tree a = Leaf a   | Branch (Tree a) (Tree a)
            deriving Show

適当に Tree a 型の値を作る。

tree = Branch (Leaf 1) 
              (Branch (Branch (Leaf 2)
                              (Leaf 3))
                      (Leaf 4))

木の「葉」が持つ値に、関数を適用する関数を mapTree とすると、

mapTree f (Leaf x)     = Leaf (f x)
mapTree f (Branch l r) = Branch (mapTree f l) (mapTree f r)

mapTree 関数を、変数 tree に適用してみる。

*Main> mapTree (*2) tree
Branch (Leaf 2) (Branch (Branch (Leaf 4) (Leaf 6)) (Leaf 8))

mapTree 関数も、先ほどの map 関数のように、適用する対象である Tree a  型の構造を前提としている。

型コンストラクタ Tree を、Functor クラスのインスタンスにするなら、

instance Functor Tree where
    fmap f (Leaf x)    = Leaf (f x)
    fmap f (Branch l r) = Branch (fmap f l) (fmap f r)

( cf .Haskell の fmap )

変数 tree に fmap を適用すると、

*Main> fmap (*2) tree
Branch (Leaf 2) (Branch (Branch (Leaf 4) (Leaf 6)) (Leaf 8))

この方法も、fmap を具体的に定義するとき、Tree a 型の構造を前提としている。

オブジェクト指向で何か考える場合も、問題領域の対象を整理し、クラスと構造を決めながら、メソッドを実装していく。型と構造を考えつつ、操作を割り当てる。構造を離れて、操作だけを考えることは難しい。

 

2. 特定の構造を前提としない関数

これに対して、「Scheme:オブジェクト指向表現」 の 抽象化の方向 には、オブジェクト指向と比べながら、関数指向のメリットが述べられている。

自分の理解した範囲で、簡単にまとめると、

  1. オブジェクト指向では、はじめに「型、構造」を想定し、それに相応しい操作を定義していく。これにより、「型、構造」と操作は不可分となり、操作のためのコンテナが必要となる。
  2. 関数指向では、「型、構造」を事前に想定しない関数を定義することができる。「型、構造」と操作が独立していることにより、必要な操作を、必要に応じて、定義することができる。これを実現するために、クロージャを用いる。

クロージャに関しては、以下を参照。

脱線するが、上記に関連して、「Why OO sucks」のオブジェクト指向に対する批判を、また、思い出した。

Objection 1 - Data structure and functions should not be bound together
Objects bind functions and data structures together in indivisible units. I think this is a fundamental error since functions and data structures belong in totally different worlds. Why is this?
  • Functions do things. They have inputs and outputs. The inputs and outputs are data structures, which get changed by the functions. In most languages functions are built from sequences of imperatives: "Do this and then that ..." to understand functions you have to understand the order in which things get done (In lazy FPLs and logical languages this restriction is relaxed).
  • Data structures just are. They don't do anything. They are intrinsically declarative. "Understanding" a data structure is a lot easier than "understanding" a function.

(装飾は引用者による)

Scheme:オブジェクト指向表現」 の 抽象化の方向に戻り、少し長めに引用する。

関数指向の考え方をちょっと示してみます。 与えられた「木」のすべての葉を深さ優先で辿り、与えられた処理を施して行く、という処理を考えてみます。 但し、木の具体的な実装はわかりません。…

関数型では、抽象的な「木」に関する可能な操作を直接関数で渡してやります。

  (define (tree-walk tree proc leaf? walker)
    (define (rec node)
      (walker (lambda (n) (if (leaf? n) (proc n) (rec n))) node))
    (if (leaf? tree) (proc tree) (rec tree)))

ここで、leaf? は木のノードを取り、それが葉かそうでないかを返す関数、 walkerは関数と木のノードを取り、ノードのすべての子供に対して渡された関数を適用する関数。…

関数指向のメリットは、tree型に対して適用可能な操作というものを限定していないことです。tree-walkを適用したくなったら、leaf? と walkerに相当する関数を(なんならその場ででも)作って渡してやれば良いのです。…

  • (Shiro) この木の例に関しては、コンスセルによる表現を全く仮定していないっす。 (walkerはリストを返す、とかいう制約もついていません)。コンスセルだろうがアレイだろうが適当なコンテナタイプだろうがファイルシステムだろうが、詳細をクロージャの中に隠蔽する、というのがクロージャ指向 :-) の流儀だと思います。

(装飾は引用者による)

先ほど述べたように、関数を適用する対象の構造を前提とせず、構造は後回しにして、関数を定義。クラス指向のように、型と操作が密結合してないので、必要に応じて、構造に対する操作を関数に渡せば良い。

しかし、例としてあげられていた関数を、スラスラと理解できないので、ゆっくりと確認していくことに。 (+_+)

とりあえず、Scheme は見慣れてないので、上記 tree-walk を Haskell で書いてみる。

treewalk tree proc isLeaf walker = if isLeaf tree 
                                   then proc tree
                                   else rec tree
    where
      rec node = walker (\n -> if isLeaf n
                               then proc n
                               else rec n)
                        node

if の部分を整理して、

treewalk tree proc isLeaf walker = treewalk' tree
    where
      treewalk' = \n -> if isLeaf n
                        then proc n 
                        else walker treewalk' n

う-ん、これでもまだ、動作のイメージがつかめない。。(@_@;

 

treewalk 関数の引数について

treewalk 関数の引数を、一つ一つ見ていく。

  • 第 1 引数 tree : treewalk を適用する対象
  • 第 2 引数 proc : 葉に適用する関数
  • 第 3 引数 isLeaf : ノードが葉である場合に、真を返す述語

イメージしにくいのは、第 4 引数 walker 。この関数が使われているのは、上記コードの3 行目。

walker treewalk’ n

tree-walk 関数の説明より、適用対象が「木」であるとき、walker の

  • 第 2 引数は、木のノード。(親ノード)
  • 第 1 引数は、木のノード(子ノード)に適用する関数。

となるように、利用が想定されている。ただし、あくまでも「想定」であり、使う側が機能を満たすように実装する必要がある。

 

第4引数 walker がイメージしにくい理由

treewalk 関数の機能は、以下の通りだった。

与えられた「木」のすべての葉を深さ優先で辿り、与えられた処理を施して行く

定義した関数の引数の名前を使い、言い換えると、

対象 tree に対して、要素が isLeaf 関数で真となる「葉」に、関数 proc を適用する

treewalk 関数の実装を見ると、すべての葉を「辿る」ための手段が具体的に書かれていない。いきなりノードに対する処理が記述されおり、walker が何をするか不明なまま、関数が再帰的に定義されているように見える。この点がイメージしにくいところ。

 

ノードを辿っていく関数 walker

CropperCapture[310]木のノードを辿るには、親ノードから、その子ノードへ辿る方法が必要となる。どこかに定義されていなくては、木の要素を辿れない。 treewalk 関数において、その具体的な方法が期待されるのが walker 。

walker を加え、もう一度、言い換えると、

対象 tree に対して、要素を辿るために walker を使い、要素が isLeaf 関数で真となる「葉」に、proc を適用する

今回は、すべての葉を対象に proc 関数を適用したい。よって、次のように walker の役割を想定することになる。

  • 第4引数 walker : 与えられたノードから辿ることのできる、子ノードに対して、関数を適用する。

このように、walker にノードの辿り方を任せるメリットは、treewalk 関数のような、特定の構造を前提としない関数を定義できることにある。関数の適用対象の構造が変われば、walker を取り替えるだけで済むため、異なる構造に対して、共通部分を抽出できる。

結果的に walker を、

構造を結びつける関数

と見なすことができる。

 

treewalk 関数のまとめ

treewalk で行っていることをまとめると、

  1. 対象のノードが葉の場合、ノードに proc を適用する。
  2. 対象のノードが葉ではない場合、walker に、そのノードと関数を与え、与えたノードから辿ることができる子ノードに関数を適用する。

treewalk 関数の型を調べると、

treewalk
  :: t1 -> (t1 -> t) -> (t1 -> Bool) -> ((t1 -> t) -> t1 -> t) -> t

第1引数が、特定の型に縛られていないことがわかる。

 

treewalk 関数の使い方

先ほど使った変数 tree に、treewalk 関数を適用するには、次のように引数を与える。

main = do print $ treewalk tree
                           (\(Leaf x) -> Leaf (x * 2))
                           (\n -> case n of
                                    Leaf _     -> True
                                    Branch _ _ -> False)
                           (\f (Branch l r) -> Branch (f l) (f r))
  • 第2引数は、葉に対する処理。
  • 第3引数は、葉であるときに真を返す関数。

第 4 引数の walker は、親となるノード(walker の第 2 引数)から、辿ることができる子ノードに対して、関数(walker 関数の第1引数)を適用する。結果は、以下のようになる。

Branch (Leaf 2) (Branch (Branch (Leaf 4) (Leaf 6)) (Leaf 8))

 

Data.Tree 型の値に対して treewalk 関数を適用

同じ treewalk 関数を使い、Data.Tree 型の値に適用してみる。

import Data.Tree

tree2 = Node 1 [ Node 2 []
               , Node 3 [ Node 4 []
                        , Node 5 []
                        , Node 6 []]]

これに対して、

main = print $ treewalk tree2
                        (\(Node x xs) -> Node (x*2) xs)
                        (\n -> case n of
                                 Node x [] -> True
                                 otherwise -> False)
                        (\f (Node x xs) -> Node x (map f xs))

子を持たない Node を「葉」と見なし、ノードを辿る walker は、先ほどの定義を少し変更するだけで済んだ。

CropperCapture[311]

結果は、

Node { rootLabel = 1
     , subForest = [ Node { rootLabel = 4
, subForest = []
                          }
                   , Node { rootLabel = 3
                          , subForest = [ Node { rootLabel = 8
, subForest = []
                                               }
                                        , Node { rootLabel = 10
, subForest = []
                                               }
                                        , Node { rootLabel = 12
, subForest = []
                                               }
                                        ]
                          }
                   ]
     }

ちなみに、「葉」に対してのみ、関数が適用されるので、子を持つノードの値は変わらない。

 

リストに対して treewalk 関数を適用

では、treewalk 関数を使って、リストの要素を 2 倍できるだろうか?

リストの場合、各要素をすべて「葉」と見なし、walker が次の要素へと辿るように考えればいいのかな…

CropperCapture[312]

          print $ treewalk [0..5]
                           (\(x:xs) -> (x*2) : xs)       
                           (\_ -> True)
                           (\f n -> case n of
                                      x : xs -> x : f xs
                                      [] -> [])

しかし、結果、要素は 2 倍されなかった。。 (+_+)

理由は、treewalk が proc を適用するのは「葉」に対してだけれど、walker がノードを辿るのは、葉ではない要素であるため。リストの各要素を、「葉である」と同時に「子ノードを持つ」と見なしたので、proc を適用できなかった。先ほど Data.Tree 型の値に対して、treewalk 関数を適用したら、子を持つノードの値が変わらなかったことと同じ。

 

3. 要素を辿っていく walk 関数について、はじめから再考

treewalk 関数のように、要素を辿る関数について、単純な形から考えてみる。

まずは、以下の 2 つの引数を与える関数。

  • 第 2 引数: ノード (node)
  • 第 1 引数: 上記ノードから辿ることができる要素に、関数を適用していく、と想定する関数 (walker)

関数名を walk とすると、定義は以下の通り。

walk walker node = walker (\n -> walk walker n) 
                          node

改めて、適用対象の「木」の型を、以下のように定義する。

data BinaryTree a = Leaf a 
                  | Branch (BinaryTree a) a (BinaryTree a) 
                  deriving Show

適当に値を作る。

tree = Branch (Leaf 1)
              100
              (Branch (Leaf 2)
                      200
                      (Leaf 3))

これに対し、walk 関数を適用してみる。要素を辿るだけで、何もせず、そのまま返すには、

  print $ walk (\f n -> case n of
                     Leaf x -> Leaf x
                     Branch l x r -> Branch (f l) x (f r))
               tree
=> Branch (Leaf 1) 100 (Branch (Leaf 2) 200 (Leaf 3))

葉を 2 倍し、枝を 3 倍するなら、

  print $ walk (\f n -> case n of
                     Leaf x -> Leaf (x*2)
                     Branch l x r -> Branch (f l) (x*3) (f r))
               tree
=> Branch (Leaf 2) 300 (Branch (Leaf 4) 600 (Leaf 6))

 

Data.Tree 型に対して、walk 関数を適用

次に、先ほど使った Data.Tree 型の値 (tree2) に、同じように walk 関数を適用してみる。

  -- 何もしないで、そのまま返す
  print $ walk (\f n -> case n of
                          Node x [] -> Node x []
                          Node x xs -> Node x $ map f xs)
               tree2

  -- 葉を 2 倍し、枝を 3 倍する
  print $ walk (\f n -> case n of
                          Node x [] -> Node (x*2) []
                          Node x xs -> Node (x*3) $ map f xs)
               tree2

 

リストに対して、walk 関数を適用

リストに対して、walk 関数を適用してみる。

  print $ walk (\f n -> case n of
                          []     -> []
                          x : xs -> x : f xs)
               [0..5]

  print $ walk (\f n -> case n of
                          []     -> []
                          x : xs -> (x*2) : f xs)
               [0..5]

 

3-1. walk 関数から、要素に適用する関数を分離

上記の方法は、

  1. ノードを辿っていくこと
  2. ノードに関数を適用すること

の 2 つを同時に行っている。これを分離したい。

「ある構造を持つ型に対して、各要素を辿り、特定の関数を適用する関数」に変更。

walk f walker node = walker (\n -> walk f walker n) 
                            (f node)
  • 第1引数 f は、要素に適用する関数。

その他は同じ。

これを使い、何もしないで、そのまま返すには、

  print $ walk id
               (\f n -> case n of
                          Leaf x       -> Leaf x
                          Branch l x r -> Branch (f l) x (f r))
               tree
=> Branch (Leaf 1) 100 (Branch (Leaf 2) 200 (Leaf 3))

要素を辿る関数を使いまわしたいので、別に定義しておく。

walkBinaryTree _ (Leaf x)       = Leaf x
walkBinaryTree f (Branch l x r) = Branch (f l) x (f r)

葉は 2 倍し、枝を 3 倍するなら、

  print $ walk (\n -> case n of 
                        Leaf x       -> Leaf (x*2)
                        Branch l x r -> Branch l (x*3) r)
               walkBinaryTree
               tree
=> Branch (Leaf 2) 300 (Branch (Leaf 4) 600 (Leaf 6))

要素に適用する関数も使いまわしたいので、別に定義。

doubleLeafTripleBranch (Leaf x)       = Leaf $ x*2
doubleLeafTripleBranch (Branch l x r) = Branch l (x*3) r

要素を辿ったとき、リストを返して欲しいなら、

walkBinaryTree2List _ (Leaf x)       = [x]
walkBinaryTree2List f (Branch l x r) = x : f l ++ f r

これを使い、

  print $ walk doubleLeafTripleBranch
               walkBinaryTree2List
               tree
=> [300,2,600,4,6]

逆に辿りたい場合は、辿り方を変更する。

reverseWalkBinaryTree2List _ (Leaf x)       = [x]
reverseWalkBinaryTree2List f (Branch l x r) = f r ++ f l ++ [x]

これを使い、

  print $ walk doubleLeafTripleBranch
               reverseWalkBinaryTree2List
               tree
=> [6,4,600,2,300]

 

Data.Tree に対して、walk 関数を適用

次に、Data.Tree 型の値を対象にする。

Node の辿り方と、要素に適用する関数を予め定義。

walkTree f (Node x xs) = Node x (map f xs)

doubleNodeTripleBranch (Node x []) = Node (x*2) []
doubleNodeTripleBranch (Node x xs) = Node (x*3) xs

これを使い、

  print $ walk doubleNodeTripleBranch
               walkTree
               tree2
=> Node { rootLabel = 3
        , subForest = [ Node { rootLabel = 4
                             , subForest = []
                             }
                      , Node { rootLabel = 9
                             , subForest = [ Node { rootLabel = 8
                                                  , subForest = []
                                                  }
                                           , Node { rootLabel = 10
                                                  , subForest = []
                                                  }
                                           , Node { rootLabel = 12
                                                  , subForest = []
                                                  }
                                           ]
                             }
                      ]
        }

 

リストに対して、walk 関数を適用

同じく、リストの場合。

要素の辿り方と、要素に適用する関数を予め定義しておく。

walkList _ []     = []
walkList f (x:xs) = x : f xs

doubleElem [] = []
doubleElem (x:xs) = (x*2) : xs

これを使い、

  print $ walk doubleElem
               walkList
               xs
=> [2,4,6,8,10]

 

3-2. walk 関数から、更に述語を分離

次に、変数 tree に戻り、「偶数であるノードの値」に対して、葉を 2 倍し、枝を 3 倍したいとする。

  print $ walk (\n -> case n of
                        Leaf x       | even x    -> Leaf (x*2)
                        Branch l x r | even x    -> Branch l (x*3) r
                        node                     -> node)
               walkBinaryTree
               tree
=> Branch (Leaf 1) 300 (Branch (Leaf 4) 600 (Leaf 3))
  • 要素に対して関数を適用する
  • 要素が条件を満たしているか検査する

という 2 つのことを同時に行っているので、これを分離してみる。

walk p f walker node = walker (\n -> walk p  f walker n) 
                              (if p node then f node else node)

第1引数 p は述語で、これが真である場合、第2引数 f をノードに適用する。

予め、ノードの値が、偶数である場合、真を返す述語を定義。

isNodeEven (Leaf x)       | even x = True
isNodeEven (Branch l x r) | even x = True
isNodeEven _                       = False

これを使い、

  print $ walk isNodeEven
               doubleLeafTripleBranch
               walkBinaryTree
               tree
=> Branch (Leaf 1) 300 (Branch (Leaf 4) 600 (Leaf 3))

結果をリストにするなら、

  print $ walk isNodeEven
               doubleLeafTripleBranch
               walkBinaryTree2List
               tree
[300,1,600,4,3]

 

Data.Tree に対して、walk 関数を適用

Data.Tree 型の値を対象にする場合、

  print $ walk (\n -> case n of
                        Node x xs | even x -> True
                        otherwise          -> False)
               doubleNodeTripleBranch
               walkTree
               tree2
=> Node { rootLabel = 1
        , subForest = [ Node { rootLabel = 4
                             , subForest = []
                             }
                      , Node { rootLabel = 3
                             , subForest = [ Node { rootLabel = 8
                                                  , subForest = []
                                                  }
                                           , Node { rootLabel = 5
                                                  , subForest = []
                                                  }
                                           , Node { rootLabel = 12
                                                  , subForest = []
                                                  }
                                           ]
                             }
                      ]
        }

 

リストに対して、walk 関数を適用

リストを対象にする場合、

  print $ walk (\n -> case n of
                        x : _ | even x -> True
                        otherwise      -> False)
               doubleElem
               walkList
               xs
[1,4,3,8,5]

このように、構造を辿る方法を抽象化しておくと、同じ関数を使い回し、組み合わせることができるようだ。

 

参考サイト

Google Chrome で Scratchpad を使ってメモを取る - 保存先は Google Docs。廃止される Google Notebook の代わりに利用する

1. Firefox の Quick Note はブックマークとしてメモを保存する

a. Firefox の QuickFox Notes

Firefox でメモを取るとき、QuickFox Notes を利用している

QuickFox Notes に書いた内容はブックマークとして保存される。そのため、ブックマークを同期することにより、複数の PC でデータを共有できる。

QuickFox Notes と同じ機能を持つメモを Google Chrome でも使いたい。

 

b. Google Chrome の Quick Note

Google Chrome ではメモ用の拡張機能として、Quick Note の評価が高い。

データの保存と同期に関して、Quick Note によると、

- Dropbox, box.net, Google docs, Evernoteといったクラウドベースのサービスとの統合も考えています

現在は Diigo (Plans and Pricing) というサービスを利用するようだ。

自分の場合、文書を Google Docs で管理しているので、Google Docs と連携するメモ帳を使いたい。

 

2. Google Chrome の Scratchpad は Google Docs に保存できる

Scratchpad はメモを Google Docs に保存できる。PC を新しくしたときに、データの移行に頭を悩ます必要がない。
a. Google アカウントで認証

メモを Google Docs に保存する設定は、インストール後、Google のアカウントで認証を行う。

Scratchpad のウィンドウが表示されたら、Get started を選択。(表示されない場合、拡張機能より、オプションを選択。)

CropperCapture[312]

次に Authorize を選択。

CropperCapture[313]

Google アカウントで認証を行うために、「アクセスを許可」を選択する。

CropperCapture[314]

 

b. メモの作成と、Google Docs 上での表示

ウェブページ上で、右クリック > New note を選択することにより、新規ノートが作成される。

ノートを追加するには、ノートの一覧が表示した状態で、左上の `+’ ボタンを押す。

CropperCapture[315]

メモのタイトルと、内容を書いた後、左上のボタンを押して、一覧に戻ると …

CropperCapture[317]

作成したメモのタイトルが表示される。

CropperCapture[318]

Google Docs を開くと、`Scratchpad’ という名前のコレクション(フォルダ)に保存されているのが確認できる。

CropperCapture[316]

 

c. 独立したアプリケーションのように利用するために

Google Chrome において、新しくタブを開き、画面下部の「アプリケーション」を選択する。

アプリケーションの中の Scratchpad のアイコンを右クリック > ショートカットを作成

CropperCapture[320]

タスクバーに固定」を選択して作成。

CropperCapture[321]

これにより、アイコンがタスクバーに表示され、独立したメモアプリのように扱える。

 

3. Scratchpad の一覧が表示されなくなったら、拡張機能を再インストール

追記(2012/08/01): Scratchpad を起動したら、これまで作成したメモの一覧が消えてしまった。ただし、ブラウザ上で Google Docs を確認すると、Scratchpad フォルダに作成したメモが存在していた。

この場合、

  1. 一度 Scratchpad を削除し、
  2. 再インストールし、同期の設定をし直す

と元に戻る。

Scratchpad を独立したウィンドウとして表示できなくなった場合も、再インストールすると直る。

 

4. その他

ノートを共有するのは問題がある

現在、ノートを他人と共有することに、やや難がある。今後改善されたら、Google Notebook の代わりに使えそうだ。最近 Google Notebook のサービス自体の終了が発表されたので、このアプリケーションを代替にしたい。

Google、終了予定サービスを発表 「Google Desktop」や「Web Security」も - ITmedia エンタープライズ

Google Notebook

2006年にスタートしたオンラインメモサービス。Webページの画像やURLをまとめて保存し、共有できる。このサービスは数カ月のうちに終了になり、ユーザーのデータは同じアカウントで利用しているGoogle Docsに自動的にエクスポートされる。

Google Notebook が開発中止になったときは、テンション下がったなぁ。 (+_+)

 

Tab Position Customizer を併用する場合

Tab Position Customizer でポップアップするウィンドウをタブに開く設定にしている場合、

  1. 独立したアプリケーションとして起動した後、
  2. 「タブに送る」ボタンを押し、
  3. 再度元の独立した状態に戻そうと「パネルに送る」ボタンを押しても元に戻らない。

これに対処するには、

  1. タブに送った Scratchpad のタブをすべて閉じた後、
  2. タスクバーから Scratchpad を起動すれば良い。

 

g. Firefox でリンクを開きたい場合

Scratchpad でリンクを開くと、Google Chrome でページが開かれる。

Firefox でリンクを開きたい場合は、

  1. リンクを含んだ文字をクリックし、
  2. 表示された URL を Firefox へ D&D する。

Firefox におけるタブのアニメーションを切る

CPU が Core 2 Duo だと、もう時代遅れなのかな?全体的に、ややもっさりとした動きにストレスを感じる。

Firefox では、操作によって、アニメーションで表示される。少しでもこれを抑制して、レスポンスを良くしたい。

 

Configuration Mania で設定

アドオン「Configuration Mania」をインストール。

設定画面の

  • ブラウザ > タブブラウジング > アニメーション

における、

  • タブの開閉
  • タブグループ

のチェックをはずす。

CropperCapture[308]

「タブのグループ分け」 (Panorama) を多用するので、もさっとしたアニメーションが切れてよかった。

2011年9月5日月曜日

フィードを全文配信する Full Text RSS Feed Builder を開くためのブックマークレット

1. フィードを全文配信してほしい

フィードを全文配信してないサイトを、Google Reader に登録するとき、「まるごとRSS」 を使っていた。

全文配信されてないサイトは、いつの間にか読まなくなる。部分的にフィードを配信しているサイトは、全文配信されるように変換しておきたい。

 

2. フィードを全文配信してくれる Full Text RSS Feed Builder

Full Text RSS Feed は、まるごとRSS と同じように、フィードを全文配信するためのサービス。

部分的に配信しているRSSフィードを全文配信に変換してくれるサイト「Full Text RSS Feed Builder」 : ライフハッカー[日本版]によると、

「Full Text RSS Feed Builder」は、部分的にRSSを配信しているフィードを全文配信に変換してくれるサービス。…

まず、Full Text RSS Feed Builderにアクセスしましょう。変換したいRSSフィードを入力して「Submit」します

Full Text RSS Feed の特徴を確認すると、

no ads

広告が表示されないので、ありがたい。 こちらに乗り換えよう。

 

3. Full Text RSS Feed Builder を開くためのブックマ-クレット

毎回 Full Text RSS Feed を開くのは面倒なので、ブックマークレットを作っておく。 以下をブックマークに D&D 。

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

(function(){
    var l=location,
        url="http://fulltextrssfeed.com/";
    l.href=url+l.host+l.pathname;
})();

 

4. フィードの画像が表示されないときの対策

登録したフィードの画像が表示されないとは、

を参照。