为了文化和智力的丰富,我决定学习一些Haskell。我一直在阅读Hughes' "Why Functional Programming Matters",并试图将其代码转换为真正的Haskell。我已经在下面附上了我的一些尝试(对于论文的数字部分; alpha-beta算法更有趣,但我还必须从头开始编写游戏评估器!)。
此时,它更多地是Haskell语法中的练习而不是其他任何内容。我已经完成了简单的事情,例如将repeat
翻译成本地Haskell iterate
,将一些使用了大量括号的函数转换为函数组合(使它们在过程中更加无点)等等
但我的代码肯定有用,我想知道它是否足够“Haskell-ish”。那里的专家可以给我一些提示吗?
-- 4.1 Newton-Raphson square roots
next n x = (x + n/x)/2.0
-- -- this is "iterate::(a->a)->a->[a]"
-- repeat f a = a : iterate f (f a)
within eps (a:b:rest) =
if abs(a-b) <= eps
then b
else within eps (b:rest)
sqroot a0 eps n = within eps (iterate (next n) a0)
relative eps (a:b:rest) =
if abs(a-b) <= eps*abs(b)
then b
else relative eps (b:rest)
relativesqrt a0 eps n = relative eps (iterate (next n) a0)
-- 4.2 numerical differentiation
easydiff f x h = (f (x+h) - f x) / h
differentiate h0 f x = map (easydiff f x) (iterate (/2) h0)
-- diff1a h0 eps f x = within eps (differentiate h0 f x)
diff1 h0 eps f = within eps . differentiate h0 f
elimerror n (a:b:rest) = (b*(2**n)-a)/(2**n-1) : elimerror n (b:rest)
-- need fromIntegral to make a non-integer out of the Int which comes out of round
order (a:b:c:rest) = fromIntegral (round (logBase 2 ((a-c)/(b-c)-1)))
improve s = elimerror (order s) s
--diff2a h0 eps f x = within eps (improve (differentiate h0 f x))
diff2 h0 eps f = within eps . improve . differentiate h0 f
--super s = map second (iterate improve s) -- how can we make this point-free?
super :: (RealFrac t, Floating t) => [t] -> [t]
-- w/o this it wants to be [double]->[double]
super = map second . iterate improve
-- second (a:b:rest) = b
second = head . tail
diff3 h0 eps f = within eps . super . differentiate h0 f
-- 4.3 integration
easyintegrate f a b = (f a + f b)*(b-a)/2
-- addpair becomes (uncurry (+))
integrate f a b = integ f a b (f a) (f b)
integ f a b fa fb =
(fa+fb)*(b-a)/2 : map (uncurry (+)) (zip (integ f a m fa fm) (integ f m b fm fb))
where m = (a+b)/2
fm = f m
-- test: following should be about pi
approxpi eps = within eps (improve (integrate (\x -> 4/(1+x*x)) 0 1))
superpi eps = within eps (super (integrate (\x -> 4/(1+x*x)) 0 1))
-- is there any way to keep track of the number of iterations? state monad, but seems like a lot of work...\
答案 0 :(得分:10)
4.1 Newton-Raphson平方根
这两行
sqroot a0 eps n = within eps (iterate (next n) a0)
relativesqrt a0 eps n = relative eps (iterate (next n) a0)
几乎相同,所以你可以进一步抽象:
sqroot method a0 eps n = method eps (iterate (next n) a0)
relativesqrt = sqroot relative
withinsqrt = sqroot within
4.2数值分化
我认为将h0
作为differentiate
函数的参数并不重要,因为它只是0
限制序列的起点。 (对于Newton-Rhapson案例中的a0
,情况也是如此,起点可能很重要。)
我认为抽象这个限制接近零的比率同样合适:
differentiate rate f x = map (easydiff f x) (iterate rate 1)
当然可以做到这两点:
differentiate rate h0 f x = map (easydiff f x) (iterate rate h0)
无论如何,这是一个非常随意的决定。
4.2整合
您可以使用
zipWith (+) (integ f a m fa fm) (integ f m b fm fb)
而不是
map (uncurry (+)) (zip (integ f a m fa fm) (integ f m b fm fb))
我认为更具可读性。
答案 1 :(得分:4)
对于within
和relative
,我会使用保护符号:
within eps (a:b:rest)
| abs(a-b)<=eps = b
| otherwise = within eps (b:rest)
对于second
,您可以撰写!! 1
。特别是最后一个是个人偏好,我想。
您还应该提供类型签名。
修改:如果您进行模糊处理,请尝试:
within :: (Ord a, Num a) => a -> [a] -> a
within eps l@(_:xs) = snd. head . filter ((<= eps) . fst) $ zip zs xs
where
zs = zipWith (\ a b -> abs (a-b)) l xs
(键入已检查,未经过测试 - 我从不知道我是否正确使用过滤器或是否必须取消;)
答案 2 :(得分:2)
答案 3 :(得分:0)
所以,这是一个直接的翻译(即,尽量保持代码看起来尽可能相似)或嵌入式(即尽可能多地对代码进行惯用调整,而不使示例更难理解当然)一个?
假设这个“项目”仍在继续......