Kahjin’s Weblog

[雑談]

未分類 カテゴリーへ kahjin が 2月 7, 2010 に投稿

Q.いつ大人(オヤジ)になるか?

A.枕が臭くなったら

ってまだ、身なり次第では高校生でもいけるらしい。

[写真]

未分類 カテゴリーへ kahjin が 2月 6, 2010 に投稿

[写真]

未分類 カテゴリーへ kahjin が 2月 6, 2010 に投稿

[和訳]LYHGG4-3

未分類 カテゴリーへ kahjin が 2月 6, 2010 に投稿

http://learnyouahaskell.com/syntax-in-functions#where
Creative Commons

Where!?

前のsectionで、こんなふうにBMIを計算する関数を定義したよね。

bmiTell :: (RealFloat a) => a -> a -> String
bmiTell weight height
| weight / height ^ 2 <= 18.5 = “You’re underweight, you emo, you!”
| weight / height ^ 2 <= 25.0 = “You’re supposedly normal. Pffft, I bet you’re ugly!”
| weight / height ^ 2 <= 30.0 = “You’re fat! Lose some weight, fatty!”
| otherwise = “You’re a whale, congratulations!”

気付いた?3回も同じことを繰り返してるのを。これはお仕置きレベルだね。なんのためのプログラミングだよって(どこへ蹴り飛ばしているのやら)。同じexpressionを3回も繰り返すなら、一度に計算してから、計算結果を名前にbindするなり、expressionの代わりにその名前を使うなりした方が理想的なんだ。そうだね、このように関数を修正できるんだ。

bmiTell :: (RealFloat a) => a -> a -> String
bmiTell weight height
| bmi <= 18.5 = “You’re underweight, you emo, you!”
| bmi <= 25.0 = “You’re supposedly normal. Pffft, I bet you’re ugly!”
| bmi <= 30.0 = “You’re fat! Lose some weight, fatty!”
| otherwise = “You’re a whale, congratulations!”
where bmi = weight / height ^ 2

guradの後にwhere句をつけて(パイプがインデントされているのと同じ感じでwhere句もインデントするのがいいね)、nameやfunctionを定義するんだ。これで、nameがgurad全体に行き届いて、繰り返しを防ぐ効果をもたらしてくれるんだ。 もし、すこし違ったBMIの計算をしようと決めたら、すぐに関数の定義を変更したいよね。こんな感じでBMIを定義しておくと、プログラムの可読性が上がるし、bmiの変数が一度しか計算されていないから、プログラムが作り直しやすいよね。それじゃ、もう少しだけ沖にいこうか。関数をこうするんだ。

bmiTell :: (RealFloat a) => a -> a -> String
bmiTell weight height
| bmi <= skinny = “You’re underweight, you emo, you!”
| bmi <= normal = “You’re supposedly normal. Pffft, I bet you’re ugly!”
| bmi <= fat = “You’re fat! Lose some weight, fatty!”
| otherwise = “You’re a whale, congratulations!”
where bmi = weight / height ^ 2
skinny = 18.5
normal = 25.0
fat = 30.0

関数のwhereセクションで定義したnameは関数の中でしか効き目がないから、他の関数にまでに感染する恐れはないんだ。 すべてのnameが縦に並んでいるのに気付いたと思うんだけど、もうちょっとかっこよく並べないのはHaskellがそれらが同じblockの部品なのかがわからなくて、混乱するからなんだ。where bindingsは異なるパターンの関数bodyを共有しないので、もし、同じ(共有する)名前で一つの関数の複数のパターンにアクセスしたいなら、それをgloballyに定義しないといけないんだ。

where bindingsをpattern matchのように使えるんだ。whereセクションをこんな風に書き換えることができるね。


where bmi = weight / height ^ 2
(skinny, normal, fat) = (18.5, 25.0, 30.0)

それじゃあ、whereを使って、firstname とlastnameを受け取って、それらのイニシャルを返す関数を作ってみよう。

initials :: String -> String -> String
initials firstname lastname = [f] ++ “. ” ++ [l] ++ “.”
where (f:_) = firstname
(l:_) = lastname

関数のパラメタをpattern matchingにすることもできるんだけど(すると、コードが短くなるし、すっきりする)、where bindingsでも似たようなことができることを確認を込めてやりました。

where blockで定数の定義をしたんだけど、ここでも関数が定義できるんだ。健康的なプログラミングが習慣になるように、weight-heightペアのリストを受け取って、BMIsのリストを返す関数を作ってみよう。

calcBmis :: (RealFloat a) => [(a, a)] -> [a]
calcBmis xs = [bmi w h | (w, h) <- xs]
where bmi weight height = weight / height ^ 2

こうすると、コンパクト! この例題で関数にbmiを入れたかった理由は関数のパラメタからだと、ひとつのBMIしか計算できなかったんだけど、関数にペアのリストを渡すと、次から次へと異なるBMIが現れるのを説明したかったからなんだ。

where bindingsもネスト構造にできるね。次文省略: It’s a common idiom to make a function and define some helper function in its where clause and then to give those functions helper functions as well, each with its own where clause.

[写真]

未分類 カテゴリーへ kahjin が 1月 30, 2010 に投稿

[写真]

未分類 カテゴリーへ kahjin が 1月 30, 2010 に投稿

[和訳]LYHGG4-2

未分類 カテゴリーへ kahjin が 1月 30, 2010 に投稿

http://learnyouahaskell.com/syntax-in-functions#guards-guards
Creative Commons

Guards, guards!

patternsは値がある形式に則しているのかを確かめたり、それを分解してみたりする方法だったんだけど、guardsは値の特性が正しいかどうか(真偽)を検証する方法なんだ。なんだかif文みたいなもんに聞こえると思うんだけど、そんなに違わないし、ほとんど同なじ。ただ、guardsを使うとコードが読みやすいし、条件を書き下すときに、なんだかパターンを弄んでる気分なんだ。

guradsの構文を説明するかわりに、さっそく浸かってみようか。

君のBMIによって、異なる忠告をする関数でも作ってみよう。体重を身長の2乗で割った値が君のBMIだから。もし、BMIが18.5以下なら、やせすぎってみなされるんだ。18.5〜25ぐらいなら標準だね。25〜30ぐらいなら、少し太りぎみかな。30以上なら、肥満。これを関数にしてみよう(ただし、BMIの計算はしないよ、BMIの数値から、忠告するところまでね)。

bmiTell :: (RealFloat a) => a -> String
bmiTell bmi
| bmi <= 18.5 = “You’re underweight, you emo, you!”
| bmi <= 25.0 = “You’re supposedly normal. Pffft, I bet you’re ugly!”
| bmi <= 30.0 = “You’re fat! Lose some weight, fatty!”
| otherwise = “You’re a whale, congratulations!”

guradsは関数名とそのパラメタを|(パイプ)で守衛しているんだ※64。少しだけ右側にインデントして整列させるのが慣習なんだ。guardは基本的にbooleanのexpressionなんだ。評価がTrueなら、body部分の関数を使うんだ。逆にFalseなら、次の関門に以降するだけだよ。それの繰り返し。もし、値が24.3でこの関数を呼び出したら、まず、最初に18.5以下かどうか調べられるんだ。違ったなら、次のguardにってね。二番目のguardで25.0以下だと判別されると、門が開いて、文字列が飛び出てくるんだ。

これは手続き型言語におけるbig if elseツリーを思い出させるよね。ただ、こっちの方がかなり読みやすいと思うんだ。次文省略:While big if else trees are usually frowned upon, sometimes a problem is defined in such a discrete way that you can’t get around them. guradはこのif else ツリーの代替法なんだ※65。

最後の門番はえてしてotherwiseなんだ。otherwiseの定義はシンプルで、どんとこいのTrue and catches everythingなんだ。これはpatternsとよく似ているけど、patternsはinputがパターンを充たすかどうかで、guardはbooleanの条件を調べるだけなんだ。もし、すべての関門でFalseと評価されたら(もちろん、最後の門番がいないときを考えているよ)、関数の評価は次のpatternに投げ出されるんだ(ごむたいな)。patternとguardがいかに協調的に働くか。身元確認と持ち物検査が済まないと、出国できなくて、不法入国者として投獄されるかも※66。

もちろん、お連れがたくさんいる関数にもguradを使うこともできるんだ。ユーザにBMIを計算させる代わりに、ユーザのheightとweightを受け取って、それを計算させる関数に修正してみよう。

bmiTell :: (RealFloat a) => a -> a -> String
bmiTell weight height
| weight / height ^ 2 <= 18.5 = “You’re underweight, you emo, you!”
| weight / height ^ 2 <= 25.0 = “You’re supposedly normal. Pffft, I bet you’re ugly!”
| weight / height ^ 2 <= 30.0 = “You’re fat! Lose some weight, fatty!”
| otherwise = “You’re a whale, congratulations!”

どうかヤセでありますように…

ghci> bmiTell 85 1.90
“You’re supposedly normal. Pffft, I bet you’re ugly!”

やった、太ってなかったよ!でも、Haskellの野郎がお前はUglyだって。ちきしょー!!

最初のguardの前に関数名とパラメタの右隣に=がないことに注意してね。おそらく、ここに=を書いて、syntax errorを頻発することになると思うから。

もういっちょ例をみてみよう。そうだ、オリジナルのmax関数を作ってみよう。覚えてるかな?比較できるものを二つ受け取って、そのうち大きい方を返す関数だったよね。

max’ :: (Ord a) => a -> a -> a
max’ a b
| a > b = a
| otherwise = b

インラインでもguardを書けるんだ。関数は短くなるけど、とっても読みにくいんだ。でも、せっかくだからインラインで書いてみよう。

max’ :: (Ord a) => a -> a -> a
max’ a b | a > b = a | otherwise = b

うげ!まったくもって読みにくい。とっとと次にいこう。guardを使って、オリジナルのcompare関数を作ってみよう。

myCompare :: (Ord a) => a -> a -> Ordering
a `myCompare` b
| a > b = GT
| a == b = EQ
| otherwise = LT

ghci> 3 `myCompare` 2
GT

infix’ ’で関数を呼び出せるし、こっちの方が読みやすい時があるから、覚えといて。

  • ※64 鉄格子
  • ※65 これを比較するのはちときついでしょう。switch -caseでええやん
  • ※66 If no suitable guards or patterns are found, an error is thrown.

[雑談]

未分類 カテゴリーへ kahjin が 1月 24, 2010 に投稿

オーシャンズを観てきました。

細かい音響とかよく拾っていて(本当?)、生物達の息遣いや動きがスクリーン越しで感じられました。少し時事色が強いですね。クモガニの集団行動には私も興味が湧きました。

[写真]

未分類 カテゴリーへ kahjin が 1月 24, 2010 に投稿

[写真]

未分類 カテゴリーへ kahjin が 1月 24, 2010 に投稿