Programming in Haskell 2nd editionやる
用語リスト
名前 | 英語 | 説明 |
---|---|---|
GHC | Glasgow Haskell Compiler | 名前の通り |
GHCi | Glasgow Haskell Compiler interactive | 対話型インタプリンタ |
プレリュード関数 | 組み込み関数が定義されているモジュール | |
全域関数 | すべての入力対して出力の値が定義されているのが全域関数、入力によっては出力の値が未定義になる関数が部分関数 |
常用するコマンド(随時更新)
runghc <ソースファイル>
ghci tui
ghci
# ソースファイルを読み込んで、REPL起動
ghci <ソースファイル>
著者前書き
Haskellは純粋関数型のプログラミング言語
Scalaとかは関数型のプログラミング言語なのかな。Haskellは「純粋」な点が違う(?)
- I
- 型
- 関数
- リスト内包表記
- 再帰関数
- 高階関数
- II
- モナド
- 構文解析
- Foldable
- 遅延評価
- プログラムの論証
1.5.2.
where
は局所定義のためのキーワード
qsort2 (x : xs) = qsort smaller ++ [x] ++ qsort larger
where
smaller = [a | a <- xs, a <= x]
larger = [b | b <- xs, b > x]
以下の2つが局所的に定義されている
- xsからx以下である全ての要素aを取り出して作ったリストsmaller
- xsからxより大きい全ての要素bを取り出して作ったリストlarger
2.4.
Haskellでは、言語において最も中心的な役割を担う関数適用に対して空白文字を使い、乗算対しては*を明記します。
関数適用は他のすべての演算子よりも高い結合順位を持ちます。
こんな感じ?
f a b + c*d
(((f a) b) + (c*d))
2.5.1.
Haskellでは、慣習として、引数がリストである場合には名前の末尾にsを付けて複数の値を含んでいる可能性を示します。
- 数値のリスト -> ns
- 任意の値のリスト -> xs
- 文字のリストのリスト -> css
関数の構造がまだ身についていない 😵💫
- 型定義
- 関数名 :: 戻り値
- 関数名 :: 引数 -> 戻り値
- 実際の定義
- 関数名 引数 = 処理
3.1.
vが型Tの値であるという意味で「v :: T」という表記を使います。「v::T」は、「vの方はTである」と読みます。
ghci> False :: Bool
False
ghci> not False :: Bool
True
GHCiでは、:typeコマンドを式の前に付けると式の型が表示されます
ghci> :type not
not :: Bool -> Bool
ghci> :type False
False :: Bool
ghci> :type not False
not False :: Bool
さらっとプレリュード関数の定義調べるのに便利?hoogleとかあるっぽいけど。
ghci> :type head
head :: GHC.Stack.Types.HasCallStack => [a] -> a
3.2.
基本型
英名 | 和名 | 説明 |
---|---|---|
Bool | 真理値 | |
Char | 文字 | |
String | 文字列 | |
Int | 固定長整数 | -2^63 ~ 2^63-1 の範囲を超えると予期せぬ結果が生じる |
Integer | 多倍長整数 | |
Float | 単精度浮動小数点数 | |
Double | 倍精度浮動小数点数 |
型クラスと型クラスのインスタンスという概念を理解しないと...(これはAIが生成したので正確性)
3.3.
リスト型
T型の要素を持つリストの型を[T]と書き込ます
ghci> [False,True,False] :: [Bool]
[False,True,False]
ghci> ['a', 'b', 'c', 'd'] :: [Char]
"abcd"
ghci> ["One", "Two", "Three"] :: [String]
["One","Two","Three"]
3.4
タプル型
ghci> [('a', False), ('b', True)] :: [(Char, Bool)]
[('a',False),('b',True)]
3.5.
型T1の引数を型T2の返り値に変換する関数の型を「T1 -> T2」と書きます
not :: Bool -> Bool
even :: Int -> Bool (整数か偶数かを判定するプレリュード関数)
Haskellの慣例に従って、関数定義の前で関数の型を(型注釈を使って)宣言
プログラマーにより指定された型の情報は、型推論を使って自動的に決定された型と照合されます。
関数は、全域関数である必要がないことに注意してください。つまり、引数として与えらえる値によっては、結果が定義されていなくてもかまいません。
headには空リストに対しては定義でされていない話がある。headの定義は、[a] -> a
だからなぁ。
でもこれ保証できるプログラミング言語はなくないか?
3.6.
() 過剰にならない2つの仕組み。
-
型の中の
->
は右結合
Int -> Int -> Int -> Int
(Int -> (Int -> (Int -> Int))) -
空白文字を用いて表す関数適用は、左結合
mult x y z
(((mult x) y) z)
3.7.
length :: [a] -> Int
任意の型aに対して、Intを返却する。1つ以上の型変数を含む型や、そのような型を持つ式は多相的と呼ばれる
[a] -> Int は多相型で、lengthは多相関数です。
zip :: [a] -> [b] -> [(a, b)]
どちらかというと3.6.の話だけど、zipを眺めていて、引数を複数設定したHaskellの関数はすべてカリー化で実現しているのかな。
タプルを渡せば引数みたいなものではあるけど。
multi :: Int -> Int -> Int -> Int
multi x y z = x * y * z
multi2 :: (Int, Int, Int) -> Int
multi2 (x, y, z) = x * y * z
3.8. 多重定義型
あんまピンときていない
型クラス
クラス名 | JP | 型クラスのインスタンスとか説明 |
---|---|---|
Eq | 同等クラス | Bool, Char,String,Integer,Float,Doubleといった基本型 |
Ord | 順序クラス | 値が順序つけられる型の集合。前述のような基本型もすべてOrdクラスのインスタンス |
Show | 表示可能クラス | これも基本型はすべてShowクラスのインスタンス |
Read | 読込可能クラス | 文字列->値。値->文字列のShowと対 |
Num | 数値クラス | |
Intergral | 整数クラス |
数値を書いて型推論でLinterがIntegerとどっちかわからん的なこと言われるのは、数値がIntとIntegerに所属しているから。という理解でいいのかしらね。
- Eq
- ==
- /=
- Ord
- <
- <=
>
>=
- min
- max
- Show
- show :: a -> String
- Read
- read :: String -> a
- Num
+
-
*
- negate 数値符号の反転
- abs 絶対値の返却
- signum 正
このガード付きの等式、ifがネストしなくていいな
signum3 :: Int -> Int
signum3 n
| n < 0 = -1
| n == 0 = 0
| otherwise = 1
=>
はコンテキストで、型クラス制約を貸すときに書くんだね
型インスタンスでint -> int
と書いていたところを、x -> x
とコンテキスト割り当てた引数を使うのが違いかなぁ
-- test1 :: Int -> Int
-- test1 a = a
-- 型引数あり
test1 :: (Integral x) => x -> x
test1 a = a
一旦選択と集中という意味で塩漬けにする。