haskell之乘以零时的惰性求值

langtianya 阅读:157 2024-05-22 17:00:29 评论:0

通过下面的程序,

f 0 0 0 1 = 0 
f 0 0 1 0 = f 0 0 0 1 + 1 
f 0 1 0 0 = f 0 0 1 1 + 1 
f 1 0 0 0 = f 0 1 1 1 + 1 
f a b c d = (p + q + r + s) / (a + b + c + d) 
    where 
    p 
        | a > 0 = a * f (a - 1) (b + 1) (c + 1) (d + 1) 
        | otherwise = 0 
    q 
        | b > 0 = b * f a (b - 1) (c + 1) (d + 1) 
        | otherwise = 0 
    r 
        | c > 0 = c * f a b (c - 1) (d + 1) 
        | otherwise = 0 
    s 
        | d > 0 = d * f a b c (d - 1) 
        | otherwise = 0 
 
main = print (f 1 1 1 1) 

我认为它可以简化为,
f 0 0 0 1 = 0 
f 0 0 1 0 = f 0 0 0 1 + 1 
f 0 1 0 0 = f 0 0 1 1 + 1 
f 1 0 0 0 = f 0 1 1 1 + 1 
f a b c d = (p + q + r + s) / (a + b + c + d) 
    where 
    p = a * f (a - 1) (b + 1) (c + 1) (d + 1) 
    q = b * f a (b - 1) (c + 1) (d + 1) 
    r = c * f a b (c - 1) (d + 1) 
    s = d * f a b c (d - 1) 
 
main = print (f 1 1 1 1) 

因为除了在数学上都是合理的之外,我认为通过懒惰的评估,编译器或解释器应该能够决定将任何东西乘以 0 是不必要的。但是,程序确实进入了无限循环。为什么这样?

请您参考如下方法:

内置乘法对两个参数都是严格的——也就是说,它计算两个参数——不管它们中的一个是否为零,这就是导致程序循环的原因。您可以定义自己的乘法运算符,它可以懒惰地消除一个或另一个参数:

0 .* y = 0 
x .* y = x * y 

或者反过来。定义一个消除两边零的运算符需要更多的时间,但可以使用 unamb 包来完成:
x .* y = unambs [ assuming (x == 0) 0 
                , assuming (y == 0) 0 
                , x * y 
                ] 

不过,据我所知,这还没有足够可靠的实现:-/。


标签:程序员
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号