プログラミングHaskellを読む (2)
第2章 はじめの一歩
標準ライブラリ:Prelude
リスト系の関数のオレオレ実装
頭の体操がてら、自力で実装してみたので置いておきます。
-- head myhead :: [a] -> a myhead [] = error "empty list" myhead (a : b) = a -- tail mytail :: [a] -> [a] mytail [] = error "empty list" mytail (a : b) = b -- last (計算量多い) mylast :: [a] -> a mylast [] = error "empty list" mylast (a : []) = a mylast (a : b) = mylast b -- init (計算量多い) myinit :: [a] -> [a] myinit [] = error "empty list" myinit (_ : []) = [] myinit (a : b) = a : myinit b -- reverse (計算量ヤバい) myreverse :: [a] -> [a] myreverse [] = [] myreverse a = mylast a : myreverse (myinit a) -- take (負値を指定すると、リストがそのまま出てしまう) mytake :: Int -> [a] -> [a] mytake _ [] = [] mytake 0 _ = [] mytake a (hd : tl) = hd : mytake (a-1) tl -- length (アキュームレータ 使わなくても 出来るのね (字余り)) mylength :: [a] -> Int mylength [] = 0 mylength (_ : tl) = 1 + mylength tl -- null mynull :: [a] -> Bool mynull [] = True mynull _ = False -- mydrop mydrop :: Int -> [a] -> [a] mydrop 0 b = b mydrop _ [] = [] mydrop a (hd : tl) = mydrop (a-1) tl -- sum mysum :: Num a => [a] -> a mysum [] = 0 mysum (hd : tl) = hd + sum tl -- product myproduct :: Num a => [a] -> a myproduct [] = 1 myproduct (hd : tl) = hd * myproduct tl -- elem (Trueの時点で止まらないのが無駄) myelem :: Eq a => a -> [a] -> Bool myelem _ [] = False myelem a (hd : tl) = (a == hd) || myelem a tl -- combine (組み込みの++) mycombine :: [a] -> [a] -> [a] mycombine [] b = b mycombine (hd : tl) b = hd : mycombine tl b -- index (組み込みの!!) myindex :: [a] -> Int -> a myindex [] _ = error "invalid index" myindex (hd : tl) 0 = hd myindex (hd : tl) a = myindex tl (a-1) -- max mymax :: Ord a => a -> a -> a mymax a b = if a > b then a else b -- min mymin :: Ord a => a -> a -> a mymin a b = if a < b then a else b -- maximum (必殺ワザfoldr) mymaximum :: Ord a => [a] -> a mymaximum [] = error "empty list" mymaximum (hd : tl) = foldr mymax hd tl -- minimum myminimum :: Ord a => [a] -> a myminimum [] = error "empty list" myminimum (hd : tl) = foldr mymin hd tl
GHCiの特殊コマンド
Hugsも同じ感じみたいです。
コマンド | 動作 |
---|---|
:load, :l | 指定したファイルのロード |
:reload, :r | 現在のファイルをリロード |
:cd, :c | 作業ディレクトリの変更 |
:type expr, :t | exprの型を見る |
:quit, :q | GHCi終了 |
:help, :h, :? | ヘルプ |
:!コマンド | シェルのコマンドを実行 |
他にも色々あります。
- :helpを見る or 日本語訳(?)
プログラムの基本
練習問題
1. 括弧を付ける
数学と同じ。
2 ^ 3 * 4 = ((2 ^ 3) * 4) 2 * 3 + 4 * 5 = ((2 * 3) + (4 * 5)) 2 + 3 * 4 ^ 5 = (2 + (3 * (4 ^ 5)))
2. 例題を実行
しました。
3. エラーを修正
N = a `div` length xs where a = 10 xs = [1,2,3,4,5]
「関数の先頭は小文字」と「where内のインデント」かな。
n = a `div` length xs where a = 10 xs = [1,2,3,4,5]
4. 空でないリストを受け取るlastを定義。他の定義も。
-- 上記の方法(パターンマッチはまだなので不正解?) mylast (a : []) = a mylast (a : b) = mylast b -- indexを利用 mylast2 a = a !! (length a - 1) -- dropを利用 mylast3 a = drop (length a - 1) a !! 0 -- reverse&head mylast4 a = head (reverse a)
headをtake 1にするとか、他にもバリエーションは色々作れそうです。
5. 空でないリストから末尾を削るinitを定義。
-- 上記の方法(パターンマッチはまだなので不正解?) myinit (_ : []) = [] myinit (a : b) = a : myinit b -- takeを利用 myinit2 a = take (length a - 1) a -- reverse&tail&reverse myinit3 a = reverse (tail (reverse a)) -- 合成関数化(おまけ) myinit4 a = (reverse . tail . reverse) a