HaskellでSICP3章のストリームを書いてみたらすごかった

言語仕様を見て、これならSICP3章だろうと思ってやってみたら、ほとんどが2行(うち型宣言が1行)で書けてわろた。あとで解説とか書くかもしれないし書かないかもしれない。

module Main where

addStream :: Num a => [a] -> [a] -> [a]
addStream = zipWith (+)

scaleStream :: Num a => a -> [a] -> [a]
scaleStream factor = map (*factor)

mulStream :: Num a => [a] -> [a] -> [a]
mulStream = zipWith (*)

integersStartingFrom :: Num a => a -> [a]
integersStartingFrom n = n : integersStartingFrom (n + 1)

ones :: Num a => [a]
ones = repeat 1

integers :: Num a => [a]
integers = integersStartingFrom 1

partialSums :: Num a => [a] -> [a]
partialSums (x:xs) = x : addStream (repeat x) (partialSums xs)

integrateSeries :: Fractional a => [a] -> [a]
integrateSeries xs = mulStream xs (map recip integers)

expSeries = 1.0 : integrateSeries expSeries
cosSeries = 1.0 : integrateSeries (map negate sinSeries)
sinSeries = 0.0 : integrateSeries cosSeries

mulSeries :: Num a => [a] -> [a] -> [a]
mulSeries (a:as) (b:bs) = a*b :
	addStream (scaleStream a bs) (mulSeries as (b:bs))

sqrtStream :: Fractional a => a -> [a]
sqrtStream x = guesses
	where
		guesses = 1.0 : map improve guesses
		improve guess = average guess (x/guess)
		average a b = (a+b)/2

eularTransform :: Fractional a => [a] -> [a]
eularTransform (x0:x1:x2:xs) = x' : eularTransform (x1:x2:xs)
	where
		x' = x2 - (square (x2 - x1)) / (x0 - 2*x1 + x2)
		square x = x * x

piSummands :: Fractional a => a -> [a]
piSummands n = 1.0/n : map negate (piSummands (n+2))

piStream :: Fractional a => [a]
piStream = scaleStream 4 (partialSums (piSummands 1))

makeTableau :: ([a]->[a]) -> [a] -> [[a]]
makeTableau t xs = xs : makeTableau t (t xs)

acceleratedSequence :: ([a]->[a]) -> [a] -> [a]
acceleratedSequence t xs = map head (makeTableau t xs)

ln2Summands :: Fractional a => a -> [a]
ln2Summands n = 1/n : map negate (ln2Summands (n+1))

ln2Stream :: Fractional a => [a]
ln2Stream = partialSums (ln2Summands 1)

geometricSeris :: Num a => a -> a -> [a]
geometricSeris a r = map ((a*).(r^)) (integersStartingFrom 0)

polySeries :: Num a => a -> [a]
polySeries = geometricSeris 1

applySeries :: Num a => [a] -> a -> [a]
applySeries series x = (partialSums (mulStream series (polySeries x)))

integral :: Num a => [a] -> a -> a -> [a]
integral integrand initial dt = int where
	int = initial : addStream (scaleStream dt integrand) int

solve' :: Num a => (a->a) -> a -> a -> [a]
solve' f y0 dt = y where
	y = integral dy y0 dt
	dy = map f y

solve :: Fractional a => (a->a) -> a -> Int -> a
solve f y0 n = (solve' f y0 dt) !! n
	where dt = 1 / (fromIntegral n)

solve2nd :: Num a => a -> a -> a -> a -> a -> [a]
solve2nd a b dt y0 dy0 = y
	where
		y   = integral dy y0 dt
		dy  = integral ddy dy0 dt
		ddy = addStream (scaleStream a dy) (scaleStream b y)

solve2nd_gen :: Num a => (a -> a -> a) -> a -> a -> a -> [a]
solve2nd_gen f dt y0 dy0 = y
	where
		y   = integral dy y0 dt
		dy  = integral ddy dy0 dt
		ddy = zipWith f dy y