fugafuga.write

日々のログ

すごいH本 part85

do 記法 do 記法は IOモナドだけでなく、他のモナドにも使える *Main Lib> Just 3 >>= (\x -> Just (show x ++ "!")) Just "3!" 入れ子にする *Main Lib> Just 3 >>= (\x -> Just "!" >>= (\y -> Just (show x ++ y))) Just "3!" let式と似ている *Main Lib>…

すごいH本 part84

ピエールを落とす バナナを仕掛けてピエールを問答無用で落とす関数を作る banana :: Pole -> Maybe Pole banana _ = Nothing これを一連の関数の中に混ぜて使う *Main> return (0, 0) >>= landLeft 1 >>= banana >>= landRight 1 Nothing 落ちた。 入力に関…

すごいH本 part83

ピエールの人生とは せっかくの休暇にバランス棒やってんのに鳥に邪魔されるピエール まず、鳥とポールを定義 その後に、ポールの右と左に鳥が止まる関数を定義 type Birds = Int type Pole = (Birds, Birds) landLeft :: Birds -> Pole -> Pole landLeft n …

すごいH本 part82

モナド モナドは強化されたアプリカティブファンクターである。 モナドはある願いを叶えるための、アプリカティブ値の自然な拡張である。 願いとは、 普通の値 a を取って文脈付きの値を返す関数に、文脈付きの値 m a を渡したい というもの。 言い換えると…

すごいH本 part81

モノイドで畳み込む いろいろなデータ構造の上に畳み込みを定義したい時にモノイドは便利。 *Main Lib F> F.foldr (*) 1 [1,2,3] 6 *Main Lib F> F.foldl (+) 2 (Just 9) 11 *Main Lib F> F.foldr (||) False (Just True) True もう少し複雑なデータ構造を畳…

すごいH本 part80

リストはモノイド インスタンス宣言 instance Monoid [a] where mempty = [] mappend = (++) リストは中身の型がなんであっても常に Monoid のインスタンスにできる。 *Main> [1,2,3] `mappend` [4,5,6] [1,2,3,4,5,6] *Main> ("one" `mappend` "two") `mapp…

すごいH本 part79

Monoid 大集合 以下のような共通の性質をもつ関数が存在する。 関数は引数を2つとる 2つの引数および返り値の型はすべて等しい 2引数関数を施して相手を変えないような特殊な値が存在する ++ なら空リスト * なら 1 例: x * 1, "hoho" ++ [] 例 *Main> (3 * …

すごいH本 part78

newtype と 遅延評価 undefined という値がある。これは、ぶっ壊れた計算を表す。 この値を評価すると Haskell はすごく怒る。 *Main> undefined *** Exception: Prelude.undefined CallStack (from HasCallStack): error, called at libraries/base/GHC/Err…

すごいH本 part77

モノイド Monoid は、値を2項演算子で結合できるような型を表現する。 newtype キーワード newtype キーワードを使うと、既存の型から新たな型を作ることができる。 リストをアプリカティブファンクターにする方法は複数ある。 左辺のリストの関数と右辺のリ…

すごいH本 part76

アプリカティブの便利な関数 Control.ApplicativeにliftA2という関数がある。 liftA2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c liftA2 f a b = f <$> a <*> b 1つの関数を2つのアプリカティブ値に適用する関数。 これを、 liftA2 :: (Appl…

すごいH本 part75

Zipリスト ZipList という型があり、これは Applicative のインスタンスである。 instance Applicative ZipList where pure x = ZipList (repeat x) ZipList fs <*> ZipList xs = ZipList (zipWith (\f x -> f x) fs xs) <*> は1つ目の関数を1つ目の値に、2…

すごいH本 part74

IOはアプリカティブファンクター IO は Applicative instance Applicative IO where pure = return a <*> b = do f <- a x <- b return (f x) return は何もしない I/Oアクションを返す。 IOに関する <*> 演算子は、 2つのI/O アクションを1つに糊付けするに…

すごいH本 part73

アプリカティブファンクターを使う 2引数関数でファンクター値を写すとどうなるか *Main> :t fmap (*) (Just 3) fmap (*) (Just 3) :: Num a => Maybe (a -> a) *Main> :t fmap compare (Just 'a') fmap compare (Just 'a') :: Maybe (Char -> Ordering) *Ma…

すごいH本 part72

ファンクター則 Functor のインスタンスはファンクター則の2つの性質を満たす必要がある。 自前のファンクターを作る時はこの性質を満たす必要がある。 第1法則 idでファンクター値を写した場合、ファンクター値が変化してはいけない idは引数をそのまま返す…

すごいH本 part71

アプリカティブファンクター ファンクターとは関数で写せるもののこと。リスト、Maybe、木など。 *Main Lib> :i Functor class Functor (f :: * -> *) where fmap :: (a -> b) -> f a -> f b (<$) :: a -> f b -> f a {-# MINIMAL fmap #-} -- Defined in ‘G…

すごいH本 part70

ヒースロー空港からロンドンへ こんな感じの図がある A - 50 - (A1) - 5 - (A2) - 40 - (A3) - 10 - (A4) | | | | 30 20 25 0 | | | | B - 10 - (B1) - 90 - (B2) - 2 - (B3) - 8 - (B4) AかBから出発して、(A4)か(B4)にたどり着く最短経路を求めるという問…

すごいH本 part69

関数型問題解決法 関数型のテクニックを使ってエレガントに 逆ポーランド記法電卓 数式を書く方法として、逆ポーランド記法(reverse polish notation) 略してRPNがある。 RPNでは、演算子は数に挟まれず、数の後ろに書く。 4 + 3 が 4 3 + になる。 4と3を足…

すごいH本 part68

bytestring を使ったファイルコピー ファイルコピー関数を実装する import System.Environment import System.Directory import System.IO import Control.Exception import qualified Data.ByteString.Lazy as B main = do (fileName1:fileName2:_) <- getA…

すごいH本 part67

bytestring まず、遅延評価について wikipedia より 評価しなければならない値が存在するとき、 実際の計算を値が必要になるまで行わないことをいう。 評価法が指示されているが実際の計算が行われていない中間状態の時 それをプロミス(英: promise)や、 …

すごいH本 part66

ランダム性とI/O getStdGen という I/O アクションは、何らかの初期データを使って システムのグローバル乱数ジェネレータを初期化する。 import System.Random main = do gen <- getStdGen putStrLn $ take 20 (randomRs ('a', 'z') gen) 実行 > stack ghc …

すごいH本 part65

もっともっとランダム関数 コインを投げる話の続き。 もっとたくさんのランダム値が欲しい場合どうするか randoms を使う *Main System.Random> :t randoms randoms :: (RandomGen g, Random a) => g -> [a] 乱数ジェネレータを受け取って無限長のランダム値…

すごいH本 part64

ランダム性 ランダム値を扱う。 Haskell は参照透明性を持つので関数が同じ引数で2回呼ばれた場合、 必ず同じ値を返すようになっていなければならない。 その中でランダム値をどのように作るのかを見る。 System.Random モジュールに random という関数があ…

すごいH本 part63

コマンドライン引数 コマンドライン引数をとれるようにする。 import System.Environment import Data.List main = do args <- getArgs progName <- getProgName putStrLn "The arguments are:" mapM putStrLn args putStrLn "The program name is:" putStrL…

すごいH本 part62

Todoリスト Todoリストをテキストファイルに追加するプログラムを書く import System.IO main = do todoItem <- getLine appendFile "todo.txt" (todoItem ++ "\n") ビルドして実行 > stack ghc -- --make appendtodo.hs [1 of 1] Compiling Main ( appendto…

すごいH本 part61

ファイルの読み書き ファイルから読んで端末に表示する baabaa.txt Baa, baa, black sheep, Have you any wool? Yes, sir, yes, syr, Three bags full; 実装 import System.IO main = do handle <- openFile "baabaa.txt" ReadMode contents <- hGetContents…

すごいH本 part60

ファイルとストリーム ファイルの内容を読み込んで大文字にして返すプログラム haiku.txt I'm a cat nyaaan nyaaan nyaaaan nyaaan nyaaaan nyaaaaaaaaaan 実装 import Control.Monad import Data.Char main = forever $ do l <- getLine putStrLn $ map toU…

すごいH本 part59

I/O 関数 putStr main = do putStr "Hey, " putStr "I'm " putStr "Andy!" 実行結果 *Main> main Hey, I'm Andy!*Main> 文字列を引数として受け取る。 受け取った文字列を端末に表示するI/Oアクションを返す。 改行しない。 putChar main = do putChar 't' p…

すごいH本 part58

I/O アクションの中で let 使う let はI/Oアクションの中で普通の値に名前を与えたいときに使う。 import Data.Char main = do putStrLn "Hello, what's your first name?" firstName <- getLine putStrLn "What's your last name?" lastName <- getLine let…

すごいH本 part57

入出力 前回はただのポエムになってしまったので真面目にやっていく。 出力するのに使った関数 putStrLn *Main Lib> :t putStrLn putStrLn :: String -> IO () *Main Lib> :t putStrLn "hello, world" putStrLn "hello, world" :: IO () putStrLn の型は、文…

すごいH本 part56

こんにちは、世界。 〜時を超えて〜 世界との邂逅 HelloWorld.hs main = putStrLn "hello, world" コンパイルして実行ファイルを生成する が、stack を使っているのでH本の通りにやってもできない。 以下のようにするとビルドできた。 > stack ghc -- --make…