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]