Concurrent Clean1部2章
Cleanの2項演算子には優先順位と、結合順序(左(infixl)、右(infixr)、未(infix))があるのか。
(%) infixl 7 :: Int Int -> Int (%) n m | n < m = n | otherwise = (%) (n - m) m
infixlは 5 % 3 % 2が(5 % 3) % 2になるもので、infixr なら5 % (2 % 3)、infixならエラーになるようだ。
カリー化した関数とパラメータを持つ関数は厳密には型が違うが、実行では大半が同じように使えるようだ。
succ1 :: (Int -> Int) succ1 = (+) 1 succ2 :: Int -> Int succ2 n = (+) 1 n
は違う型?
map :: (a->b) [a] -> [b] map f [] = [] map f [x:xs] = [f x : map f xs]
[a:b]でconsになるのね。
iterate :: (t->t) t -> [t] iterate f x = [x: iterate f (f x)]
ができるのは遅延実行だからですね。
無名関数は\がλになるらしい。
map (\ x -> x * 2) [1,2,3,4]
関数と違って| hoge = なパターンは使えない。let inは使える
関数合成はoらしい
(o) infixr 9 :: (b->c) (a->b) -> (a->c) (o) g f = \x -> g (f x)
二項演算子なので、λを使って関数を返すように定義しているのがミソ。
map (not o isEven) [1,2,3,4]
曜日計算
:: Day :== Int :: Month :== Int :: Year :== Int day :: Day Month Year -> String day d m y = weekday (daynumber d m y) weekday :: Day -> String weekday 0 = "Sunday" weekday 1 = "Monday" weekday 2 = "Tuesday" weekday 3 = "Wednesday" weekday 4 = "Thursday" weekday 5 = "Friday" weekday 6 = "Saturday"
最初の「:: NewType :== OldType」は同型の型かな。1.6.2にあった。型シノニム。新たな型ではなく、別名扱いみたい。
day :: Day Month Year -> String day d m y = case daynumber d m y of 0 -> "Sunday" 1 -> "Monday" 2 -> "Tuesday" 3 -> "Wednesday" 4 -> "Thursday" 5 -> "Friday" 6 -> "Saturday"
case式は case n of p -> expでパターンは関数でのパターン| p = expのと同じっぽい。
day :: Day Month Year -> String day d m y = ["Sunday","Monday","Tuesday","Wednesday" ,"Thursday","Friday","Saturday"] !! daynumber d m y
3番目の例ではリストからインデックスで引いている。!!がインデックスを引く2項演算子。
daynumber :: Day Month Year -> Int daynumber d m y = ( (y-1)*365 // この年の前の全ての年の日 + (y-1)/4 // 通常のうるう年補正 - (y-1)/100 // 世紀のうるう年補正 + (y-1)/400 // 4世紀のうるう年補正 + sum (take (m-1) (months y)) // この年の月の持つ日 + d ) rem 7
remは整数での余りを出す2項演算子。
months :: Year -> [Int] months y = [31, if (leap y) 29 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
if a b cですね。
day :: Day Month Year -> String day d m y | y>1752 = weekday (daynumber d m y) | otherwise = abort ("day: undefined for year "+++toString y)
abortでエラーを出すらしい。
Start "e = " +++ toString (exp 1.0) +++ "\npi = " +++ toString (2.0*asin 1.0)
toStringで文字列に変換。+++で文字列連結か。Startの右に = は必要ですね。
flexDiff :: Real (Real->Real) Real -> Real flexDiff h f x = (f (x+h) - f x) / h
微分関数の定義。hは微分の変化量。fは関数。xは微分を求める位置。
root :: Real -> Real root x = until goodEnough improve 1.0 where improve y = 0.5*(y+x/y) goodEnough y = y*y ~=~ x (~=~) infix 5 :: Real real -> Bool (~=~) a b = a-b < h && b-a < h where h = 0.000001
untilは第一引数の関数がtrueになるまで第二引数の関数に再帰的に適用する関数。
until :: (a -> Bool) (a -> a) a -> a until p f x | p x = x | otherwise = until p f (f x)
1.
module tut2_1 import StdEnv odd = even o ((+) 1) Start = odd 11
2.
module tut2_2 import StdEnv Start = takeLast ((<>) 0.0) (iterate (\x -> x/10.0) 1.0) 1.0 takeLast :: (a -> Bool) [a] a -> a takeLast f [x:xs] last | f x = takeLast f xs x | otherwise = last
3.
daynumToBirthday :: Year Month Day Month Day daynumToBirthday ny nm nd bm bd | nm < bm = (daynumber bd bm ny) - (daynumber nd nm ny) | nm == bm && nd < bd = bd - nd | otherwise = (daynumber bd bm (ny + 1)) - (daynumber nd nm ny)
4.
mapfun :: [a->b] a -> [b] mapfun [] _ = [] mapfun [f:flist] n = [f n : mapfun flist n]