LoginSignup
12
14

More than 5 years have passed since last update.

すごいHaskellたのしく学ぼう! 第2章 読書メモ

Posted at

明示的な型宣言

GHCiで型を調べる

:tを使う。

:t "a"
-- "a" :: [Char]
:t 1
-- 1 :: Num a => a
:t 2.0
-- 2.0 :: Fractional a => a

::は〜の型を持つという意味。

関数の型宣言

引数と戻り値の方は->で区切って、戻り値の型は最後。

removeNonUppercase :: [Char] -> [Char]
removeNonUppercase st = [c | c <- st, c `elem` ['A'..'Z']]

addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z

Haskellの一般的な型

  • Int
  • Float
  • Double
  • Bool
  • Char

これらは他の言語とほぼ同じ。
違うのはこれ。

Integer

とても大きい整数。ただしIntを使うほうが効率的。

factorial 50
-- 30414093201713378043612608166064768844377641568960512000000000000

()

空のタプルも型。ユニットと呼ばれる。

型変数

:t head
-- head :: [a] -> a

aが型変数。どんな方も取り得る。
型変数を用いた関数は多相的関数と呼ばれる。
他のプログラミング言語にあるジェネリクスにちょっと似ている。

型変数の命名

abなど1文字の場合が多い。

型クラス

型クラスとは?

何らかの振る舞いを定義するインターフェイス。
具体的には関数の集まり。
また、それらの関数をその型クラスのメソッドと呼ぶこともある。

オブジェクト指向型言語のクラスとは同じものではない。

型クラス制約

GHCi==の型を確認。

:t (==)
-- (==) :: Eq a => a -> a -> Bool

=>よりも前にあるものは型クラス制約と呼ばれる。
この結果の意味は「==は同じ型の引数を2つ受け取り、Boolを返す。引数の2つの型はEqクラスのインスタンスでなければならない」

Eq型クラス

Haskellのすべての標準型はEqクラスのインスタンス(一部を除く)
2つの引数が同じ値かを確認。

Ord型クラス

何らかの順序付けられる型のための型クラス。

:t (>)
-- (>) :: Ord a => a -> a -> Bool
:t (>=)
-- (>=) :: Ord a => a -> a -> Bool

Show型クラス

ある値はその型がShow型クラスのインスタンスになっていれば、文字列として表現できる。
Rubyのto_sみたいなもの?

show 3
-- "3"
show "a"
-- "\"a\""

Read型クラス

文字列を受け取りReadのインスタンス型の値を返す。

read "True" || False
-- True
read "False" || False
-- False
read "1" + 2
-- 3

こういのはダメ。

read "5"

read関数の型は以下のとおり。
GHCiが何を返せばいいかわからない。GHCiread関数から戻ってきた値の型を判定できない。
直後に+ 5みたいなのがあると整数だと判定できる。

:t read
-- read :: Read a => String -> a

型注釈

コンパイラに型を伝える。

read "5" :: Int
-- 5
(read "5" :: Int) + 5
-- 10

Enum型クラス

要素の値を列挙できる型クラス。

['a' .. 'z']
-- "abcdefghijklmnopqrstuvwxyz"
[LT .. GT]
-- [LT,EQ,GT]

サンプルとして[LT .. GT]とあったけどLTってなんだろうか。

調べたあった。
HaskellのLT、GT、EQって - skalabeの日記

Orderingという型らしい。

Bounded型クラス

上限と下限を持つ。

minBound :: Int
--9223372036854775808
maxBound :: Int
-- 9223372036854775807
:t minBound
-- minBound :: Bounded a => a
:t maxBound
-- maxBound :: Bounded a => a

Num型クラス

数値の型クラス。

:t 10
-- 10 :: Num a => a
:t 10.5
-- 10.5 :: Fractional a => a
:t 10 :: Double
-- 10 :: Double :: Double

あらゆる数値は多相定数として表現されている。
多相定数ってなんだ?

*の型を調べる。

:t (*)
-- (*) :: Num a => a -> a -> a

2つの引数を受け取って1つの数を返し、これらはすべて同じ型でないといけない。
そのため、これはエラーになる。

(5 :: Integer) * (2 :: Int)

-- <interactive>:137:19:
--     Couldn't match expected type `Integer' with actual type `Int'
--     In the second argument of `(*)', namely `(2 :: Int)'
--     In the expression: (5 :: Integer) * (2 :: Int)
--     In an equation for `it': it = (5 :: Integer) * (2 :: Int)
--

けどこれはOK。

5 * (2 :: Integer)
-- 10

5はIntIntegerのどちらとしても振る舞える。

Floating型クラス

FloatDoubleが含まれる。浮動小数点の型クラス。

Integral型クラス

Numは実数の型クラス、Integralは整数の型クラス。

fromIntegral関数

浮動小数点と整数を一緒に扱う場合に使う。

fromIntegral :: (Integral a, Num b) => a -> b

何らかの整数を引数に取って一般的な数値を返す。

例えばlength関数は整数を返すので、その値に実数をプラスするとエラー。

length [1,2,3] + 3.2

-- <interactive>:148:18:
--     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] + 3.2
--     In an equation for `it': it = length [1, 2, 3] + 3.2

+は同じ型でなければいけない。

:t (+)
-- (+) :: Num a => a -> a -> a
fromIntegral(length [1,2,3]) + 3.2
-- 6.2

型クラスに関するいくつかの注意

  • 1つの型クラスはいくつもの型クラスのインスタンスになることができる
  • 1つの型クラスはいくつもの型をインスタンスとして持てる
  • ある型のインスタンスにするために一旦、別のクラスのインスタンスにする必要がある場合がある
  • OrdクラスのインスタンスになるにはEqクラスにインスタンスになる必要がある
12
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
14