document_lang: ja

langs: ja en ja ja ja ja ja ja ja ja ja ja ja en en en en ja ja ja ja ja de ja de ja ja ja en en en ja en ja en ja uk ja ja ja ja ja ja en en ja en ja en ja en ja en ja ja ja en ja ja en ja en ja ja pl ja ja en ja ja ja ja en en ja ja en ja en ja ja en ja ja en ja en ja en ja en ja zh en ja ja ja ja ja ja en ja ja ja ja ja ru ja en en ja ja ja ja ja en ja ja en ja ja ja ja ja en ja en ja ja ja ja ja ja ja en ja en en ja en ja ja ja hbs_lat ja ja ja ja ja ja ja ja en en ja ja en ja ja ja en ja ja ja en ja en ja ja en en ja en ja ja en zh ja ja ja ja ja en ja ja en ja en ja ja pl ja en ja en ja en ja en ja en en ja ja en en ja en ja en ja en ja en en ja ja en ja en ja ja en en zh ja ja ja en ja ja ja ja ja ja ja ja ja en ja ja en ja en ja ja ja en ja en en ja ja en ja en en ja ja en ja en ja br en ja ja ja en ja en ja ja en en en ja ja en ja ja en en ja en ja en ja ja en en ja en en ja ja ja ja en ja ja ja ja ja ja en ja en ja en tr en ja ja ja en ja tr ja en ja ja en ja ja ja ja ja es ja en ja en ja ja en ja ja en ja ja ja ja ja ja ja en ja en ja en ja ja en en ja en ja ja ja ja ja en ja ja ja ja ja ja ja ja ja ja en ja en ja ja ja ja ja en ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja en zh sv zh fr zh de zh de zh ja en ja ja en ja ja en en ja ja ja ja en ja ja ja en ja en ja ja en ja en en ja ja ja ja hbs_lat ja ja en ja ja ja hbs_lat ja en en ja ja en ja en ja en zh ja en ja ja en en zh ja en ja en ja ja en ja ja ja en zh ja ja ja ja ja ja ja ja ja zh ja tr ja tr ja en ja ja en ja en ja de en ja ja en ja ko ja ja en ja ja tr en ja ja en ja tr en ja ja tr ja tr ja en ja en ja ru ja ja en ja ja ja en ja ja en ja ja en en en ja en ja ja tr ja ja tr ja tr ja tr ja tr ja en ja ja ja ja ja en ja en ja en ja ja ja ja ja ja ja en ja ja ja en ja en ja ja en ja ja el ja en en ja en ja ja ja en ja ja en ja en ja en ja ja el ja ja ja ja ja ja ja en ja fr ja ja en ja ja fr ja ja en ja en ja en en ja ja ja ja en ja ja ja en ja ja en ja ja ja en ja en ja ja ja ja en en ja ja ja ja ja ja ja ja zh ja ja en en ja ja en ja en en zh ja en ja en ja ja en en en ja ja ja ja en ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja en en ja en ja ja ja ja en en ja ja ja en en ja en ja ja en ja en ja ja en ja en en en en ja ja en ja en ja ja zh ja en ja en ja ja ja ja ja ja en ja en en ja ja zh en ja en ja ja en ja en ja ja en en ja ja ja en ja ja en ja en ja ja ja ja en ja ja zh ja en en ja en ja en ja en en ja ja ja ja ja ja ja ja ja en zh ja ja en ja en ja en ja ja ja ja ja ja ja ja ja ja ko ja ja en ja ja ja ja en en ja ja ja en en en ja en en ru ja en ja en ja ja ja en ja en ja ja ja ja ja ja ja ja ja ja ja ja ja ja en ja en ja ja ja ja en ja en en ja ja en ja zh ja ja ja ja ja ja en ja ja en ja hbs_lat ja tr ja ja ja ja en ja ja en ja ja ja en ja ja ja en ja zh en ja ja ja ja ja en ja hbs_lat ja ja ja ja ja ja en ja ja en ja en en ja en ja en ja en en ja en ja en en ja en ja en ja en en ja en ja da en en ja en ja en en ja en ja ja ja ja ja ja en ja ja ja en ja ja tr en kn ja ja ja en ja en ja en ja ja en en ja ja ja en en en en en en ja ja ja ja ja ja ja ja ja en ja ja ja ja en ja ja ja ja ja ja ja fr en ja en ja ja ja ja ja ja ja ja ja ja ja ja ja ja cs zh cs zh ja zh zh zh de zh zh zh zh zh zh zh zh de zh zh zh zh zh zh zh ja ja zh zh zh de zh zh zh zh zh zh zh zh ja zh zh zh cs zh zh zh zh zh zh zh zh zh zh zh cs zh zh zh zh zh zh zh zh ja zh zh zh cs zh zh zh zh zh zh zh zh ja zh zh zh cs zh zh zh ja zh zh zh zh zh zh zh zh fr ja zh ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja en ja ja ja ja ja zh zh zh zh ja zh zh zh cs ja zh zh zh zh zh zh zh ja zh zh ja en en es hu en sv en en en en it it fr en en en it en en it pms nb pt en en pt pt en en cs pt en en pt en it pt it it en ilo en it it en it it en pt en en en en en en pt en nb en it it hu en ceb en en en fr ceb it pt en it en en fr en en pt en it it it fr en it en en es en en en en es en en en en en en en it en it en en et en pt it de jv cv en en en en en en en en en en en en en en en en en en en en en en en ca ja ja ja ja ja en en it en en hu it en en it it hu hbs_lat en pt hbs_lat en it ia en it it en en ja en it en cs hu cs it en it uk en it en en it is en it pl en en en pt en en it mk it it hu en it en en it en it en en zh it pt es hu en en it en en en en en en en it pt en la de it pt it en it it pt en it it it it en et es it en en en it en en pt en it en pl en en it en en la it it en hu it fr it en en en nb et en it en kk en is it it it en en en fr en hu en pt en ca hbs_lat en pt it es pt en it it it de it zh it ja ru te it it cs en en en pt it en en en it cs en ja ja ca cs ja en it hu en it en en en en it it pt en en en en en et it it en ko ro gl en es pt en en pt en sk ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ca ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja zh ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ko ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja es ja ja ja ja ja ja ja ja ja ko zh ja ja ja ja ja ja zh ja ja zh zh zh zh ja it ja ja zh ja hu ja ja ja ja hu ja ja ja ja ja ja ko ja ja hu ja hu ja ja ja ja ja it ja ja ja ja zh ja ja zh ja ja zh zh ja zh ja it hu zh ja hu ja ja ru ja ja ja ja zh ja ja ja gl ja ja ja ja ja ja zh ja ja ja ko ja ja ja zh ja hu zh ja ja zh ja ja ja zh ja ja ja ja ja ja ja ja ja ja ja ceb ja ja zh zh zh hu ja ja zh ja ja ja zh ja ja ja zh ja ja ja ja ja zh zh ja ja zh ja zh zh ja zh ja ja zh ja hu ja zh ja hu zh ja ja ja it ja ja zh ja zh zh hu ja zh ja it ja hu zh zh zh zh zh ja zh ja zh ja zh ja zh ja zh zh ja ja ja zh ja ja hu ja ja ja zh zh ja ja hu zh ja ko zh zh zh zh zh ja it zh ja ja ja ja zh zh zh ja ja ja ja ja ja ja zh zh ja pt it vi hu ja ja ja ja it ja ja ja it ja ja ja zh ja hu ja zh zh hu ja zh it en

text:
投稿者 KURITA Jute 時刻: 16:55 0コメント
落ち着く音楽はないかな? - I Will See You Again
イライラしているときは、いくら昔好きだったレーベルだとは言え、さすがに Tresor を聞くことはあまりない。アコースティックギター で何か落ち着く感じのものはないかなと、Last.fm を BGM に流していたら、いい音楽に出会えた。 ^^
Andy McKee – I Will See You Again – @ Last.fm
YouTube - I will see you again - Andy Mckee
Andy McKee – Drifting –  @ Last.fm
ART OF MOTION ANDY McKEE
Andy McKee – The friend I never met – @ Last.fm
こちらは、「I Will See You Again」と同じく「DREAMCATCHER 」に。
Andy McKee ラジオ – Last.fm
投稿者 KURITA Jute 時刻: 0:19 0コメント
データコンストラクタによるパターンマッチというと、例えば、以前に Person 型を定義して、Show クラスのインスタンスにしたときに実装した show メソッドの引数での利用が挙げられる。(cf. Haskell で代数的データ型の値を print で出力には)
data Person = Person {name :: String, age :: Int} instance Show Person where show (Person name age) = "Person: " ++ name ++ ", " ++ show age main = print (Person "Tarou" 20)
リストにも当然ながらデータコンストラクタが存在する。(cf. ふつうのHaskellプログラミング , p.173) 普段よく見る「リストによるパターンマッチ」、
「エラトステネスのふるい」でも、リストの先頭要素 p と、先頭以外のリスト ps にパターンマッチさせている。
こういうのがリストのパターンマッチだと最初頭に入れてしまったので、それ以外の方法が頭の隅から追いやられてしまっていた。 (@_@;) それに気づかされたのが、Haskell (programming language) - Wikipedia, the free encyclopedia に書かれていた「逆ポーランド記法」を計算するための関数の例。
The Haskell 98 Report: 定義ずみの型とクラス によると、
data  [a]  =  [] | a : [a]  deriving (Eq, Ord)
リストは、二つの構築子をもつ代数的データ型であるが、3.7 節で述べたように特別な構文をもつ。最初 の構築子は空リストで、`[]' (「ニル」)と書く。二つ目の構築子 は、`:' (「コンス」)と書く。
cons - Wikipedia, the free encyclopedia
上記の引用にあるように : , [] は特別な構文。他のデータコンストラクタとは違う形をしている。そのため、関数における引数のパターンマッチにおいて、「これはデータコンストラクタによるパターンマッチなんだ。」という意識が薄れてしまっていた。
fold についても復習。(cf. Haskell の foldl , foldr)
calc = "1 2 + 3 *" calc = foldl f [] ["1","2","+","3","*"]
関数 f は先ほど foldl の型で見たように、二つの引数を取るので、最初は…
これをファイルに保存して、GHCi 上で :l によりロード。:t f で関数 f の型を見ると、
投稿者 KURITA Jute 時刻: 14:40 0コメント
素朴にエラトステネスのふるい (3) – Python の実装を Haskell へ
前回、再帰的な表現を関数からオブジェクトのメソッドに移すことにより、再帰関数のイメージを複数のオブジェクトの連鎖として理解しようと試みた。実際にオブジェクトが連鎖する場合の実装を Python でしてみたが、今回はこのイメージに沿うように Haskell のコードを変更してみる。
… 呼出すごとに返り値の違うメソッドが作れるのは、Java に (再) 代入があるからです。言語に (再) 代入があると、ある式を、それと等しい値で置き換えられなくなります。つまり、参照透明でなくなります。
Real World Haskell においてもその冒頭で、Why functional programming? Why Haskell? として、
In Haskell, we de-emphasise code that modifies data. Instead, we focus on functions that take immutable values as input and produce new values as output. Given the same inputs, these functions always return the same results. This is a core idea behind functional programming.
考えてみると、前者は当然ながらグローバル変数に限った話ではない。インスタンス変数然り、ローカル変数もまた然り。例えばもし、巨大なクラスがあり、そこにたくさんのインスタンス変数があって、複数のメソッドからいじられているコードを見たら、変更する気が失せる。(+_+) 加えて、テストコードが付属してないなら最悪で、そのままふたをして地中深くに埋めておきたくなってしまう。^^; ローカル変数にしても同じ。「リファクタリング」の「問合わせによる一時変数の置き換え」の対象くらいのものだったらいいけれど、複数の仕事を長々と、 for や if のネスト祭りで、一画面以上に渡り変数がボカスカとひっかき回されているメソッドを見たら、脳みそ沸騰、そして卒倒。(o_ _)o~† インスタンス変数と呼んではいるけれど、人の認識にとってグローバル変数と等価なものは本当に勘弁してほしい。
正直、自分の容量の小さい脳みそでは、成長過程にあるクラスにおいてインスタンス変数が画面から徐々に見えない位置になるに従って徐々にやばくなる。複数のメソッドからインスタンス変数に変更を加えたり、状態に応じたコードを書く段になると目が回りだし、テストコードを書きながらでないとエラー連発。ストレス爆発。昔、「リファクタリング」を読んでいなかったらと思うと、ぞっとする。(@_@;) 長いメソッドや、巨大なクラスを書いて平気な人は、きっと記憶力がいいか、もしくは頭がいいのだろうと思う。自分のように、昨日書いたコードの内容なんて忘れてしまうタイプの脳みそでは全く無理。^^; そういった意味で、もしかすると Haskell が書けるようになったら楽できるかも、という密かな期待が…。
そうえいば、Haskell をさわっていて、はじめに連想したのがリファクタリングだった。メソッド一つの意味を明確にするという動機が、結果的にあらゆるローカル変数・インスタンス変数のスコープを小さくすることに貢献し、問題の局所化と変更への耐性を上げていく。コンパクトでシンプルなものは、理解しやすいし変更しやすい。Haskell に慣れて書けるようになったら、自然とそういたったコードに落ち着くのかな (?) とか思いつつ、未だコンパクトな再帰で目を回しているので、先は長い… ^^;
と、ここで以前に「まるごと JavaScript」 の「Flash の ActionScript で関数型風プログラミング」の記事に「関数型プログラミング」の説明が書かれていたことを思い出した。それによると、
counter 変数はカウンタを表現しており、内部でカウンタの値の状態(state) とカウンタの増分 (step) を持っている。next_counter 関数は、与えられたカウンタオブジェクトの値から新しくオブジェクトを作って返す。
これを Firefox の Firebug 上で実行すると結果は、
Object state=0 step=1 Object state=1 step=1 Object state=2 step=1 Object state=3 step=1 Object state=4 step=1 Object state=5 step=1 Object state=6 step=1 Object state=7 step=1 Object state=8 step=1 Object state=9 step=1 Object state=10 step=1
これを見て更に思い出したのが、Joshua Bloch の Effective Java の「項目 13 不変性を選ぶ」という節。そこでは 複素数 (Complex) クラスにおける不変性について説明されていた。(p.62) 以下は Complex クラスにおける足し算の例。
public Complex add(Complex c) { return new Complex(re + c.re, im + c.im); }
String str = "ABC"; str.toLowerCase();
これに加えて「項目 24 必要な場合には、防御的にコピーする」(p.114) も参考に。実装例は以下を参照。コンストラクタにおいて可変オブジェクトを受け取ったら、それを元にして新しくオブジェクトを生成してフィールドに設定。また、get メソッドにおいても、同様にクライアントに渡す前に新しくオブジェクトを生成して渡している。
ふつうのHaskellプログラミング を見ると、 「9.2 代数的データ型」の「多相的な型の宣言」「再帰的な型」(p.232)、また、「フィールドの更新」(p.228) 辺り が参考になりそう。
Implementation of basic functions にはスタックの Haskell での実装例が書かれていた。
最初に、以下のような多相的な型をフィールドに持つ Stack a 型の定義がある。 (Type declaration より)
data Stack a = MakeStack [a]
push の実装は Implementation of basic functions に、
なるほど、第一引数 Stack a 型の値を `オブジェクト’ 、関数名 push を `メソッド’ と見たてれば、クラスによる実装と同じように見える。ただし、違うのは、返される値が「引数を元に作られた新しい値」であるということ。
また、pop を見ると、返される値がタプルであれば、pop で取り出した値と、pop した後のスタックを返すことができることがわかる。言われてみれば当り前だけれど、「なるほど (@_@) こうすればいいのか」と思った。(同上より)
data Sieve = Sieve { list :: [Int], -- ふるいにかける前の数値のリスト tail :: Sieve -- リストの先頭要素でふるいにかけた後、 --「このふるいから落ちた数値のリスト」を保持するふるい } | Empty deriving Show
前回の Python の実装と違うところは、「ふるいにかけるときの基準となるリストの先頭要素」を保持するフィールド head がないこと。これは右図のピンク色の数値に相当するが、「ふるいにかける前のリスト」から取得できるので、わざわざ作る必要がないことに気がついた。
データコンストラクタ Empty は、Python のコンストラクタ内において、self.tail = None と設定していることに相当するものを書きたいため。
次に、連続してふるいにかけていく動作を書いてみる。ここが Python とは異なるところ。先ほどのスタックの push の実装を真似して、「ふるいにかけたら、ふるい」が返ってくるようにする。当然ながらふるいにかける前とかけた後の中身(値)は異なる。ということで、関数の型宣言は以下のように。
sieve (Sieve xs s) =
今定義しているのは、ふるいを連続的にかけていく sieve 関数。しかし、注目するのは上二つのふるいのみでよい。なぜなら、 sieve 関数が一回に適用できるふるいは一つであり、適用された引数によって「ふるいにかける様子」を表現しなくてはならないため。
sieve $ Sieve (sieveByHead xs) s
sieve (Sieve [] _) = Empty
headSieve (Sieve (x:_) s) = x : (headSieve s)
sieveByHead 関数は、n = 1, –1 で無限ループになってしまったので、パターンマッチを増やした。
投稿者 KURITA Jute 時刻: 10:20 0コメント
A Gentle Introduction to Haskell: Classes によると、
fmap 関数は以前につかった map 関数を一般化したものです。
map と言えば、リストの各要素に対して関数を適用するための関数。例えば、リストの要素を 2 倍したいときは、
print $ map (* 2) $ [1,2,3,4,5] -- [2,4,6,8,10]
map がリストのためにあるのに対し、fmap は自分で作成した代数的データ型に対して、map のように各要素に関数を適用するためにあるようだ。今回、以前に定義したシンプルな Iremono 型 を少し変更し、これに適用できるようにしてみる。
Iremono a 型の定義を以下のように変更。
data Iremono a = Iremono [a] deriving (Show,Eq)
前回は Iremono 型のフィールドが 型変数 a だったけれど、今回はリスト [a] にした。
まずは、fmap を使わずに「入れ物」(Iremono a) の中の中身の要素を 2 倍にする関数を定義してみた。
と、その前に念のため確認。例えば次のように Iremono a 型に map 関数を適用してみても、
print $ map (*2) $ Iremono [1,2,3,4,5]
当然ながら怒られる。 (+_+)
Couldn't match expected type `[a]' against inferred type `Iremono t' In the second argument of `($)', namely `Iremono [1, 2, 3, 4, ....]' In the second argument of `($)', namely `map ((*2)) $ Iremono [1, 2, 3, 4, ....]' In the expression: print $ map ((*2)) $ Iremono [1, 2, 3, 4, ....]
入れ物の中の要素を 2倍にする
Iremono の要素を 2 倍にする doubleIremono 関数を定義。
doubleIremono :: Num a => Iremono a -> Iremono a doubleIremono (Iremono xs) = Iremono (map (*2) xs)
doubleIremono 関数を使ってみる。
print $ doubleIremono $ Iremono [1,2,3,4,5] -- Iremono [2,4,6,8,10]
入れ物の中身の要素に関数を適用
doubleIremono 関数は「要素を 2 倍する」しかできないので、もう少し汎用的にしたい。そこで、関数を渡したら「入れ物」の中身に関数を適用する mapIremono 関数を定義。
mapIremono :: (a -> b) -> Iremono a -> Iremono b mapIremono f (Iremono xs) = Iremono (map f xs)
これを使ってみると、例えば、
print $ mapIremono (* 2) $ Iremono [1,2,3,4,5] print $ mapIremono (\x -> if x < 3 then "hoge" else "piyo") $ Iremono [1,2,3,4,5]
Iremono [2,4,6,8,10] Iremono ["hoge","hoge","piyo","piyo","piyo"]
A Gentle Introduction to Haskell の例を見る
最初に、Functor クラスの fmap 宣言を確認しておく。
fmap は、Functor クラスのメソッド。
class Functor f where fmap :: (a -> b) -> f a -> f b
A Gentle Introduction to Haskell: Classes では Tree a 型を Functor のインスタンスにする例が書かれている。Tree a 型は、
data Tree a    = Leaf a | Branch (Tree a) (Tree a)
(A Gentle Introduction to Haskell: Modules より)
これを以下のように Functor クラスのインスタンスにしている。
instance Functor Tree where
fmap f (Leaf x)       = Leaf   (f x)
fmap f (Branch t1 t2) = Branch (fmap f t1) (fmap f t2)
実装を見ると、各 Tree の要素に fmap 関数の第一引数である `f’ を適用しているのがわかる。
ここでいつも頭が混乱するのでゆっくり考える。(+_+)  上記のように型コンストラクタ Tree は Functor クラスのインスタンスであると宣言した。 Functor Tree の fmap の実装で返しているは Tree a 型。Functor クラスの定義の `f’ を Tree で置き換えることができるとすると、 次のよう想像することができる。
class Functor Tree where fmap :: (a -> b) -> Tree a -> Tree b
この fmap の型が Tree  a 型における実際の fmap の宣言ということ。だから、Tree  a 型の fmap が返している型が Tree b 型で OK と。
あ~ (@_@;) なかなか慣れない…。
Iremono a 型にも fmap
上記を真似して、fmap が適用されたとき、「入れ物」の中身である各要素に関数が適用されるように実装してみる。
instance Functor Iremono where fmap f (Iremono xs) = Iremono (map f xs)
Tree のときと同じように Functor クラスの定義の f を Iremono で置き換えて考えてみると、
class Functor Iremono where fmap :: (a -> b) -> Iremono a -> Iremono b
上記で定義した fmap 関数の定義は、この宣言に沿うように定義されていることがわかる。
さて、実際に fmap を使ってみると、
print $ fmap (*2) $ Iremono [1,2,3,4,5] -- Iremono [2,4,6,8,10]
ところで、class Functor f where によると、
The Functor class is used for types that can be mapped over. Instances of Functor should satisfy the following laws:
fmap id == id fmap (f . g) == fmap f . fmap g
上記を満たすように実装する必要があるらしい。第3回 mapからモナドを理解する:ITpro によると、
idは恒等関数(identity functionもしくはidentity)の略であり,入力したデータをそのまま返す関数です。(.)演算子は関数合成(functional composition)です。(.)の定義は,(f . g) x = f (g x)です。
確かに、型クラスによる宣言だけでは、関数がどのように振舞えばいいのかを規定することはできない。定義の内容はプログラマの手にゆだねられている。
「自分で定義した代数的データ型のフィールドの各要素に関数を適用していく」ということが、上記を保証することでなぜ実現できるのかという一番肝心なところがわからないのだけれど ^^; 、とりあえず一例だけでも試してみることに。  QQQ
main = do print $ test1 # True print $ test2 # True test1 = (fmap id $ Iremono [1,2,3,4,5]) == (id $ Iremono [1,2,3,4,5]) where id = (\x -> x) test2 = (fmap (f . g) $ Iremono [1,2,3,4,5]) == (fmap f . fmap g $ Iremono [1,2,3,4,5]) where f = (* 2) g = (+ 100)
投稿者 KURITA Jute 時刻: 14:53 0コメント
ラベル: Haskell
2008年10月26日日曜日
Haskell で文字列の分割と結合
lines :: String -> [String]
words :: String -> [String]
特定の文字列で区切るなら正規表現を使って、( Text.Regex )
splitRegex :: Regex -> String -> [String]
import Text.Regex main = do print $ lines "hoge\npiyo\nfuga" print $ words "hoge piyo fuga" print $ splitRegex (mkRegex ",") "hoge,piyo,fuga" print $ splitRegex (mkRegex "--") "hoge--piyo--fuga"
lines, words の接頭辞として `un’ をつける。
文字列でくっつけたい場合は、intercalate 。(cf. Haskell でリストの要素を join - List.Data の intersperse, intercalate)
import Data.List css = ["hoge","piyo","fuga"] main = do putStrLn $ unlines css putStrLn $ unwords css putStrLn $ intercalate "—" css
hoge piyo fuga hoge piyo fuga hoge--piyo--fuga
単に文字列のリストをくっつけて、文字列にしたいだけなら concat 。文字列のリストは、文字のリストのリストであるため。
日本語を扱うときは、「Haskell で日本語表示 - utf8-string を利用して」 を参照。
Haskell で Text.Regex の splitRegex 関数を利用しようとするとリンクエラー
投稿者 KURITA Jute 時刻: 23:29 0コメント
ラベル: Haskell , 正規表現 , 文字列
Meadow (Emacs) で矩形領域をカット & ペースト
C-x r k → C-x r y
微妙に使わないものは何度でも忘れてしまう。 (+_+) どうやって忘れないようにしようか。
このカット&ペーストのパターンはさすがに忘れないのでこれを基本形と考え、
は、コマンド実行 command e`x’ecute 。そして矩形の`r’ectangle 。
… いつまで覚えていることができるかな。
最近やっと M-x goto-line と入力しなくても、M-g g で特定の行へジャンプする入力を手が覚えてくれた。 ^^; これは Go! Go! と覚えた。
Meadow/Emacs memo: コピー,切り取り,貼り付け関連
投稿者 KURITA Jute 時刻: 22:29 0コメント
ラベル: Emacs , Meadow
素朴にエラトステネスのふるい (2) - オブジェクト指向を手がかりに再帰表現を考える
「素朴にエラトステネスのふるい (1)」の続き。
コードを再掲。Haskell では、
sieve (p:ps) = p : sieve [n|n <- ps, n ‘mod‘ p /= 0]
def sieve(L): if not L: return [] else: return [L[0]] + sieve([x for x in L[1:] if x % L[0] != 0])
やはり、今日見ても再帰的な表現はどこか理解しきれないと感じる。(+_+) これ以上考えてもらちが開かないので、このままの形で考えるのは諦めた。
ところで、上記のコードは直接素数を生成するわけではない。`ふるい’ はあくまでも素数を生成するためのツール。「2 からはじまる自然数のリスト」を与えたときに素数のリストが生成される。
main = do print $ take 10 $ sieve [2..]
print sieve(range(2,100))
もし、「1 からはじまる自然数のリスト」を引数に与えたなら、その `ふるい’ の性質上、生成されるのは [1] 。なぜなら、最初の「リストの先頭要素で割り切れる要素をふるいにかける」というところで、1 以降の要素が脱落してしまうため。つまり、上記のコードは `ふるい’ の動作を表現しているということを忘れてはダメ。素数が生成されるのはその結果に過ぎない。
よくわからないときは絵を描くことにしているので、素数を生成するときの `ふるい’ をイメージしてみた …
「このふるいは、近所の量販店で売られているふるいとは違う。小麦粉を `ふるう’ のではなく、「数値のリスト」をふるう。動作も一風変わっていて、数値のリストをザザーっと流し込むと、最初にふるいに落ちた数値がふるいにセットされ、その数値で『割り切れない数値』がふるいを通り抜け、割り切れた数値がふるいに残される。
ある数値のリストをこのふるいにかけたとする。直後、ふるわれた数値が地面に落ちる寸前、同じ種類のふるいを別にもう一つ用意し、落ちていく数値を受けとめる。同種のふるいなので動作も同じ。また落ちてきた先頭の要素がふるいにセットされ、残りの要素に対してふるいをかける基準となる。
手元にふるいが更に何個もあったので、これをどんどん繰り返していたら、最後には落ちていく数値がなくなってしまった。」
この様子を示したの右図。で、このふるいを一つのオブジェクトと見たて、ふるいクラスを作成する。まずはこのふるいに対して何ができるかという視点で。
数値のリストをセットする
ここからふるいの内部はどうなっているかと想像すると、
セットされた数値のリストを持つ
セットされたリストの先頭要素を持つ
それから、右図のようにふるいをつなげて使っている様子をふるい自身に覚えてもらうことにすると、
自分がふるい落とした数値を受けとめるふるいを知っている
そして、各自ふるった後、落ちた数値を受け止めるためのふるいを自分で用意してもらうことに。
class Sieve: """ ふるい このクラスのオブジェクトが連なって働くことによって 「エラトステネスのふるい」の振る舞いをする - 使い方 1. インスタンスの生成 2. 値の設定 3. ふるいにかける """ def __init__(self): self.L = [] # ふるいにかける前の数値のリスト self.head = None # ふるいにかける数値のリストの先頭 (ふるいの基準) self.tail = None # Sieve : ふるいにかけた後の数値のリストを保持 def set(self,L): """ ふるいにかける数値のリストを設定 """ self.L = L self.head = L[0] return self def sieve(self): """ ふるいにかける """ self._sieveByHead() if self.tail: self.tail.sieve() def _sieveByHead(self): """ 設定されたリストの要素をその先頭要素で割り、 割り切れなかったものをふるいから落とし、新たにふるいに設定する ※ 設定されたリストの要素が二つ以上ないと tail は None のまま。 """ if len(self.L) > 1: self.tail = Sieve() sieved = [x for x in self.L if x % self.head != 0] if sieved: self.tail.set(sieved) def __str__(self): """ ふるいの基準として使われた数値を出力 """ if not self.head: return "" return str(self.head) + ", " + str(self.tail) if self.tail \ else str(self.head) s = Sieve().set(range(2,100)) s.sieve() print s
最初に示したコードと比べるとかなり長くなってしまったが、こちらはイメージしやすい。 ^^ なぜかと言えば、クラス定義で意識するのはオブジェクト単位であり、オブジェクト一つで何ができるかを考えればいいため。sieve メソッドを見ると「自らふるい落とした数値のリストを受けとる`ふるい’」に対して sieve メソッドを呼出している。しかし、メソッドを見ても頭が混乱することはない。単純に `ふるい’ が `ふるい’ に対して 「sieve してくれ」と依頼しているようにしか見えないから。
結局、再帰的な関数において呼出す度に生成される文脈を、オブジェクトというイメージしやすい形に置き換えることにより理解しやすくなった気がする。オブジェクト指向で考えるときの一番基本的な戦略は、「オブジェクトと関わりのあるオブジェクトに対して、どのようにコラボレーションするか?」を問うこと。この方針が `考える範囲を限る’ ということに対して、`オブジェクト‘ という範囲の枠を提供してくれる。
再帰的な関数との違いがもう一つ。それは、やることを分割しているということ。上記のクラスでの実装は、「ふるいにかける動作、ふるう動作、ふるいを連ねる動作、その結果を表示するための動作」を別々にした。そして、それらの動作を `一つのふるい’ というイメージと関連付けて考えた。再帰的な関数では、これを一行で表現する。そうすると、自分の脳みそでは、「一体誰が何をしてその結果どうなったの?」というところで、えっ?(@_@;)? となってしまう。
オブジェクト指向をアナロジーとして用いる
逆に言えば、再帰的な関数を、アナロジーとして上記のような表現とほぼ等価であると見なすことができれば、すんなりと理解できるはず…。明らかな動作の違いは、クラスによる実装では計算が終った時点で計算過程の一部の履歴が残っているのに対して、再帰関数では消えているという点くらいだし。… ということは、えーと、再帰関数である sieve を見たら、次のように見たてればいいということか。
「sieve というメソッドを持つオブジェクト」があると想定。(ふるいに相当)
sieve を再帰的に呼出すところは、新しく同種のオブジェクトを生成すると見なす。
ただし、そのオブジェクトは最終的に計算の過程を保持することなく、計算の終了とともに消滅して結果 (関数の返り値) のみを残す。
最後に、残された結果を連結。
つまり、関数で呼出された文脈をオブジェクトと見なし、そこで使われているローカル変数をインスタンス変数に見たてるということ。以前より少し理解が進んだような気になれた。 ^^
素朴にエラトステネスのふるい (3) – Python の実装を Haskell へ
投稿者 KURITA Jute 時刻: 16:23 0コメント
ラベル: Haskell , Python , 再帰
2008年10月25日土曜日
Haskell で簡単なテキスト処理 (2)
「Haskell で簡単なテキスト処理 - データの抽出」の続き。もう一度、前回と同じ処理を書いてみる。
対象のデータは、「Python で簡単なテキスト処理 (2) - データの抽出」で使った以下の 気象データ 。ここから、気圧 (1列目) と気温 (6列目) のデータのみを抽出したい。
998.7 1003.1 -- -- -- 6.0 10.9 1.8 36 16 2.6 4.8 北西 9.4 北西 6.9 -- -- 晴後一時曇 快晴
1007.2 1011.7 -- -- -- 6.2 11.2 1.1 35 19 3.1 6.6 北西 13.3 北西 9.1 -- -- 快晴 快晴
1011.6 1016.1 -- -- -- 5.9 10.4 1.5 45 29 1.8 3.6 北北西 6.4 南南東 9.1 -- -- 晴 快晴
1014.6 1019.1 -- -- -- 7.0 12.1 2.7 43 24 2.5 5.0 北西 9.4 北北西 9.0 -- -- 快晴 晴後曇
1014.0 1018.6 0.0 0.0 0.0 6.0 8.7 4.0 53 39 2.0 3.8 北西 6.1 西北西 3.7 --
※データファイルは UTF-8 で保存。
まずは、なるべくシンプルに書くにはどうしたらいいかという視点で考えると、
import qualified System.IO.UTF8 as U import Text.Regex.Posix main = U.getContents >>= U.putStr . unlines . extract . lines extract = map col . filter (\x -> not $ x =~ "^[[:digit:]]{1,2}$|^$") col line = let ds = words line in ds !! 0 ++ "\t" ++ ds !! 5
さすがに Ruby のようなシンプル書き方はできないかなぁ…。
追記(2008.11.7) : filter の第1引数を関数合成に変更するなら、
extract = map col . filter (not . (=~ "^[[:digit:]]{1,2}$|^$"))
前回と違うところは、main において do 式を使わずに (>>=) で置き換えたこと。 (>>=) は「左の箱の中身を、右の箱の中に流し込むための装置」と理解している。(これが正しいのかよくわからないのだけれど…。)  do 式では渡された中身を変数に束縛していたが、(>>=) を使うと省略できる。
※ モナドについてはまだよくわからない。(+_+) ただし、Meet the Monads の以下の部分を読んで、イメージとして何か「入れ物」と「中身」の扱いについてのメタ的な記述だというくらいの認識にはなった。 ^^;
多相型は多くの異る型の値を保持できるコンテナのようなものです。… Haskell ではこのコンテナの型も多相にすることができます。それゆえ、「m a」と書いて、ある型の値を保持するある型のコンテナを表現することができます。
Meet the Monads によると (>>=) の型は、
(>>=) :: m a -> (a -> m b) -> m b
関数の合成は、(cf. Haskell の関数合成)
(.) :: (b –> c) –> (a –> b) –> (a –>c)
getContens の型は、Prelude によると、
getContents :: IO String
これは、`IO’ という入れ物に String を入れて運び、 (>>=) で右側に中身だけ「よっこらせ」と降ろすということ。(多分)
lines は String が引数で、`IO’ の中身はここに投入される。
lines :: String -> [String]
そして、必要な処理がされると、putStr によってまた`IO’ に入れられて出力。これが main 関数の返り値になる。
putStr :: String -> IO ()
ところで、(.) により putStr から lines までが、Stirng –> IO() という型の一つの関数に合成される。
IO モナド によると、
Haskell では、トップレベルの main 関数の型は IO () でなければなりません。
(>>=) の関数の型を今回の場合に当てはめると、
IO String –> (String –> IO ()) –> IO ()
これで String が投入されると IO () が返され、main 関数の型に沿うようになる。
モナドついてわからないけれど、外見は上記のような理解でいいのだろうか… ^^;
Haskell で正規表現 (2) =~ , Python・Ruby と比較しながら を参照。
数字を表わすには `\d’ ではなく、Rx - Posix Basic Regular Expressions によると、
[[:digit:]]
正規表現に一致しないものを抽出したい場合、not 関数 で Bool 値を反転させる。
not :: Bool -> Bool
map と filter を合成している関数をリスト内包表記に置き換えると、
extract css = [col cs| cs <- [cs| cs <- css, not $ cs =~ "^[[:digit:]]{1,2}$|^$"]]
しかし、あまり見やすくならないので map, filter の合成を使うことに。
map f . filter match
一つのパターンとして覚えておくといいかも。
main 関数において、行を抽出した後に、列を抽出するという意図を明確にしたいなら、
import qualified System.IO.UTF8 as U import Text.Regex.Posix main = U.getContents >>= U.putStr . col . row row = filter (\x -> not $ x =~ "^[[:digit:]]{1,2}$|^$") . lines col = unlines . map col' where col' line = let ds = words line in ds !! 0 ++ "\t" ++ ds !! 5
line – unlines の組み合わせを別々の関数の入口と出口に配置し、filter ・ map をそれぞれ行・列の抽出処理に対応させるようにしてみた。例1.と比べて、どちらが理解しやすく書きやすいだろう?
filter に適用する無名関数が長いと感じたら、filter match として、match 関数を作成。
match cs = not $ cs =~ "^[[:digit:]]{1,2}$|^$"
なるべくシンプルにしたいと思って、列の抽出をまとめていったら、逆に長くなってしまった。(+_+) 抽出する列数が少なければあまり意味がなさそう。
import qualified System.IO.UTF8 as U import Text.Regex.Posix import Data.List main = U.getContents >>= U.putStr . unlines . row . lines row = map col . filter match match cs = not $ cs =~ "^[[:digit:]]{1,2}$|^$" col cs = intercalate "\t" $ col' [0,5] cs col' [] _ = [""] col' (x:xs) cs = (col'' x) : (col' xs cs) where col'' i = (words cs) !! i
(cf. Haskell でリストの要素を join - List.Data の intersperse, intercalate)
データを「表」とみなし、表は「列のリスト」からなり、列は「文字列のリスト」からなると考えると、
import qualified System.IO.UTF8 as U import Data.List data Table = Table [Row] instance Show Table where show (Table xs) = concatMap show xs data Row = Row [String] instance Show Row where show (Row xs) = intercalate "\t" xs ++ "\n" main = U.getContents >>= U.print . filterCol . filterRow . readTable filterRow :: Table -> Table filterRow (Table rows) = Table $ filter match rows where match :: Row -> Bool match (Row cells) = if length cells > 1 then True else False filterCol :: Table -> Table filterCol (Table rows) = Table $ map (col [0,5]) rows where col :: [Int] -> Row -> Row col is (Row cells) = Row $ map (cells !!) is readTable :: String -> Table readTable css = Table $ map readRow $ lines css readRow :: String -> Row readRow cs = Row $ words cs
データを readTable , readRow 関数によって Table 型の値に一度変換し、filterRow, filterCol によって必要な部分を抽出するようにした。そのため、ここでは正規表現を利用していない。
各関数はシンプルになったけれど、これはちょっと長すぎる気が。うーん… (+_+)
それにしても、こういう文字列から値の変換は、8.3 Read クラスと Show クラス のように Read を使うのかな?
実際に関数を定義してみて実感したことがあった。それは、パターンマッチの書き方、つまり、フィールドの値を変数に束縛する仕方が、定義でどのように値を使いたいかを暗示しているということ。例えば、上記の filterRow 関数において (Row cells) としているところを (Row (x:xs)) と束縛していたなら、パターンマッチを見ただけで定義において再帰的に処理がされているのでは (?) と予想できる。普通のリスト処理のときはそんなの当り前と思っていたけれど、フィールドにリストがある型に対してはそういう見方になってなかった。 ^^; 多分、読むだけでアップアップしてた。
Haskell で簡単なテキスト処理 (3) – break 関数を使って再帰処理
投稿者 KURITA Jute 時刻: 21:35 0コメント
ラベル: Haskell
2008年10月24日金曜日
Haskell で正規表現 (2) =~ , Python・Ruby と比較しながら
以前試したように Haskell において正規表現を使いたい場合は、Text.Regex モジュールを利用する。(cf. Haskell で正規表現)
「正規表現型の値」を生成 : mkRegex
(1) を利用して一致する部分があるか確かめる : matchRegex
import Text.Regex main = do print $ matchRegex (mkRegex "(piyo)") "123hogepiyofuga" print $ matchRegexAll (mkRegex "(piyo)") "123hogepiyofuga"
Just ["piyo"] Just ("123hoge","piyo","fuga",["piyo"])
ただし、matchRegex において Just で包んで返される値は、 mkRegex の正規表現で subexpression として指定 したもの。
Python でも同様の手順を踏む。
match または search (cf. 4.2.2 マッチング vs 検索)
import re print re.compile("piyo").match("123hogepiyofuga") print re.compile("piyo").search("123hogepiyofuga")
search と match の違い
4.2.3 モジュール コンテンツ によると、
search(pattern, string[, flags])
string全体を走査して、…
match(pattern, string[, flags])
もし string の先頭で0 個以上の文字が正規表現 pattern と マッチすれば、…
Haskell の matchRegex は search に相当するということかな。
上記は正規表現を使い回さないのであれば、compile せずに、
print re.match("piyo", "123hogepiyofuga") print re.search("piyo","123hogepiyofuga")
matchRegexAll のように
Haskell の matchRegexAll と同じものを取得するには、4.2.5 MatchObject オブジェクト を使い、
str = "123hogepiyofuga" m = re.search("(piyo)",str) print str[:m.start()], m.group(1), str[m.end():], m.groups()
123hoge piyo fuga ('piyo',)
Ruby で正規表現と言えばすぐに /正規表現/=~ “文字列” を思い出す。(cf. Regexp - Rubyリファレンスマニュアル) そういう書き方ができるから、テキスト処理をするとき Ruby は扱いやすいなぁ~と思った。組み込み変数 は忘れてしまうけれど。 ^^;
p /(piyo)/ =~ "123hogepiyofuga" p $`, $1, $', $~.to_a
7 "123hoge" "piyo" "fuga" ["piyo", "piyo"]
せっかくなので、上記の組み込み変数だけでも覚えておこう。
Python でも =~ が使えるといいのに…。 (+_+)
Haskell でも =~
Text.Regex.Posix.Wrap
前回、A Haskell regular expression tutorial を読むのを見逃してた。(via Cookbook - HaskellWiki) Haskell でも Ruby と同じように =~ が使えるようだ。
定義されている場所は、Text.Regex の一つ下の階層に Text.Regex.Posix があり、そのまた下の Text.Regex.Posix.Wrap。どういうモジュールかと思って見てみると、
WrapPosix.hsc exports a wrapped version of the ffi imports.
FFIとは - はてなキーワード
ある言語から他言語で作成したライブラリを呼び出すインターフェイスで、ラッパーを作らずに直接呼び出す事が特徴である。
…と言われても、何に対してどうなのか具体的によくわからなかった。 ^^;
それはさておき、 =~ を見ると、
(=~) :: (RegexMaker Regex CompOption ExecOption source, RegexContext Regex source1 target) => source1 -> source -> target
うわっ!(@_@;) この型クラスの制約はどうやって読めばいいのだろうか? QQQ
A Haskell regular expression tutorial によると、とりあえずはシンプルに考えておけと。
this function is polymorphic in both its arguments and its return type; … Here’s a simplified type signature, to give you the idea.
(=~) :: string -> pattern -> result
(I’ve left out the constraints on these type variables. …
なるほど。しかし、引数だけではなく、返り値の型まで多相とは…?
とりあえず、上記にならって使い方を試してみる。
import Text.Regex import Text.Regex.Posix main = do print $ ("123hogepiyofuga" =~ "(piyo)" :: Bool) # True
最後の :: Bool と型を指定するのがポイント。
最初にマッチした文字列を返すには、
print $ ("123hogepiyofuga" =~ "(piyo)" :: String) # "piyo"
マッチした全ての文字列をリストにして返すには、
print $ ("123hogepiyofuga" =~ "(piyo)" :: [String]) # ["piyo"]
マッチした部分よりも前、マッチした文字列、マッチした文字列の後ろを返したい場合は、
print $ ("123hogepiyofuga" =~ "(piyo)" :: (String,String,String)) # ("123hoge","piyo","fuga")
上記に加えて、先ほどのように部分式にマッチした文字列をリストにしたものも加えたい場合は、
print $ ("123hogepiyofuga" =~ "(piyo)" :: (String,String,String,[String])) # ("123hoge","piyo","fuga",["piyo"])
マッチした文字列の位置とその長さを得たい場合は、Text.Regex.Base をインポートしておいた上で、
print $ ("123hogepiyofuga" =~ "(piyo)" :: (MatchOffset,MatchLength)) # (7,4)
投稿者 KURITA Jute 時刻: 18:07 0コメント
ラベル: Haskell , Python , Ruby , 正規表現
2008年10月23日木曜日
素朴にエラトステネスのふるい (1)
Haskell プログラミング ~ 純粋関数型言語への誘い~ を読んでいたら、「エラトステネスのふるい」 (p15) というのがあった。
sieve (p:ps) = p : sieve [n|n <- ps, n ‘mod‘ p /= 0]
Python で真似するなら、
def sieve(L): if not L: return [] else: return [L[0]] + sieve([x for x in L[1:] if x % L[0] != 0])
(ただし、L は有限のリスト)
エラトステネスの篩 – Wikipedia によると、
素数判定法の一種で、指定された整数以下の全ての素数を発見するための単純なアルゴリズムである。
え~ (@_@;) 、こんなシンプルな表現で素数が得られるとは…。てゆうか「素数」なんて言葉何年ぶりに聞いただろうか。 ^^;
1とその数自身以外に正の約数がない(つまり1とその数以外のどんな自然数によっても割り切れない)、1 より大きな自然数のこと。
(素数 – Wikipedia より)
上記 sieve 関数は、定義の中で更に sieve 関数を適用している。苦手な再帰的な表現だ。うーむ。。。 (@_@;)
素数のリストが欲しいときは、2 以上の自然数のリストに関数を適用。これにより素数の無限リストが得られる。
primes = sieve [2..] (同上より)
Python であれば、range(2,100) などのような有限のリストを sieve 関数に渡す。
どのように動作するか具体的な例で考えてみる。例えば、「2 ~ 11 の自然数のリスト」に sieve 関数を適用した場合は、
sieve [2..11] = 2 : sieve [n|n <- [3..11], n `mod` 2 /= 0]
あ~  (+_+) 、再帰はいきなり見ると目が回るので部分ごとに。
まずは、リスト内包表記から。
[n|n <- [3..11], n `mod` 2 /= 0]
sieve 関数に適用したのは [2..11] のリスト。だから、ここでは「seive に適用したリストの先頭以外の要素」の中で「seive に適用したリストの先頭である 2」 で割り切れない要素をリストにしている。これが `ふるい’ にかける様子の一部を表現。
その後 `ふるい’ にかけたリストに対して更に sieve 関数を適用。ここが再帰的に関数を適用しているところで、目が回る原因。(@_@;)
sieve [n|n <- [3..11], n `mod` 2 /= 0]
「ふるいにかける方法は、ふるいにかけたものを、更にふるいにかけること」
… と日本語にしたところで、再帰のイメージがしやすくなるわけではないか。 ^^;
再帰の混乱の元は、再帰的に連なる呼出しをイメージしようとすることにある気がする。 (+_+) あくまでも考えるのは、連なる呼出し全体ではなく、そのスナップショット的な表現。例えば、上記のように sieve [2..11] と適用された場合、その適用された文脈でのみ動作を考える。再帰のそのまた先まで考えない。
具体的に、sieve[2..11] を定義するのであれば、定義は適用された引数 [2..11] に対してどのような作用をするのか考えるということ。あくまでも、一つ先の再帰を手持のコマで表現する。もう一度、以下を見ると、
sieve [n|n <- [3..11], n `mod` 2 /= 0]
再帰的に適用している対象  (リスト内包表記の中の変数) は、その文脈での「関数の適用対象」を使って表現している。
定義の内容を続けて読んでいくと、次に、上記の再帰的な関数の適用によって生成されるリストと、先頭要素である `2’ をくっつけてリストを作成。ここでも同じく、 sieve の再帰的な適用の先の先は読まない。関数は「自分が欲しいものが既に得られた」と仮定し、「それを使ってどうしたいのか」という視点で考えると考えやすい。
2 : sieve [n|n <- [3..11], n `mod` 2 /= 0]
上記を言葉で表現するなら、
「ふるいにかける方法は、『ふるいにかけるリストの先頭』と『その先頭の要素では割り切れない要素に対して更にふるいをかけた結果』をつなげてリストにする。」
ポイントは、ふるいにかけられることによって「何」が残るのかということ。ここが自分はイメージしにくい。 (+_+) 関数が何を返し、それに対してどうしたいのか。再帰的な定義だと急に動作を想像しにくくなる気がする。
これを考えるには、関数の定義で再帰的に考えなくても明らかな部分に注目。上記の例ではリストの先頭要素である `2’ が手がかりとなる。
ところで、seive 関数の全体を眺めると、次のように再帰的に関数を適用している。
sieve リスト = リストの先頭要素 : sieve リストの先頭要素以外に対するリスト内包表記
こうやってみると全体の形が「n からはじまる数の無限リストを得る」再帰と類似しているのがわかる。
ints :: Int -> [Int] ints n = n : ints (n+1)
ints 関数の実際の動作を考えると、例えば ints 1 なら、
1 : ints(2) 1 : 2 : ints(3) 1 : 2 : 3 : ints(4) 1 : 2 : 3 : 4 : ints(5)
再帰的に ints が適用されるごとに先頭要素がひねりだされ、前の要素にくっついていくという感じがする。適用されるごとに ints がリストを生長させているようにも見える。
sieve 関数も同様に見たてることができる。 sieve により適用されたリストの先頭がひねりだされ、リストが生長していく。再帰的に sieve 関数に適用されるリストによって、最終的に生成されるリストの内容が決定される。つまり、sieve に適用するリスト内包表記による操作がリストの要素を構成する決め手。このとき、最初にひねりだされるのが、リストの先頭要素である自明な `2’ 。
しかし、やはり実際に関数が定義と置き換えられていく様子を追ってみないと納得できない。 ^^;
2 : sieve [n|n <- [3..11], n `mod` 2 /= 0] 2 : sieve [3,5,7,9,11] 2 : 3 : sieve [n|n <- [5,7,9,11], n `mod` 3 /= 0] 2 : 3 : sieve [5,7,11] 2 : 3 : 5 : sieve [n|n <- [7,11], n `mod` 5 /= 0] 2 : 3 : 5 : sieve [7,11] 2 : 3 : 5 : 7 : sieve [n|n <- [11], n `mod` 7 /= 0] 2 : 3 : 5 : 7 : sieve [11] 2 : 3 : 5 : 7 : 11 : sieve [n|n <- [], n `mod` 11 /= 0] 2 : 3 : 5 : 7 : 11 : sieve [] -- ここで例外が発生
先ほど ints 関数を見たので、sieve 関数がリストの要素をゾロゾロと生み出しているように見える。 ^^;
ところで、上記では有限のリストに適用したので、例外が発生してしまった。
Prelude> sieve ([2..11]) [2,3,5,7,11*** Exception: :1:4-54: Non-exhaustive patterns in funct ion sieve
例外が発生しないようにするには take 関数を使うか、
Prelude> take 5 $ sieve [2..] [2,3,5,7,11]
空のリストに適用したときに空のリストを返すようにしておく。
sieve [] = []
さて、最初に Python におけるエラトステネスのふるいの実装例を挙げた。そこでは再帰的な定義をしたが、アルゴリズムとしては素朴な内容となっている。「素朴」である理由は、エラトステネスの篩 – Wikipedia のアルゴリズムの説明の中で、「ステップ 4」の一部の判定を省略しているため。
探索リストの最大値が素数リストの最大値の平方よりも小さい場合、素数リストおよび探索リストに残っている数が素数となる。
この判定をする理由については、「エラトステネスの篩い」の説明、「エラトステネスの篩いの原理」の「2.どの数の倍数を取り除くか」がわかりやすい。しかし、ここではこの判定を省略し、「素朴」に倍数を消す作業をリストの終りまで続けることにした。
はじめは、ごく普通に ループを使って実装してみる。
def sieveByHead(L): """ 先頭の要素で割り切れない要素のリストを返す """ result = [] for e in L[1:]: if e % L[0] != 0 : result.append(e) return result def sieve(L): """ 渡されたリストの中の素数を返す """ result = [L[0]] while L: sieved = sieveByHead(L) if sieved: result.append(sieved[0]) L = sieved return result print sieve(range(2,100))
上記の sieveByHead 関数をリスト内包表記で置きかえるとコンパクトになる。
def sieve(L): """ 渡されたリストの中の素数を返す """ result = [L[0]] while L: sieved = [x for x in L if x % L[0] != 0] if sieved: result.append(sieved[0]) L = sieved return result
最初に挙げた再帰的な表現だと、有限のリストにしか適用することができない。 Haskell のように無限リストを扱うには、ジェネレータで書き直す必要がある。
def sieve(L): if not L: return [] else: return [L[0]] + sieve([x for x in L[1:] if x % L[0] != 0])
これをジェネレータに変更すると、
def sieve(L): head = L.next() yield head for e in sieve(x for x in L if x % head != 0): yield e
ジェネレータは next() の呼出しによって、対象となる要素が一つ先へ進む。ジェネレータを代入する変数 L をリストと見たてるなら、最初の next() の呼出しによって先頭の要素がなくなったとイメージするとわかりやすい。また、リスト内包表記を ジェネレータ式 で置き換えていることにも注意。
上記の関数を使うには、無限リストを生成する関数を定義して、その呼出し結果を sieve 関数に渡す。
def ints(n): """ n 以降の自然数の無限リスト """ while True: yield n n += 1 primes = sieve(ints(2)) for i in range(10): print primes.next()
または、有限のリストであるなら、iter 関数を適用してから呼出す。
print list(sieve(iter(range(2,100))))
ここまで来ても、再帰的な定義を見ると、やはりどこかイメージしきれないという感じがする。 ^^; 答えが得られた後もスッキリとしない。なぜだろう。 (+_+) 単に慣れていないのか、そもそも根本的にどこか理解の仕方が違うのだろうか? わかっている人にとってみれば、「何を当り前のことを…」と思うのだろうけれど、その「当り前の考え方」が自分には感覚的に納得しきれないのでこだわってしまう。また、ツールとして再帰を利用することができない。
パタッ(o_ _)o~†
もう一度別の角度からアプローチしていこう…。
投稿者 KURITA Jute 時刻: 22:44 0コメント
ラベル: Haskell , Python , ジェネレータ , 再帰
Python のジェネレータ (5) - 再帰とジェネレータと Composite
Python のジェネレータ (4) - 無限リスト のつづき
例えば、「リストの要素を 2 倍したい」とする。
リスト内包表記や map 関数を使うなら、以下のように書ける。
L = [1,2,3,4,5] print [x*2 for x in L] print map(lambda e: e*2, L)
単純に、for ループでリストを走査しながら、要素を2 倍するなら、
def double(L): result = [] for e in L: result.append(e*2) return result print double(L)
これをジェネレータで置き換える。
def gDouble(L): for e in L: yield e * 2 for e in gDouble(L): print e
def rDouble(L): if not L: return [] else: return [L[0]*2] + rDouble(L[1:]) print rDouble(L)
これをジェネレータで置き換えてみる。ジェネレータは要素をいっぺんに返さず、処理した要素ごとに返すようにする。
def grDouble(L): if not L: return else: yield L[0]*2 for g in grDouble(L[1:]): yield g for e in grDouble(L): print e
ジェネレータを再帰的に呼出すには、再帰的に適用したい部分を for に投入し (next() が呼出されるため)、その要素を yield で返す。渡された引数 L の要素がなければ、何もせず return でジェネレータを終了する。
次のように書き直すこともできる。
def grDouble(L): if L: yield L[0]*2 for g in grDouble(L[1:]): yield g
4. Composite
ジェネレータを再帰的に呼出すことに、何かメリットがあるのだろうか?
ツリー状のノードの要素を走査するためにジェネレータが使われている例 を目にした。これを見ると、Iterator パターン 、Visitor パターン を連想する。
試しに、Composite パターン のオブジェクトに対して、その要素を走査する関数をジェネレータで定義してみる。
Composite パターン - Wikipedia via kwout
class Component: pass class Composite(Component): def __init__(self): self.components = [] def add(self, component): self.components.append(component) return self def __iter__(self): return iter(self.components) class Leaf(Component): def __init__(self, val): self.val = val def gComposite(composite): if isinstance(composite, Leaf): yield composite.val else: for c in composite: for g in gComposite(c): yield g c = Composite().add( Leaf(100)).add( Leaf(200)).add( Composite().add( Leaf(1000)).add( Composite().add( Leaf(10000)).add( Leaf(2000))).add( Leaf(300))) for e in gComposite(c): print e
Composite クラスの __iter__() メソッドの定義については、Python のイテレータ (3) を参照。
投稿者 KURITA Jute 時刻: 16:15 0コメント
ラベル: Python , ジェネレータ , デザインパターン , 再帰
2008年10月19日日曜日
wxPython の準備 – Python で GUI
1. 標準添付の Tkinter は使わない
Python で GUI を作成したい。
wxPython でお手軽 gui によると、
Python には Tkinter, PyQt, PyGTK, wxPython などの gui toolkit があります。 いろいろと物色した結果次のことが分かりました。
これらの toolkit のマニュアル、チュートリアルは極めて不備である。
wxPython はデモスクリプトがあるだけまだましである。
wxPython はいろいろな widget が揃っている。
wxPython は最近人気があるようである。(その結果として web resources が他の toolkit より多い。)
Python に標準で Tkinter がついている。
16. Tkを用いたグラフィカルユーザインターフェイス の 16.1.2.2 簡単なHello Worldプログラム を実行すると、シンプルなウィンドウが表示される。
ただし、Tkinter  は、動作が遅く、長い間アップデートされていない。
Introduction to wxPython
The offcial python "toolkit" is TkInter. It is slow, looks terrible on all platforms, it has not been updated for ages. … It remains a mystery, why it was not excluded years ago.
よって、Tkinter 以外のものを使う。
2. wxPython と wxWidgets の関係
wxPython 1: はじめに によると、
wxPythonとは、Pythonで GUIアプリケーションを作るためのツールキットです。…
wxPythonは wxWidgetsという一般的なツールキットが元になっていて、…
wxWidgets – Wikipedia
The Team - wxWidgets via kwout
wxWidgetsとはクロスプラットホームなウィジェット・ツールキットであり、C++で記述されているが、多くのプログラミング言語向けにバインディングが用意されており、Python、Perl、JavaScriptなどから使うことが出来る。
wxWidgets のベースは C++ で、Python から使うことができる。
wxWidgets のダウンロードページ によると、
Not using C++? Get wxWidgets from the wxPython, wxPerl, and wx.NET download sites. Other ports...
3. wxPython のダウンロードとインストール
Untitled via kwout
wxPython のダウンロードページ に、Python のバージョンと対応した wxPython が用意されている。
現在、最新の Python のバージョンは 2.6。ただし、Google App Engine を使いたいので、Python 2.5 に対応したものを利用する。 Pure Python によると、
The Python runtime environment uses Python 2.5.
wxPython Download より、Python 2.5 の win32-unicode をダウンロードしてインストール。デフォルトでは
C:\Python25\Lib\site-packages
にインストールされた。
IDE にPyScripter を使っている場合、インストール後、一度 PyScripter を起動しなおす必要がある。
4. wxPython の入門サイト
The wxPython tutorial
wxPython Index
A First Application: "Hello, World"
Style Guide for wxPython code
特に、The wxPython tutorial の Introduction to wxPython における
「wxPython」の構造
wxPython API
は、全体を把握するのにわかりやすい。ドキュメントを読むための手がかりとなる。
5. wxPython のドキュメント
wxWidgets 2.8.9: A portable C++ and Python GUI toolkit」。
この中で頻繁に見ることになりそうなのは、
Classes by category
最初は、以下から読む。
wxFrame::wxFrame
投稿者 KURITA Jute 時刻: 17:00 0コメント
ラベル: GUI , Python
Python で部分適用 - functools モジュールの partial 関数
1. Python は一部の引数を与えて関数を呼び出すことができない
Haskell では、関数に複数の引数があるとき、先に一部の引数のみ渡しておき、後から残りの引数を渡すことができる。一部の引数を与えることを「部分適用」と言う。
Python では、普通そういうことはできない。例えば、3つの引数を足し合わせる関数 addThree 関数に対して、1つの引数だけ与える。
def addThree(a,b,c): return a + b + c print addThree(1)
上記を実行すると、引数が足りないとエラーが表示される。
exceptions.TypeError: addThree() takes exactly 3 arguments (1 given)
2. functools の partial 関数で部分適用
6.6 functools モジュールの partial 関数を使うと、部分適用を利用できる。
partial(func[,*args][, **keywords])
Return a new partial object which when called will behave like func called with the positional arguments args and keyword arguments keywords.
例えば、先ほど定義した addThree 関数に対して、partial 関数を使い、引数を1つだけ与える。
import functools addTwo = functools.partial(addThree,1) print addTwo(2,3)
partial 関数により、addThree 関数の最初の引数だけ渡した関数 addTwo を作成した。その後、addTwo 関数に対して、残りの二つの引数を与えている。
以下では、部分適用をした結果から、更に部分適用した addOneFromTwo 関数を作成し、元の addThree に二つ引数を渡した関数 addOne を定義した。
addOneFromTwo = functools.partial(addTwo,2) print addOneFromTwo(3) addOne = functools.partial(addThree,1,2) print addOne(3)
部分適用により、予め抽象的な関数を定義しておき、部分適用によって具体的な関数を導くことができる。上手く使えば、関数のモジュール化 を促進できる。
キーワード引数を利用して
キーワード引数を使うと、部分適用するときの引数を特定できる。
addTwo_ = functools.partial(addThree,c=3) print addTwo_(1,2) addOne_ = functools.partial(addTwo_,a=1) print addOne_(b=2) addOneFromTwo = functools.partial(addThree,a=1,c=3) print addOneFromTwo(b=2)
3. reduce 関数に対して部分適用し、具体的な関数を導く
リストの要素を足し合わせる sum 関数は、畳み込み関数 reduce より導くことができる。
なぜ関数プログラミングは重要か によると、
sum = reduce add 0
reduce 関数に対して、部分適用することによって sum を定義している。
Python の reduce 関数の使い方は、
print reduce(lambda a,b: a+b, [1,2,3,4,5])
reduce 関数に対して部分適用を利用し、シーケンスを後で与えるようにして、sum 関数を定義してみる。
L = [1,2,3,4,5] import operator from functools import partial # 合計 mysum = partial(reduce, operator.add) print mysum(L)
(functools.partial と書くのが面倒だったので、import の仕方を変更した。)
上記の書き方から、sum 関数が reduce というメタ的な関数の特殊パターンであるという雰囲気が伝わって来る。
cf. Python で合計
Python では、(+) のように、二項演算子を渡すことができないので、3.10 operator モジュールの add を利用した。
4. 関数を合成する関数を定義
Haskell の 関数を合成する(.) 関数を、partial を使い Python  で定義してみる。
cf. Haskell の関数合成
関数を合成する関数名を `c’ とした。
cf. function composition
c = lambda f,g: partial(lambda f,g,h: f(g(h)), f, g)
def … return で定義した方が読みやすいかな。
def c(f,g): return partial(lambda f,g,h: f(g(h)), f, g)
それとも、関数をネストして定義してみる。
def c(f,g): def _(f,g,h): return f(g(h)) return partial(_,f,g)
c 関数を使ってみる。
add3 = lambda x: x+3 mul3 = lambda x: x*3 print c(add3,mul3)(10) # 33 print c(mul3,add3)(10) # 39
Python でリスト内包表記を使ってクイックソート
Python の map, filter, reduce とリスト内包表記
Haskell の Prelude 散策 (1) - リスト操作 : 要素の重ね合わせ (folds)
Haskell の部分適用 (2)
投稿者 KURITA Jute 時刻: 12:10 0コメント
ラベル: Haskell , Python , 関数型
Firefox でウェブサイトの表の内容をコピーして表計算ソフトに貼り付ける
Firefox のアドオン「Table2Clipboard」をインストール。
例えば、気象庁 | 毎日の全国データ一覧表 日別値 のデータの一部を得たいとき、Ctrl キーを押しながらドラッグして範囲を選択。
Ctrl + Shift + C でコピー。
表計算ソフトにペースト。
OpenOffice 3.0, Google スプレッドシート では、表の内容をコピーするときに Ctrl + C でも上手くペーストすることができた。ただし、Excel 2003 では必ず Ctrl + Shift + C でないとダメ。
Python で簡単なテキスト処理 (2) - データの抽出
気象庁の、前日の、一時間ごとの「気圧データ」が含まれるページを表示するためのブックマークレット
投稿者 KURITA Jute 時刻: 1:03 0コメント
ラベル: Firefox 3 , Google Spreadsheets , アドオン
2008年10月18日土曜日
Python で二進数、十進数の変換
1. 二進数から十進数へ
Python で、数値を 2 進数から十進数に変換したい。
2.1 組み込み関数 によると、
int([x[, radix]])
文字列または数値を通常の整数に変換します。…
radix 引数は変換の基数を表し、範囲 [2, 36] の整数またはゼロをとることができます。
long([x[, radix]])
文字列または数値を長整数値に変換します。…
radix 引数は int() と同じように解釈され、x が文字列の時だけ与えることができます。
int() 関数を、このような目的で使えることを知らなかった。(@_@;)
例えば、2進数を表す文字列 1010 を、十進数に変更する。
>>> print int('1010',2) 10
2. 十進数から二進数へ
十進数から2進数へ変換するには format 関数を使う。
PEP 3101: Advanced String Formatting によると、
In Python 3.0, the % operator is supplemented by a more powerful string formatting method, format(). Support for the str.format() method has been backported to Python 2.6.…
There’s also a format() built-in that will format a single value. It calls the type’s __format__() method with the provided specifier:…
'b' - Binary. Outputs the number in base 2.
Python 2.6 であれば、次のように書ける。例えば、十進数の 10 を、2進数に変換する。
>>> print format (10,'b') 1010
Binary numbers には
Welcome to General Multiprecision PYthon
を使った方法が紹介されていた。
十進法 – Wikipedia によると、
十進記数法は単に十進法と呼ばれることもあるが、これを「10 進法」と書くのは好ましくない。10 が十を意味するのは十進記数法だからであり、例えば二進記数法ならば二を意味する。漢数字にはそのような曖昧さはない。英語でも同様に base 10 より decimal が好まれる。
6.6 functools -- Higher order functions and operations on callable objects.
Python で文字列が数値に変換できるか確かめる
Python で正確な小数の計算をする
投稿者 KURITA Jute 時刻: 12:48 0コメント
ラベル: Python , 数値
2008年10月17日金曜日
Python のデコレータ式 (3) - デコレートする側とデコレートされる側に引数がある場合
Python のデコレータ式 (2) のつづき
1. デコレートされる関数に引数がある場合を考える
これまで試したデコレータ式は、デコレートされる側の関数が引数を取らなかった。
Python のデコレータ式 (1) より、
def D(f): print u"デコレータが実行された" return f # デコレータを適用したときに、関数 D が適用される。 @D def hoge(): print "hoge" hoge()
前回は `デコレートする側に引数がある’ 場合について考えた。
Python のデコレータ式 (2) より、
def D(arg): def _(f): def __(): print "*--" * arg f() print "--*" * arg return __ return _ @D(5) def hoge(): print "hoge" hoge()
今回は、デコレートされる関数に引数がある場合を考える。
2. デコレータが受け取る関数の引数を固定しないために、可変引数を使う
デコレートする関数は、デコレートされる関数の引数について予め分からない。どのような型の値が渡されるか未知であり、関数が引数をいくつとるのか知らない。
もし、デコレータの受け取る関数の引数の数が固定されていたら、デコレータは使いにくい。これに対処するには、可変引数を使う。
デコレータについて考える前に、Python の可変引数 の書き方を復習しておく。
def test(*args): for e in args: print e test(1,2,3,"hoge","piyo") def test2(**keywords): for k,v in keywords.iteritems(): print k, v test2(a=100, b=200)
Python では、引数の前にアスタリスクを付けると、可変引数となる。
*args, **keywords
3. デコレートされる関数の引数が一つの場合
最初は、「デコレートされる側の関数の引数が一つ」の場合について考える。
def D(f): def _(arg): print "*--" * 10 f(arg) print "--*" * 10 return _ @D def hoge(n): print "hoge" * n ##hoge = D(hoge) hoge(3)
*--*--*--*--*--*--*--*--*--*-- hogehogehoge --*--*--*--*--*--*--*--*—*—*
コードが実行される様子を順に考える。上記コード中のコメントアウトしてある、デコレータ式を使わない場合で考えると分かりやすい。
デコレータ関数 D に、関数 hoge を渡すと、`_ 関数’ が返される。このとき引数 f に hoge がセットされる。
hoge(3) の呼出しは、`_(3)’ となり、ネストされた関数が実行される。
追記 (2009.12.22) : 上記の手順 1 で返される `_ 関数’ は、
引数を一つ受け取る関数
として定義されている。デコレートしたときに、何か特別な機能として arg に引数が渡される仕組みがあるわけではない。
4. デコレートされる関数の引数が複数の場合
次に、デコレートされる関数の引数が、複数の場合に対応できるように変更する。
def D(f): def _(*args): print "*--" * 10 f(*args) print "--*" * 10 return _ @D def hoge(n): print "hoge" * n @D def piyo(a,b): print "piyo" * a print "piyo" * b ##hoge = D(hoge) ##piyo = D(piyo) hoge(3) piyo(3,5)
*--*--*--*--*--*--*--*--*--*-- hogehogehoge --*--*--*--*--*--*--*--*--*--* *--*--*--*--*--*--*--*--*--*-- piyopiyopiyo piyopiyopiyopiyopiyo --*--*--*--*--*--*--*--*--*--*
デコレートする関数におけるネストした関数の引数を
とすることにより、引数の数が異なる hoge(n), piyo(a,b) 関数をデコレートできるようになった。
複数の引数を受け取る関数
として定義されている。
5. デコレートされる関数の引数にキーワード引数が含まれる場合
デコレートされる関数の引数に、キーワード引数 が含まれている場合は、次のように記述する。
def D(f): def _(*args, **keywords): print "*--" * 10 f(*args, **keywords) print "--*" * 10 return _ @D def hoge(n): print "hoge" * n @D def piyo(x,y): print "piyo" * x print "piyo" * y @D def fuga(a,b,c=8,d=10): print "fuga" * a print "fuga" * b print "fuga" * c print "fuga" * d hoge(5) piyo(5,10) fuga(1,2) fuga(1,2,3) fuga(1,2,c=10) fuga(1,2,c=10,d=5)
これまでと同じように、デコレートされたときに
複数の引数とキーワード引数を受け取る関数
が返されるように定義する。
6. デコレートする関数、デコレートされる関数に引数がある場合
前回は、デコレートする関数に引数がある場合について考えた。
デコレートする関数と、デコレートされる関数に引数がある場合を定義してみる。デコレータに引数が渡されるので、ネストが一つ増えることに注意する。
def D(n): def _(f): def __(*args, **keywords): print "*--" * n f(*args, **keywords) print "--*" * n return __ return _ @D(15) def hoge(n): print "hoge" * n @D(10) def fuga(a,b,c=8,d=10): print "fuga" * a print "fuga" * b print "fuga" * c print "fuga" * d ##hoge = D(15)(hoge) hoge(10) fuga(1,2,c=5,d=7)
*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-- hogehogehogehogehogehogehogehogehogehoge --*--*--*--*--*--*--*--*--*--*--*--*--*--*--* *--*--*--*--*--*--*--*--*--*-- fuga fugafuga fugafugafugafugafuga fugafugafugafugafugafugafuga --*--*--*--*--*--*--*--*--*—*
7. デコレータを重ねて利用する
デコレートに必要な情報をデコレータの呼出しのときに渡し、
デコレータを重ねて利用する
def D(top, bottom, x, y): def _(f): def __(*args, **keywords): print top * x f(*args, **keywords) print bottom * y return __ return _ @D("-#-", "-#-", 4, 10) @D("--*", "*--", 3, 9) @D("-+-", "+-+", 2, 7) def fuga(a,b,c=8,d=10): print "fuga" * a print "fuga" * b print "fuga" * c print "fuga" * d fuga(1,2,c=3,d=4)
-#--#--#--#- --*--*--* -+--+- fuga fugafuga fugafugafuga fugafugafugafuga +-++-++-++-++-++-++-+ *--*--*--*--*--*--*--*--*-- -#--#--#--#--#--#--#—#—#—#-
これで、一つのデコレータで様々な装飾を施せるようなった。 ^^
下図に、色分けして見やすくしたコードを示す。
投稿者 KURITA Jute 時刻: 15:39 0コメント
ラベル: Python , デコレータ
Haskell でフィールドに型変数を含んだ型の print
前回の「Haskell で代数的データ型の値を print で出力」では、型のフィールドに型変数が含まれていなかった。今回はフィールドに型変数が含まれる場合について試してみる。
Iremono a 型
例えば、何でも入る「入れ物」を想定し、型変数を一つフィールドに持つ `Iremono a 型’ を定義。
data Iremono a = Iremono a
これを print で出力できるようにしたい。
instance Show Iremono
ここで、次のように Iremono を Show クラスのインスタンスにすると、
instance Show Iremono
次のように怒られる。 (+_+)
`Iremono' is not applied to enough type arguments Expected kind `*', but `Iremono' has kind `* -> *' In the instance declaration for `Show Iremono'
これは kind と言って、型を分類するための概念らしい。 (cf. Kind – HaskellWiki) 詳しくはわからないので横に置いておく。 ^^; QQQ
instance Show (Iremono a)
ところで、Show クラスのインスタンスにしたい対象は Iremono 型ではなくて Iremono a 型。( Iremono は型ではなくて、型コンストラクタ) だから次のように、
instance Show (Iremono a) where show (Iremono x) = "nakami ari" main = print $ Iremono 100
上記は入れ物の中に中身がある場合に「中身あり」と表示させるようにしただけ。
instance Show a => (Iremono a)
しかし、普通 print と言ったら、その中身を表示させたいので、
instance Show (Iremono a) where show (Iremono x) = show x
これでいいのかなと思いきや、また怒られた。 (+_+)
Could not deduce (Show a) from the context (Show (Iremono a)) arising from a use of `show' at functest.hs:4:23-28 Possible fix: add (Show a) to the context of the type signature for `show' In the expression: show x In the definition of `show': show (Iremono x) = show x In the definition for method `show'
deduce とか難しいことが書かれている (@_@;) けれど、ゆっくりとエラーの内容を読むと、show x の式が問題なことがわかる。show x の x と言ったら、「入れ物」の `中身’ のこと。これはどんな型でも入れることができるので、show を適用できるかどうかはわからない。だから、次のように `中身’ も Show クラスのインスタンスでないといけないことを示す必要がある。
instance Show a => Show (Iremono a) where show (Iremono x) = show x
data Iremono a = Iremono a instance Show a => Show (Iremono a) where show (Iremono x) = show x main = print $ Iremono 100
前回教えていただいたように deriving を使うと、instance Show … を書かなくても、
data Iremono a = Iremono a deriving Show main = print $ Iremono 100
結果は、次のように表示される。
Iremono 100
A Gentle Introduction to Haskell: Standard Classes
投稿者 KURITA Jute 時刻: 13:13 0コメント
ラベル: Haskell , 型
Firefox のスクロールが遅い – ハードウェア アクセラレータの値を変更
1. 画像がたくさんあるページで、異常に重くなる
Firefox が特定のページで重い。
画像がたくさんあるとダメなのだろうか? 例えば、
4U - 4u beauty image bookmarking
なんてスクロールさせると CPU が異常に反応して、もたつく。
しかも、不思議なことに、マウスを画像の上に持っていくと、マウスの動きが激烈に悪くなる。 (+_+)
スクロールが遅い原因として、表示の拡大縮小が原因 だったことがあった。しかし、今回の原因はこれではない。
2. background-attachment を設定しても効果なし
調べてみると、firefoxだとこのページが重いです。 - 教えて!goo に
background-attachment:scroll !important;
これをuser.jsではなく、userContent.cssに書けばいいです。
アドオンとして Stylish を入れている。上記を userContent.css に書かなくても、Removes background-attachment: fixed | userstyles.org において、「Load into Stylish」のボタンを押して簡単にインストールできる。
しかし、効果はなかった。
Bug 201307 – slow scrolling in pages with position:fixed elements
に、重くて、もたつくページの例として、
a bit of position:fixed element and a bunch of resized images (2.30 KB, text/html)
があった。開いたら、なかなかスクロールさせることができない。
3. ハードウェア アクセラレータ の値を変更する
更に調べていたら、非常に気になるスレッドが。↓ (@_@;)
AMD Game Forums - 780G HD3200 XP slow 2D / browser scrolling major performance issue
(via. How to disable Powerplay ATI cards - GameReplays.org)
自分の PC のマザーボードは、GA-MA78GM-S2H (rev.1.1) なので、まさに上記に該当する。(cf. はじめての自作 PC の検討 2)
AMD の 780G で HD3200 。かつ Windows XP でブラウザのスクロールの問題。ATI 絡みの問題であることが書かれている。
とりあえずの対策として、次のようなことが書かれていた。
- right-click on your desktop
- click "properties"
- click the "settings" tab
- click the "advanced" button
- click the "troubleshoot" tab
- move the "hardware acceleration" slider ONE point to the left, so the description says something like "Disable cursor and bitmap accelerations. Use this setting..."
早速、上記の設定を試してみた。
コントロールパネル > 画面 より、設定タブ > 詳細設定ボタン
を押す。トラブルシューティングタブ を開いて、
ハードウェア アクセラレータ
の横スクロールバーが「最大」になっていたので、これを一つ左へ移動。
「カーソルおよびビットマップのアクセラレータを無効」
となる。なるほど、それでカーソルの動きが悪くなっていたのか。
4. 結果、スムーズに動くようになった
スクロールが普通にスイスイと動くようになった。 ^^  マウスジェスチャの動きもスムーズに。
これで、Yet Another Smooth Scrolling をインストールしても問題がなくなった。
しかし、最近、カクカクとした動きに慣れていたので、滑らかなスクロールにしたら、目が回った。(@_@;)
5. グラフィックドライバの問題
追記 (2009.1.12) : ATI Catalyst 8.12 にアップデートしたら画像の表示がスムーズになった。
投稿者 KURITA Jute 時刻: 1:10 7コメント
ラベル: Firefox 3
新しい投稿 前の投稿 ホーム
登録: 投稿(Atom)
jutememo.blogspot.com
Google+ Badge
Python で変数の型 (クラス) を調べる – types モジュール
Firefox の高速ダウンローダー DownThemAll! をデフォルトのダウンローダーの動作に近づける
DNS の IPv6 の設定を Google Public DNS に変更
Windows で見やすくて綺麗なフォント表示 - MeiryoKe に変更し、MacType で滑らかにする
Gimp で画像を結合する - 複数の画像を並べて一枚に合成。「キャンバスをレイヤーに合わせる」
Firefox, Cyberfox が「応答なし」で固まり、頻繁にフリーズする場合
NVIDIA のグラフィックスドライバーのインストールに失敗する原因は Comodo Firewall だった
どんな紙でもポストイットにする糊 - 「貼ってはがせる糊」も100円ショップにあった
サクラエディタで文字コードの変更
Google スプレッドシートで連続データを作成する 二つの方法
■ すぐに忘れる脳みそのための Wiki
■ 計るだけダイエット表の作成
■ Google 検索と同時に Google ブックマーク の検索結果を表示
►  2017 (1)
►  2016 (19)
►  2015 (101)
►  2014 (141)
►  10月 (13)
►  2013 (108)
►  10月 (12)
►  2012 (114)
►  2011 (111)
►  2010 (119)
►  10月 (12)
►  2009 (186)
►  12月 (16)
►  11月 (12)
►  10月 (19)
▼  2008 (505)
►  12月 (24)
►  11月 (36)
▼  10月 (48)
Firefox で特定のサイトのクッキーを受け付けないようにする
落ち着く音楽はないかな? - I Will See You Again
Haskell のリストのデータコンストラクタによるパターンマッチ
素朴にエラトステネスのふるい (3) – Python の実装を Haskell へ
Haskell の fmap
Haskell で文字列の分割と結合
Meadow (Emacs) で矩形領域をカット & ペースト
素朴にエラトステネスのふるい (2) - オブジェクト指向を手がかりに再帰表現を考える
Haskell で簡単なテキスト処理 (2)
Haskell で正規表現 (2) =~ , Python・Ruby と比較しながら
素朴にエラトステネスのふるい (1)
Python のジェネレータ (5) - 再帰とジェネレータと Composite
wxPython の準備 – Python で GUI
Python で部分適用 - functools モジュールの partial 関数
Firefox でウェブサイトの表の内容をコピーして表計算ソフトに貼り付ける
Python で二進数、十進数の変換
Python のデコレータ式 (3) - デコレートする側とデコレートされる側に引数がある場合
Haskell でフィールドに型変数を含んだ型の print
Firefox のスクロールが遅い – ハードウェア アクセラレータの値を変更
OpenOffice Calc で簡易に複数の関数のグラフを重ねて描く
OpenOffice Calc の ソルバー機能
Python のデコレータ式 (2) - デコレータに引数があり、複数のデコレータを適用する場合
Haskell で、繰り返しのある数値を生成する関数を定義 – read, cycle 関数を使って...
Haskell の数値 – Int は型で、Num は型クラス
Haskell でパスカルの三角形
explorer.exe から bb4win_mod へ
Python の文字列はシーケンス (2) - リストと文字列を透過的に扱うには if not L
Python の空リストと再帰
Python, Haskell の サーチ パス - いつも何度でも (o_ _)o~†
Python のデコレータ式 (1)
最近ずっと頭の中をループしている音楽 - A Paw in My Face
Haskell の Prelude 散策 (1) - リスト操作 : 要素の重ね合わせ (folds...
Python でメソッドの実行時間の計測
「Google エラー 申し訳ありません」
Python で逆ポーランド記法の計算
Python におけるバックスラッシュ (\) の扱いと、row stirng と正規表現における注...
Dropbox で Web のマーカーをポータブルに – Wired-Marker のデータをクラウ...
Python の文字列はシーケンスの一種 (1)
Haskell で代数的データ型の値を print で出力には
Make Link で「文章を引用」する形式を作成
AutoHotkey で サイトのタイトルと URL から、 FreeMind の子ノードを作成 (...