Skip to content

Instantly share code, notes, and snippets.

@akiyoshi83
Last active August 29, 2015 14:07
Show Gist options
  • Save akiyoshi83/3d84e8e83661ee8a9986 to your computer and use it in GitHub Desktop.
Save akiyoshi83/3d84e8e83661ee8a9986 to your computer and use it in GitHub Desktop.
写経:『すごいHaskellたのしく学ぼう!』
module Main where
factorial :: Integer -> Integer
factorial n = product [1..n]
circumference :: Float -> Float
circumference r = 2 * pi * r
circumference' :: Double -> Double
circumference' r = 2 * pi * r
main = do
print $ factorial 50
print $ circumference 4.0
print $ circumference' 4.0
{-
Chapter 2 型を信じろ!
-}
{-
2.1 明示的な型宣言
-}
{-
:: という記号は「の型を持つ」と読む。
GHCiでは :t コマンドで型を確認できる。
-}
Prelude> :t 'a'
'a' :: Char
Prelude> :t True
True :: Bool
Prelude> :t "HELLO!"
"HELLO!" :: [Char]
Prelude> :t (True, 'a')
(True, 'a') :: (Bool, Char)
Prelude> :t 4 == 5
4 == 5 :: Bool
{-
GHCiで関数名を定義するにはletが必要だが、型宣言をしようとするとエラーになる。
以下のように一行で関数本体も記述する。
-}
Prelude> let removeNonUppercase :: [Char] -> [Char]; removeNonUppercase st = [ c | c <- st, c `elem` ['A' .. 'Z']]
Prelude> :t removeNonUppercase
removeNonUppercase :: [Char] -> [Char]
-- letのあとを波括弧で囲むこともできる。
Prelude> let { removeNonUppercase :: [Char] -> [Char]; removeNonUppercase st = [ c | c <- st, c `elem` ['A' .. 'Z']] }
-- 複数行で書くこともできる。
-- この場合letのあとの波括弧は必須みたい。
Prelude> :{
Prelude| let {
Prelude| removeNonUppercase :: [Char] -> [Char];
Prelude| removeNonUppercase st = [ c | c <- st, c `elem` ['A' .. 'Z']];
Prelude| }
Prelude| :}
Prelude> :t removeNonUppercase
removeNonUppercase :: [Char] -> [Char]
Prelude> :{
Prelude| let {
Prelude| addThree :: Int -> Int -> Int -> Int;
Prelude| addThree x y z = x + y + z;
Prelude| }
Prelude| :}
Prelude> :t addThree
addThree :: Int -> Int -> Int -> Int
{-
2.2 一般的なHaskellの型
-}
{-
ここではchapter02.hsに実装して試す。
CharはUnicode文字を表し文字列型はその配列。
真理値型BoolはTrueとFalseのみ。
タプルは要素数とそれぞれの型によって無限の型があるが、
処理系としては要素の最大数は今のところ62個。
また空のタプル()も型でありただ1つの値()を持つ。
空のタプルはユニットと呼ばれることもある。
-}
-- Intは有界(最小値、最大値がある)のに対しIntegerはその制限がない。
Prelude> :l chapter02
[1 of 1] Compiling Main ( chapter02.hs, interpreted )
Ok, modules loaded: Main.
*Main> factorial 50
30414093201713378043612608166064768844377641568960512000000000000
*Main> circumference 4.0
25.132742
*Main> circumference' 4.0
25.132741228718345
{-
2.3 型変数
-}
{-
型名は大文字で始まるが以下の型の部分は小文字。
これを型変数と呼ぶ。
ジェネリクスみたいなもの。
型変数を使った関数を多相的関数と呼ぶ。
-}
-- headの型宣言は「任意の型のリストを引数に取り、素のか他の要素を1つ返す」と読める。
Prelude> :t head
head :: [a] -> a
-- fstの型宣言は「タプル(ダブル)を引数に取りその1つ目と同じか他の値を返す」と読める。
Prelude> :t fst
fst :: (a, b) -> a
{-
2.4 型クラス 初級講座
-}
{-
型クラス: インターフェース、関数の集まり
型: 型クラスのインスタンス
メソッド: 固くラスに属する関数をその型クラスのメソッドと呼ぶ
-}
{-
以下の演算子は実際には関数。
関数名が特殊文字のみからなる場合デフォルトで中置関数になる。
型名を調べたり他の関数に渡す場合は丸括弧で囲む。
-}
{-
=> というシンボルは型クラス制約と呼ばれる。
(==)の場合はaがEq型クラスのインスタンスである必要があることを表す。
ちなみにHaskellのI/O型と関数を除く全ての標準型はEqのインスタンス。
-}
Prelude> :t (==)
(==) :: Eq a => a -> a -> Bool
Prelude> :t (+)
(+) :: Num a => a -> a -> a
Prelude> :t (-)
(-) :: Num a => a -> a -> a
Prelude> :t (*)
(*) :: Num a => a -> a -> a
Prelude> :t (/)
(/) :: Fractional a => a -> a -> a
-- Eq型クラス
-- 等値性をテストできる型に使われる。
-- ==, /=を定義する。
Prelude> 5 == 5
True
Prelude> 5 /= 5
False
Prelude> 'a' == 'a'
True
Prelude> "Ho Ho" == "Ho Ho"
True
Prelude> 3.423 == 3.423
True
-- Ord型クラス
-- 順序を付けられる型に使われる。
-- >, <, >=, <= を定義する。
-- 関数を除けば全ての標準型はOrdのインスタンス。
Prelude> :t (>)
(>) :: Ord a => a -> a -> Bool
Prelude> "Abrakadabra" < "Zebra"
True
Prelude> "Abrakadabra" `compare` "Zebra"
LT
Prelude> 5 >= 2
True
Prelude> 5 `compare` 3
GT
Prelude> 'b' > 'a'
True
-- Show型クラス
-- 関数を除けば全ての標準型はShowのインスタンス。
-- Show型クラスのインスタンスは文字列として表現できる。
-- showは引数の値を文字列として表示する。
Prelude> show 3
"3"
Prelude> show 5.334
"5.334"
Prelude> show True
"True"
-- Read型クラス
-- 関数を除けば全ての標準型はShowのインスタンス。
-- Showと対をなす型クラス。
-- readは文字列を受け取りReadのインスタンスの型を返す。
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]
-- readが返り値の型を推論で切るのは返り値に何かしらの操作をしているから。
-- 以下のコードはエラーを起こす。
Prelude> read 4
<interactive>:2:6:
No instance for (Num String) arising from the literal `4'
Possible fix: add an instance declaration for (Num String)
In the first argument of `read', namely `4'
In the expression: read 4
In an equation for `it': it = read 4
-- readの型を確認。
-- Stringは単に[Char]のエイリアス。
Prelude> :t read
read :: Read a => String -> a
-- readの型宣言からはaがReadのインスタンスであることは分かるが、
-- 具体的にどの型かまでは分からない場合がある。
-- そんた場合に型注釈が使える。
Prelude> read "5" :: Int
5
Prelude> read "5" :: Float
5.0
Prelude> (read "5" :: Float) * 4
20.0
Prelude> read "[1,2,3,4]" :: [Int]
[1,2,3,4]
Prelude> read "(3, 'a')" :: (Int, Char)
(3,'a')
-- Haskellは型推論があるので
-- 以下のようにリストに突っ込んだりしていれば型注釈はいらない。
-- リストは要素の肩書き待っているのでおのずとBoolだと分かる。
Prelude> [read "True", False, True, False]
[True,False,True,False]
-- Enum型クラス
-- 順番に並んだ型、要素の値を列挙できる型
-- これのインスタンスはレンジの中で使える。
-- また後者関数succと前者関数predも定義される。
-- 主な具体的なインスタンスは
-- (), Book, Char, Ordering, Int, Integer, Float, Dobule
-- ※なんでユニットもなのか?
Prelude> ['a' .. 'e']
"abcde"
Prelude> [LT .. GT]
[LT,EQ,GT]
Prelude> [3 .. 5]
[3,4,5]
Prelude> succ 'B'
'C'
-- Bounded型クラス
-- 上限と下限を持つ。
-- それぞれminBoud, maxBoundで調べられる。
Prelude> minBound :: Int
-9223372036854775808
Prelude> maxBound :: Char
'\1114111'
Prelude> maxBound :: Bool
True
Prelude> minBound :: Bool
False
-- minBound, maxBoundの型はちょっと変わっている。
-- 多相定数とか言われるらしい(?)
-- 関数なのに::で使われるのは多相定数だから?本当に関数?
Prelude> :t minBound
minBound :: Bounded a => a
Prelude> :t maxBound
maxBound :: Bounded a => a
-- タプルの全ての要素がBoundedのインスタンスなら、
-- そのタプル自体もBoundedになる。
-- ※どんな用途があるのかは不明。
Prelude> minBound :: (Bool, Int, Char)
(False,-9223372036854775808,'\NUL')
-- Num型クラス
-- Numも多相定数。
Prelude> :t 20
20 :: Num a => a
-- 多相定数ってつまり色んな具体的な型として振る舞えるってこと?
Prelude> 20 :: Int
20
Prelude> 20 :: Integer
20
Prelude> 20 :: Float
20.0
Prelude> 20 :: Double
20.0
-- (*)の型を見ると3つのaはNumのインスタンスでかつ同じ型。
-- IntもIntegerもNumのインスタンスだがaは同時に2つにはなれない。
Prelude> :t (*)
(*) :: Num a => a -> a -> a
-- これはダメ。
Prelude> (5 :: Int) * (6 :: Integer)
<interactive>:56:15:
Couldn't match expected type `Int' with actual type `Integer'
In the second argument of `(*)', namely `(6 :: Integer)'
In the expression: (5 :: Int) * (6 :: Integer)
In an equation for `it': it = (5 :: Int) * (6 :: Integer)
-- これはOK。
Prelude> 5 * (6 :: Integer)
30
-- Floating型クラス
-- 浮動小数点数。
-- Float, Double。
-- sin, cos, sqrtなど。
Prelude> :t sin
sin :: Floating a => a -> a
Prelude> sin 1.0
0.8414709848078965
Prelude> :t cos
cos :: Floating a => a -> a
Prelude> cos 1.0
0.5403023058681398
Prelude> :t sqrt
sqrt :: Floating a => a -> a
Prelude> sqrt 2.0
1.4142135623730951
-- Integral型クラス
-- 整数。
-- Int, Integer。
-- fromIntegralは整数を実数にする。
-- ちなみに複数の型クラス制約は丸括弧で囲んでカンマで区切る。
Prelude> :t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b
-- 例えば整数を返す関数があって
Prelude> :t length
length :: [a] -> Int
-- その結果を実数を要求する関数に渡す場合に使える。
Prelude> fromIntegral (length [1,2,3,4]) + 3.2
7.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment