「ふつける」勉強会 資料用 このページをアンテナに追加 RSSフィード

 | 

2006-07-16

ふつける勉強会 第5回目 第六章 「基本的な値」 (終了) ふつける勉強会 第5回目 第六章 「基本的な値」 (終了) - 「ふつける」勉強会 資料用 を含むブックマーク はてなブックマーク - ふつける勉強会 第5回目 第六章 「基本的な値」 (終了) - 「ふつける」勉強会 資料用 ふつける勉強会 第5回目 第六章 「基本的な値」 (終了) - 「ふつける」勉強会 資料用 のブックマークコメント

リファレンス的な第2部で、このタイミングで基本的な値の説明。どわーっと値に関する話題(各型のリテラルの書き方と数値計算関数とか)があったあとに、catnという関数を作ってみてしめくくり。

まず、いろんな値と関連する関数の説明。

真偽値 Bool

  • not,(&&),(||)

副作用ある関数だと(||)や(&&)の実行順が気になるけど、haskellだと関係ないか。

数値

文脈によって型が解釈されうる。明示的に型指定も可能。数値演算一覧が(p.133)に。演算するときは型に注意。暗黙の変換はしてくれない。変換にはtoIntegerとかを使う。(p.134)に変換関数抜粋。

明示的に型を指定してみた。Intは32bitなのでちょうどあふれる。Integerなら大丈夫。

*Main> (2 ^ 32) :: Int
0
*Main> (2 ^ 32) :: Integer
4294967296

有理数型(Rational)や複素数型(Complex)を使えるようになるモジュールもある。

と思いきや、Rational型はPreludeにあった。

Prelude> (toRational 1)
1%1
Prelude> :t (toRational 1)
(toRational 1) :: Rational
Prelude> let a = (toRational 3)
Prelude> let b = (toRational 4)
Prelude> a / b
3%4

文字、文字列 Char,String([Char])

(内部的にはUnicodeだがGHCでは入出力のエンコーディング変換が未実装。)

タプル "(a,b)"

要素の個数と順序固定。要素が一個のタプルはない。

3つめ以降の値を直接とりだす関数は発見できず。パターンマッチで取れということか。

  • ふたつの配列からタプルの配列にするzipと逆変換unzip。
    • zip :: [a]->[b]->[(a,b)],unzip :: [(a,b)] -> ([a],[b])
    • p.142の図がわかりやすい

ユニット "()"

要素が0個のタプル。

リスト "[a]"

  • : がcons。
    • 右結合する。 1:2:3:[ ] = 1:(2:(3:[ ]))
  • null 空リスト判定。
  • (++) いわゆるappend。[1,2] ++ [3,4] -> [1,2,3,4]

リスト数列表記

  • [1..10] -> [1,2,3,4,5]
  • [1,3..10] -> [1,3,5,7,9] 増分を見てくれる。
  • '..'の前に三つ以上の要素を','で並べるとパースエラー
  • ['a'..'e'] -> "abcde" 文字もいける。増分指定も可。(['a','c'..'z']とか)
  • 終端を省略すると無限リスト.
    • ['a','c'..] もいけた。
    • 文字だと無限じゃなくて、文字コードの最後まで列挙しているらしい。
    • length ['a'..] -> 1114015
  • Enumがまさにこのための型クラスのようだ。あ、でもFloatやDoubleの挙動がよくわからない

:info Enumの結果

class Enum a where
  succ :: a -> a
  pred :: a -> a
  toEnum :: Int -> a    -- 数値と値の対応
  fromEnum :: a -> Int  
  enumFrom :: a -> [a] 
  enumFromThen :: a -> a -> [a] -- 増分指定
  enumFromTo :: a -> a -> [a]   -- 終端指定 
  enumFromThenTo :: a -> a -> a -> [a] -- 増分および終端指定

BoolやOrdering(比較結果を返す型)もEnumに属しているので…

*Main> [(False)..]
[False,True]
*Main> [(LT)..]
[LT,EQ,GT]

ということは…自分で定義した型もEnumの型クラスに属させておけば数列記法が使える。なかなか楽しい

data MyEnum = A | B | C | D | E | F |G deriving (Show,Enum) -- Enumのインスタンスとして定義
-- 以下、GHCiで読みこんだ後テスト
*Main> [(A)..(E)]  -- ()でくるまないとパースエラー
[A,B,C,D,E]
*Main> [(B)..]
[B,C,D,E,F,G]
*Main> [(A),(C)..(F)]
[A,C,E]
*Main> [(A),(C)..]
[A,C,E,G]

リスト内包表記

p.148より

[abs x | x <- xs]

…「xsの各要素xについて(abs x)を集める」

要は、

  • "<-"によるリストからの要素のとりだし。(複数のリストを指定すると全ての組みあわせを生成できる)
  • 条件式によるフィルタ
  • 要素を組みあわせた演算の結果をリストに。

をまとめた記法。上の例では、ひとつのリストを指定していて条件式もないが、クイックソートの例に条件式が、さらにその次に複数リスト指定した組みあわせ列挙の例あり。

全部組みあわせた例を書くとこんなかんじ。

*Main> [(x,y) | x <- [1..10],y <- [1..10] , x * 2 == y]
[(1,2),(2,4),(3,6),(4,8),(5,10)]

結局、mapとfilterとconcatがひとつにまとめられているだけだが、mapの入れ子相当のものを簡単に書けるようになっていて、はまると強力。

catnの実装

行番号付きでファイルの中身を表示するコマンド

zipLineNumberで行番号と行ペアのタプルをつくって、それぞれ(の行番号部分を)formatで整形して、最後にまとめて表示。

練習問題

resolv f (x:xs) = textify x ++ resolve f xs
getenv key env = fromMaybe "" $ lookup key env
readTemplate id = readFile $ prefix repo ++ "/" ++ id
-- に()をおぎなうと以下に
resolv f (x:xs) = (textify x) ++ (resolve f xs)
getenv key env = fromMaybe "" (lookup key env)
readTemplate id = readFile ((prefix repo) ++ ("/" ++ id))

(++)は右結合 (infixr 5)


ちなみに、今回のソースの表示には、http://hatena.g.hatena.ne.jp/hatenagroup/20060616/1150453529 を使って色をつけました。

 |