Thursday, July 24, 2014

Haskell part3

haskell勉強中。part3。今の段階だと本当に面白い言語だ。

Types and Typeclasses

とりあえずTypeとTypeclassの違いを分かりたい。
Typeはその名の通り型で、Typeclassは型の振る舞い(特性)を決めるひな形っぽい役割を持っている気がする。typeclassは型制約として:tコマンドで表示したときの=>シンボルの前に表れる。

:t コマンド

:tコマンドで型を調べることができる。
*Main> :t "y"
"y" :: [Char]
*Main> :t "yukarin"
"yukarin" :: [Char]
*Main> :t 'y'
'y' :: Char
*Main> :t "y"
"y" :: [Char]
*Main> :t "yukarin"
"yukarin" :: [Char]
*Main> :t 10
10 :: Num a => a
*Main> :t True
True :: Bool
*Main> :t doubleMe
doubleMe :: Num a => a -> a
*Main> :t [1,2,3]
[1,2,3] :: Num t => [t]
*Main> :t (1,2)
(1,2) :: (Num t, Num t1) => (t, t1)
*Main> :t ("yukarin", "makky")
("yukarin", "makky") :: ([Char], [Char])
型というか定義だな。これ。
::has a type ofと読み替えてね、とのこと。
part1で出てきたこの関数。
removeNonUppercase :: [Char] -> [Char]  
removeNonUppercase st = [ c | c <- st, c `elem` ['A'..'Z']]
  • [Char]はつまるところString
  • このケースでは、別に型の情報を与えなくてもコンパイラが勝手にString -> Stringを解釈
:tは関数を作ったものの、型がよく分からない時に使うといいよ、って書いてある。
--addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z
型を指定する場合と指定しない場合では:tしたときの結果が違う。
指定した場合。
*Main> :t addThree
addThree :: Int -> Int -> Int -> Int
指定しない場合。
*Main> :t addThree
addThree :: Num a => a -> a -> a -> a
指定した場合はInt以外を与えると落ちそうだな…
*Main> addThree 1.1 2.2 3.3

<interactive>:266:10:
    No instance for (Fractional Int) arising from the literal `1.1'
    Possible fix: add an instance declaration for (Fractional Int)
    In the first argument of `addThree', namely `1.1'
    In the expression: addThree 1.1 2.2 3.3
    In an equation for `it': it = addThree 1.1 2.2 3.3
落ちた。型を指定しない場合はNumなので小数点も捌いてくれる。

Type

補足
Int -2147483648..2147483647
Integer 制限なし(not bounded)
Float 単精度
Double 倍精度
Bool True, False
Char キャラクタ(文字)、シングルクォートで括って表現
Tuple タプルもいわゆる型だが、タプル長ごとに異なる型と言える。タプルの各要素も型であるため、理論的には無限個の型が存在する。ちょっと難しいのでこれ以上は書かない。ただ()もまた、単一の()を値として持つ型だということを覚えておいてくれ..ともう何言ってるか分からないorz

Typeclasses 101

==の定義。

Prelude> :t (==)
(==) :: Eq a => a -> a -> Bool
シンボル=>の前の記述は全てclass constraitになる。
この定義の意味は、==は2つの型が同じ値を取り、返り値としてBoolを返すになる。この2つの型aはEqクラスに属しているとなり、これがclass constraint
Eq typeclassは等価性を確認するためのインターフェースを提供。IOを除く全てのHaskellの標準型はEq typeclassに属している。
Prelude> 5 == 5
True
Prelude> 5 /= 5
False
Prelude> 'a' == 'a'
True
Prelude> "yukarin" == "yukarin"
True
Prelude> 3.1234 == 3.1234
True
Prelude> [1, 2] == [1, 2]
True
Prelude> (1, 2) == (1, 2)
True
これを踏まえた上でelem関数。
Prelude> :t elem
elem :: Eq a => a -> [a] -> Bool
リストの中に同じ値があるかをチェックするのでclass constraintとしてEq aが設定されている。
Eqは等価性のテストをサポートする==/=を実装している。関数の型変数にEq class constraintがかかている場合,その定義のどこかで==または/=が使われている。

Ord

Ordは順序を持つ型。
Prelude> :t (>)
(>) :: Ord a => a -> a -> Bool
Prelude> :t compare
compare :: Ord a => a -> a -> Ordering
ここまでで言及した関数以外の型はOrd型にも属している。Ordは’>’, <,>=, <=といった標準的な比較関数を実装している。比較関数は2つの同じ型のメンバーを取り、Bool値を返す。 Orderingは型の一種であり、GT,LT,EQのいずれかの値を持つ。それぞれgreater than, lesser than, equalの意味。
Ordのメンバーになるためには、まずEqの一員でなければならない。
Prelude> "Yukarin" > "Maki"
True
Prelude> "Yukarin" `compare` "Maki"
GT
Prelude> 5 >= 2
True
Prelude> compare 5 2
GT

Show

ShowのメンバーはStringで表現できる。
Prelude> :t show
show :: Show a => a -> String
Prelude> show 2
"2"
Prelude> show 1.2345
"1.2345"
Prelude> show True
"True"
Prelude> show "yukarin"
"\"yukarin\""
関数以外の全ての型はこれまで同様Showクラブの会員様。Showクラブの中でも最も人気があるのは上記例のshowで、受け取った会員の値をstringで表現する。

Oposite

ReadはShowとは対照的なtypeclassになっている。Stringで受け取ったデータを、対応するReadクラブに所属する型に変換する。
Prelude> :t read
read :: Read a => String -> a
Prelude> read "True" || False
True
Prelude> read "8.2" + 3.8
12.0
Prelude> read "5" - 2
3
Prelude> read "[1,2,3,4]" ++ [3]
[1,2,3,4,3]
Prelude> read "8.2"

<interactive>:49:1:
    No instance for (Read a0) arising from a use of `read'
    The type variable `a0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Read () -- Defined in `GHC.Read'
      instance (Read a, Read b) => Read (a, b) -- Defined in `GHC.Read'
      instance (Read a, Read b, Read c) => Read (a, b, c)
        -- Defined in `GHC.Read'
      ...plus 25 others
    In the expression: read "8.2"
    In an equation for `it': it = read "8.2"
右側の取ってつけたようなRead会員様はもしかして、型を確定(推定)させるために付与してるのん…? 続く文面でそんなことが書いてるからきっとそうなんだな…。
こんな悲しい事態を回避するためにtype annotationさんがいる。
Prelude> read "5" :: Int
5
Prelude> read "5" :: Float
5.0
Prelude> read "[1,2,3,4]" :: [Int]
[1,2,3,4]
Prelude> read "(\"yukarisan\", 18)" :: (String, Int)
アノテーションでReadクラブの会員様を指定すれば変換が許可されるみたいだ。

Enum

Enumクラブはシーケンシャルな順番を有するかが参加資格になる。この手のtypeclassの利点はレンジ指定ができるところにある。あらかじめ次の値、1つ前の値が確定している。succ, predでこの値を参照できる。
Enumクラブの会員typeclass。
(), Bool, Char, Ordering, Int, Integer, Float, Double
Prelude> :t succ
succ :: Enum a => a -> a
Prelude> :t pred
pred :: Enum a => a -> a
Prelude> ['a'..'e']
"abcde"
Prelude> [LT .. GT]
[LT,EQ,GT]
Prelude> [3 .. 5]
[3,4,5]
Prelude> succ 'B'
'C'

Bounded

上限・下限、自分の限界をわきまえた大人のためのクラブ。
Prelude> :t minBound
minBound :: Bounded a => a
Prelude> :t maxBound
maxBound :: Bounded a => a
Prelude> minBound :: Int
-2147483648
Prelude> maxBound :: Char
'\1114111'
Prelude> maxBound :: Bool
True
Prelude> maxBound :: (Bool, Int, Char)
(True,2147483647,'\1114111')
minBound, maxBoundは意味敵的には多様な定数と捉えることができる。最後のサンプルのようにタプルは、その要素の型がBounded会員の場合は、自身もBounded会員になる。

Num

数値に関するtypeclass。このメンバーは数値のように振る舞う特性を持っている。
Prelude> :t 10
10 :: Num a => a
Prelude> :t 0.1
0.1 :: Fractional a => a
aはNum型に何かだよ、という制約が付いている。FractionalというtypeclassもNumと同じレベルであるんだな。
Prelude> :t (*)
(*) :: Num a => a -> a -> a
積算の定義、typeclassがNumの2つの値を取り、同a型を返す。

Integral

Numと異なり、整数のみを含むtypeclass。IntとIntegerを包含している。

Floating

数値を扱うとても便利な関数にfromIntegralがある。
こいつの定義。
Prelude> :t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b
Integral会員に属す型の値を与えると、それをNum会員の値に変換して返す。
Prelude> :t length
length :: [a] -> Int
Prelude> length [1,2,3,4] + 3.2

<interactive>:99:20:
    No instance for (Fractional Int) arising from the literal `3.2'
    Possible fix: add an instance declaration for (Fractional Int)
    In the second argument of `(+)', namely `3.2'
    In the expression: length [1, 2, 3, 4] + 3.2
    In an equation for `it': it = length [1, 2, 3, ....] + 3.2
この例でlength関数はInt型の値を返すので、その結果と3.2という浮動小数点で計算ができない。ここでfromIntegrsal先生を使うと、これはNum bを返すので3.2との足し算が可能になる。
Prelude> fromIntegral (length [1,2,3,4]) + 3.2
7.2
Written with StackEdit.

No comments:

Post a Comment