プログラミングと日々思ったことなど

ブログ名通りです。仕事でプログラミングをはじめました。

Haskell入門【2+練習問題】

すごいHaskellたのしく学ぼう! | Miran Lipovača, 田中 英行, 村主 崇行 |本 | 通販 | Amazon
これ↑の第8章(p159)から。

複数のI/Oアクションをのりづけして1つにする→do構文 p162

ファイルを開いて追加・観覧・削除 p195

p196 練習問題
ファイルとタスクの番号を受け取り、そのタスクをToDoリストの先頭に持ってくるbump関数を実装する
・unlinesは最後の要素を含め全て末尾に改行文字をつける

bump :: [String] -> IO ()
bump [fileName, numberString] = do
    contents <- readFile fileName
    let todoTasks = lines contents
    let numberedTasks = zipWith (\n line -> show n ++ " - " ++ line)
                                    [0..] todoTasks
    let number = read numberString
    let inTodoItems = todoTasks !! number 
    let newTodoItems = unlines $ delete (todoTasks !! number) todoTasks
    let addTodoItems = inTodoItems ++ "\n" ++ newTodoItems
    bracketOnError (openTempFile "." "temp")
        (\(tempName, tempHandle) -> do
            hClose tempHandle
            removeFile tempName)
        (\(tempName, tempHandle) -> do
            hPutStr tempHandle addTodoItems
            hClose tempHandle
            removeFile "todo.txt"
            renameFile tempName "todo.txt")

これで問題通りには動いた

ランダム性 p199
System.Random モジュールというものがある(先にstackでinstallが必要)
ここのコイントスプログラムを写経していて気づいたのですが、ghcコンパイルする時、プログラム内にmainが無いとエラーになる。ghciだとmainがなくても動く。対話型(式を評価してすぐに結果を得る)ってそういうことなんですね。

bytestring p205
リストの未評価の部分→サンク(thunk)
正格bytestringは遅延性が完全に排除されている。
遅延bytestringは 1 バイトずつ行われるのではなく、64K バイトずつ行われる。この塊をチャンク (chunk) という。

逆ポーランド記法(reverse polish notation)、略してRPN p211
例)10 4 3 + 2 * -
スタック:10 4 3
演算子:4+3 = 7
スタック:10 7(4+3) 2
演算子:7 * 2
スタック:10 14
演算子:10 - 14

答え:-4

対数
対数とは?logって何?対数関数について基礎から解説!|高校生向け受験応援メディア「受験のミカタ」

多相性を実装できる p227
これらの型はどのように振舞うか?と考えて、適切な型クラスに関連付ければ良い。
例)Int は様々な「もの」のように振る舞う。同じかどうか判定できるもの、順序がついたもの、列挙できるもの、etc

IOがファンクターの一種 p229

main = do line <- fmap reverse getLine
                  putStrLn $ "You said " ++ line ++ " backwards!"

ファンクターは aを取ってbを返す関数 と、aの入った箱を渡し、bの入った箱にして返す
Maybeという箱に入っている値に関数を適用できるのと同様に、IOという箱の中に入っている値に関数を適用できるが、fmapした結果もIO。

演算子を作用する対象の中間に記述する関数(*とか)→中置関数

全てのファンクターの性質や挙動は、ある一定の法則に従うことになっている。fmap f をファンクターに適用したら、それはファンクターの中身にfを適用すべきで合って、それ以上のことをしてはいけない。
この挙動はファンクター則に記述されている p234

Applicative p240
型クラスApplicativeは、2つの関数pureと<*>を定義している。
Applicativeは箱の中の関数を適用することができる。
箱で考えるFunctor、ApplicativeそしてMonad - Qiita
ordは文字を取って数値を返す p255

Monoid p257
モノイドは、値を二項演算子で結合できるような型を表す。
data→独自の代数データ型を作る
type→既存の型に型シノニム(既存のデータ型に別名をつける)を与える

newtype→既存の型から新たな型を作る
newtypeは高速。コンストラクタを1つしか作れない。
dataはオリジナルな型を無から作り出す。newtypeは既存の型をもとに、はっきり区別される新しい型を作るもの。

    1. や * の関数を3つ以上の値を1つの値にまとめる計算をする時、値の間に関数を挟む順序を変えても結果は変わらない、という性質がある。 p266

(3 * 2) * (8 * 5)
240
3 * (2 * (8 * 5))
240
この性質を結合的(associativity)と呼ぶ。

リストの連結→concat p269

Foldableは畳み込みできるものを表す。 p277
Preludeのfoldrはリストを取って畳み込みを行う関数で、Data.Foldableのfoldrは、畳み込みできる型ならリストに限らず、何でも受け付ける関数
foldMapがあれば、ある型をFoldableにできる(foldMapさえ定義すれば、その型のfoldrやfoldlは自動的に手に入る

モナドは強化されたアプリカティブファンクター p281
関数 >>= はバインド(bind)と呼ばれる
>>=は、モナド値と普通の値を取る関数を引数に取り、その関数をモナド値に適用してモナド値を得る
do式の中でパターンマッチ が失敗した場合、Monad型クラスのfail関数が使われるので、異常終了という形ではなく、そのモナドの文脈に合った形で失敗を処理できる。p300

>>=は文脈付きの値(モナディックな値)を、「通常の値を取って文脈付きの値を返す関数」に食わせる演算。

MonadPlus→モノイドの性質をあわせ持つモナドを表す型クラス p304
guard→リスト内包表記でフィルタを使うことと同値 p306

p312

(.) :: (b -> c) -> (a -> b) -> (a -> c)
f . g = (\x -> f (g x))

gの型がa -> b で、fの型がb ->c ならば、2つの関数を結合し、gの返り値をfの引数に渡すことで、a -> c 型の新しい関数が作れる。

長くなってきたので切ります。