将"为什么功能编程很重要"翻译成Haskell

And*_*ffe 14 haskell functional-programming

为了文化和智力的丰富,我决定学习一些Haskell.我一直在阅读休斯的"为什么功能编程很重要",并试图将其代码转换为真正的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...\
Run Code Online (Sandbox Code Playgroud)

Jon*_*nas 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)
Run Code Online (Sandbox Code Playgroud)

几乎相同,所以你可以进一步抽象:

sqroot method a0 eps n = method eps (iterate (next n) a0)
relativesqrt = sqroot relative
withinsqrt   = sqroot within
Run Code Online (Sandbox Code Playgroud)

4.2数值区分

我没有看到h0作为differentiate函数的参数的重点,因为它只是0限制序列的起点.(a0在Newton-Rhapson案例中,情况也是如此,起点可能很重要).

我认为抽象这个限制接近零的比率同样合适:

differentiate rate f x = map (easydiff f x) (iterate rate 1)
Run Code Online (Sandbox Code Playgroud)

当然可以做到这两点:

differentiate rate h0 f x = map (easydiff f x) (iterate rate h0)
Run Code Online (Sandbox Code Playgroud)

无论如何,这是一个非常随意的决定.

4.2整合

您可以使用

zipWith (+) (integ f a m fa fm) (integ f m b fm fb)
Run Code Online (Sandbox Code Playgroud)

代替

map (uncurry (+)) (zip (integ f a m fa fm) (integ f m b fm fb))
Run Code Online (Sandbox Code Playgroud)

我觉得它更具可读性.


Shi*_*iSi 4

对于within并且relative我会使用保护符号:

within eps (a:b:rest)
  | abs(a-b)<=eps = b
  | otherwise = within eps (b:rest)
Run Code Online (Sandbox Code Playgroud)

对于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
Run Code Online (Sandbox Code Playgroud)

(类型检查,未测试 - 我永远不知道我的过滤器是否正确或是否必须被否定;)