Last active
August 29, 2015 14:07
-
-
Save akiyoshi83/3d84e8e83661ee8a9986 to your computer and use it in GitHub Desktop.
写経:『すごいHaskellたのしく学ぼう!』
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- | |
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