« 最近の日常ではない何か | メイン | 嗚呼、斑鳩に行く・・・・・・ »

2007年5月22日

Haskell勉強会#4メモ記録

なんか、blogに書くまでが勉強会みたいなのでちょっといろいろ書いてみます。ただ会場にいるメンバの3分の1がどうみてもRuby勉強会のメンバだったのはさすがというかある意味というか・・・。

まず、Haskellがなんぞやという人はごめんなさい、興味ある人は適当に各自で調べてください。LispやSchemeと同じ関数型言語ですが括弧がそんなに出てこないので多少はとっつきやすいかと思います。

今回は6.1から6.6までを主に読み進めました。

まずは復習というか基本的なことから、ということで関数の読み方を。


(&&) :: Bool -> Bool -> Bool
translate :: Char -> Char

たとえば、上の&&は第1引数がBool、第2引数もBool、返り値がBoolである関数、下のtranslateは第1引数がchar、返り値がcharであるような関数を示している。
公式には「関数名 :: 第一引数の型 -> 第二引数の型 -> ‥‥ -> 返り値の型」となっている。まぁ忘れやすいというかとにかくぱっと見て思い出せないと思う。
また、true && y のように書かれていた場合、yに関しては評価されない。

さらに自分で演算子を定義することも可能。


(^-^) :: String -> String -> String
(^-^) x y = x ++ " Love " ++ y

main = print $ "I" ^-^ "ruby"

これは[^-^]という演算子を自分で定義した例です。この例では2つの文字列を引数にとって、その間にLoveという文字列を挟むというものです。演算子として使える記号は[^]、[-]、[%]、[+]、[-]などなどです。多用しすぎるといろいろ文句言われそうな気がしますが。

普通の関数の場合だと前置記法で順番が関数、引数(f a b)となり、演算子だと中置記法で順番が引数1、演算子、引数2(a + b)になる。しかし、括弧をつけると中置記法を前置記法に変換( (+) a b)でき、また関数もバッククオートで囲むと中置記法になる(a 'f' b)。

ちなみに「中置記法」は「ちゅうちきほう」と読むらしいです。

次は数値型について。
基本はInt型とInteger型の2つがある、Int型は32ビット、Integer型は大きさが任意に決めることが可能。しかし2つを同時に計算はできない。

Prelude> ((300::Int) * (30000::Int)) 9000000

Prelude> ((300000::Int) * (300000000000::Int))
-305594368

Prelude> ((300000::Integer) * (300000000000::Integer))
90000000000000000

Prelude> ((300000::Integer) * (300000000000::Int))

:1:22:
Couldn't match expected type `Integer' against inferred type `Int'
In the second argument of `(*)', namely `(300000000000 :: Int)'
In the expression: ((300000 :: Integer) * (300000000000 :: Int))
In the definition of `it':
it = ((300000 :: Integer) * (300000000000 :: Int))

一番上がInt同士の計算、その次がオーバーフローを起こしたIntの計算、その次がInteger同士の計算、最後にIntとIntegerの計算です。ちなみに型宣言(::Intとか)を書いてない場合はIntegerになります。

後の型については省略、っていうかなんにもメモってなかった。
1つ注意しておくのはchar型とstring型は異なるということ。つまり1文字だとchar型、2文字以上だとstring型で別の型になる。

最後にタプルとリスト。
まず、リストについて。要は配列と思ってもらっていい(と勝手に考えている)。ただRubyなどに慣れている人間が1つ気をつけることはリストの中に格納できるのは同じ型のみ。一方タプルは異なる型でも格納できるという利点を持つ。

以下、はまりそうなところを。
zip :: [a] -> [b] -> [(a,b)]
2つのリストの各要素をつないだタプルのリストを作成、となるけどこの際aとbの長さが異なる場合は短いほうに合わせてくれます。

Prelude> zip [1, 2, 3, 4] ["Jan", "Feb", "Mar"] [(1,"Jan"),(2,"Feb"),(3,"Mar")]

Prelude> zip [1, 2, 3, '4'] ["Jan", "Feb", "Mar"]

:1:6:
No instance for (Num Char)
arising from the literal `1' at :1:6
Possible fix: add an instance declaration for (Num Char)
In the expression: 1
In the first argument of `zip', namely `[1, 2, 3, '4']'
In the expression: zip [1, 2, 3, '4'] ["Jan", "Feb", "Mar"]

unzip ::[(a,b)] -> [[a], [b]]
タプルのリストをリストのタプルの変換、ですがこの場合はタプルの中の要素数は必ず2個です。

リストについてはこんだけわかってればいいと思う。


[1..7] = [1,2,3,4,5,6,7]
['a' ..'e'] = ['a' , 'b' , 'c', 'd', 'e']
[1..] = [1,2,3,4............]  無限リスト
[1,3..] = [1,3,5........]  奇数を含む無限リスト

最後に内包表現。ここがある意味一番数学っぽい。例えば[abs x | x <- xs]のような表現があったとする。これは「リストxsの各要素について絶対値を返す」という意味だけど、数学的に表すと{ f(x) | ∀x ∈ {1,2,3,4,5,6} }みたいになる(この場合、リストxsの各要素が1から6までの値、関数fが絶対値を取る関数)。

これでかなり納得できたのはやっぱり理系人間だからなのかな。

というわけで今回はここまで。

投稿者 mak : 2007年5月22日 22:51

トラックバック

このエントリーのトラックバックURL:
http://sorakaze.net/cgi-bin/blog/mt-tb.cgi/111

コメント

コメントする