Haskell 实现中的两个功能
关于Haskell 实现中的两个功能,haskell,haskell-prelude,Haskell,Haskell Prelude,关于haskell中^的实现,我不了解一件事: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 < 0 = errorWithoutStackTrace "Negative exponent" | y0 == 0 = 1 | otherwise = f x0 y0 where -- f : x0 ^ y0 = x ^ y f x y | ev
haskell
中^
的实现,我不了解一件事:
(^) :: (Num a, Integral b) => a -> b -> a
x0 ^ y0 | y0 < 0 = errorWithoutStackTrace "Negative exponent"
| y0 == 0 = 1
| otherwise = f x0 y0
where -- f : x0 ^ y0 = x ^ y
f x y | even y = f (x * x) (y `quot` 2)
| y == 1 = x
| otherwise = g (x * x) (y `quot` 2) x -- See Note [Half of y - 1]
-- g : x0 ^ y0 = (x ^ y) * z
g x y z | even y = g (x * x) (y `quot` 2) z
| y == 1 = x * z
| otherwise = g (x * x) (y `quot` 2) (x * z) -- See Note [Half of y - 1]
不,
fxy
不仅仅是gxy1
:gx31
调用g(x*x)1(x*1)
,而是fx3
调用g(x*x)1x
。特别是,前一个参数是x*1
,后一个参数是x
。如果发现这样一个实例会产生语义差异或显著的性能差异,那将是令人惊讶的,但它们至少不是完全相同的东西。您还没有复制出来。如果仔细观察,您会注意到有一条关于内联和专门化的注释——我怀疑这是相关的,尽管您认为这些定义在语义上是等价的,这是正确的。@AJFarmar我读了好几遍,仍然不明白它是如何相关的。@DanielWagner它将违反*
的限制。具体地说,这个@x*fromInteger 1@=@x@和@fromInteger 1*x@=@x@
。正如我所说,它将违反@x*fromInteger 1@=@x@和@fromInteger 1*x@=@x@
@talex-Correct。1.有可能(尽管显然不推荐)编写违反类规则的实例,以及2。在最新的base
文档中,这些法律是全新的,我知道至少有一个遗留实例违反了这些法律。我同意,但我怀疑此代码是因为这个原因而创建的。否则,f
应该具有相同的x*1
以保持一致性。@talex这正是我的观点:代码可能是以这种方式创建的,这样f
就可以避免乘以1——可能是出于性能原因,在构造1
或乘以1
并不便宜的情况下。例如,想象一下非常大的矩阵,它是有意义的。它将节省很少的乘法运算。
(^) :: (Num a, Integral b) => a -> b -> a
x0 ^ y0 | y0 < 0 = errorWithoutStackTrace "Negative exponent"
| y0 == 0 = 1
| otherwise = g x0 y0 1
where
g x y z | even y = g (x * x) (y `quot` 2) z
| y == 1 = x * z
| otherwise = g (x * x) (y `quot` 2) (x * z)