[英]Can't understand the result of the high-order function invocation provided with not partially applied function as an argument
I have a high-order function declaration to apply a function given as an argument twice: 我有一个高阶函数声明来应用两次作为参数给出的函数:
twice :: (a -> a) -> a -> a
twice f x = f (f x)
The confusion comes from this GHCi session: 混淆来自GHCi会议:
*Main> let _4 = twice twice
*Main> let __4 = twice twice (*2)
*Main> let _16 = _4 _4
*Main> let __16 = _4 __4
*Main> _16 (*2) 2
231584178474632390847141970017375815706539969331281128078915168015826259279872
*Main> __16 2
131072
It is kinda clear with __16
, because what's going on is just "multiplying" of this function call, so we'll actually get (2 ^ 16) * 2
after it's invocation. __16
有点清楚,因为正在进行的只是这个函数调用的“倍增”,所以在调用之后我们实际上会得到(2 ^ 16) * 2
。 As far as I can understood it happens because function given as a parameter is already partially applied, so the type of either __4 and __16 is (Num a) => a -> a
. 据我所知,这是因为作为参数给出的函数已经部分应用,所以__4和__16的类型是(Num a) => a -> a
。
But the result of invocation of _16
with given function and integer arguments just leads me into confusion. 但是使用给定的函数和整数参数调用_16
的结果只会让我感到困惑。 I can understand that the type of either _4
and _16
are raw (are equal to twice
function's signature, but are nested under the hood), but it gives me no clue about why the results differ so much. 我可以理解_4
和_16
的类型是原始的(等于twice
函数的签名,但是嵌套在引擎盖下),但它没有让我知道为什么结果差异如此之大。 I just can't get program's semantics after providing a function that is not partially applied as an argument. 在提供一个未部分应用为参数的函数后,我无法获得程序的语义。 Can somebody please explain why is this number just SO GREAT? 有人可以解释为什么这个号码太棒了?
With Church numerals, the application of two numerals ab
is equivalent to the exponential b^a
. 对于教会数字,两个数字ab
的应用等同于指数b^a
。 So, _4 _4
corresponds to 4^4=256
, not 16
. 所以, _4 _4
对应于4^4=256
,而不是16
。
Roughly: _4 f
means f . f . f . f
粗略地说: _4 f
表示f . f . f . f
f . f . f . f
f . f . f . f
, ie "doing f
four times, or "multiplying f
by four". So, _4 _4 f
means "multiplying f
by four, four times", hence 4^4
. f . f . f . f
,即“执行f
四次,或”将f
乘以四“。因此, _4 _4 f
表示”将f
乘以四,四次“,因此为4^4
。
Indeed: 确实:
> 2^256 * 2 :: Integer
231584178474632390847141970017375815706539969331281128078915168015826259279872
Looking at a reducing __16 2
a bit: 看一下减少__16 2
:
__16 2 = _4 __4 2
= (twice twice) (twice twice (*2)) 2
= twice (twice (twice twice (*2)) 2
= twice (twice (twice (twice (*2)) 2
compared to 相比
_16 (*2) 2 = _4 _4 (*2) 2
= (twice twice) (twice twice) (*2) 2
= twice (twice (twice twice)) (*2) 2
Notice with the __16
version, you are just directly doubling the number of times you apply (*2)
with each twice
. 该通知__16
版本,你只是直接加倍你申请的次数(*2)
与各twice
。 If you look carefully, you will see that the _16
version is parenthesized slightly differently. 如果你仔细观察,你会发现_16
版本的括号略有不同。 You are first doubling the doubling operation itself , and then you are applying that to (*2)
and 2
. 您首先将倍增操作本身加倍 ,然后将其应用于(*2)
和2
。
The first few steps of reducing _16 (*2) 2
might look like this, following from above 减少_16 (*2) 2
的前几个步骤可能如下所示,从上面开始
twice (twice (twice twice)) (*2) 2
= twice (twice (\x -> twice (twice x))) (*2) 2
= twice (\z -> (\x -> twice (twice x)) ((\y -> twice (twice y)) z)) (*2) 2
= twice (\z -> (\x -> twice (twice x)) (twice (twice z))) (*2) 2
= twice (\z -> twice (twice (twice (twice z)))) (*2) 2
= (\z -> twice (twice (twice (twice z)))) ((\w -> twice (twice (twice (twice w)))) (*2)) 2
= ((\z -> twice (twice (twice (twice z)))) (twice (twice (twice (twice (*2)))))) 2
= twice (twice (twice (twice (twice (twice (twice (twice (*2)))))))) 2
= ...
The innermost twice (*2)
gives you two (*2)
s. 最里面的twice (*2)
给你两个(*2)
s。 The next twice
doubles that to 4 (*2)
s, the one after that doubles that again to 8 (*2)
s and so on. 接下来的twice
加倍到4 (*2)
s,之后再加倍再加到8 (*2)
s,依此类推。 There are eight twice
s in the above expression, so you end up with 2^8 = 256 (*2)
s, so the result is 2 * (2^(2^8)) = 2 * (2^256) = 231584178474632390847141970017375815706539969331281128078915168015826259279872
. 有八个twice
S IN上述表达式中,所以你最终用2 ^ 8 = 256 (*2)
S,所以结果是2 * (2^(2^8)) = 2 * (2^256) = 231584178474632390847141970017375815706539969331281128078915168015826259279872
。
twice
isn't "twice", it's "squared" : twice
不是“两次”,它是“平方” : (^.) :: (a -> a) -> Int -> (a -> a)
(f^.n) x = foldr ($) x [f | _ <- [1..n]]
((^.m) . (^.n)) f x = ((f^.n)^.m) x
= foldr ($) x [f^.n | _ <- [1..m]]
= (f^.(m * n)) x
= (^.(m * n)) f x
twice = (^.2) -- f^.2 = f . f f squared
_4 = twice twice
_4 f = (^.2) (^.2) f = ((^.2) . (^.2)) f = (f^.2)^.2 = f^.4
_4 = (^.4)
(^.3) (^.3) f = ((^.3) . (^.3) . (^.3)) f =
= ((^.3) . (^.3)) (f^.3)
= (^.3) ((f^.3)^.3)
= ((f^.3)^.3)^.3 = f^.(3*3*3) = f^.(3^3) = f^27
(^.4) (^.3) f = (((f^.3)^.3)^.3)^.3 = f^.(3*3*3*3) = f^.(3^4) = f^81
And in general, 一般来说,
(^.m) (^.n) f = f^.(n^m)
Functional composition is multiplication, and application is (reverse) exponentiation. 功能组合是乘法,应用是(反向)取幂。
Thus we have 因此,我们有
_16 f x = _4 _4 f x = (^.4) (^.4) f x = (f^.(4^4)) x = (f^.256) x
_16 (*2) 2 = ((*2)^.256) 2 = (* (2^256)) 2 = 2^257
*Main> _16 (*2) 2
231584178474632390847141970017375815706539969331281128078915168015826259279872
*Main> 2^257
231584178474632390847141970017375815706539969331281128078915168015826259279872
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.