[英]Can't understand the result of the high-order function invocation provided with not partially applied function as an argument
我有一个高阶函数声明来应用两次作为参数给出的函数:
twice :: (a -> a) -> a -> a
twice f x = f (f x)
混淆来自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
__16
有点清楚,因为正在进行的只是这个函数调用的“倍增”,所以在调用之后我们实际上会得到(2 ^ 16) * 2
。 据我所知,这是因为作为参数给出的函数已经部分应用,所以__4和__16的类型是(Num a) => a -> a
。
但是使用给定的函数和整数参数调用_16
的结果只会让我感到困惑。 我可以理解_4
和_16
的类型是原始的(等于twice
函数的签名,但是嵌套在引擎盖下),但它没有让我知道为什么结果差异如此之大。 在提供一个未部分应用为参数的函数后,我无法获得程序的语义。 有人可以解释为什么这个号码太棒了?
对于教会数字,两个数字ab
的应用等同于指数b^a
。 所以, _4 _4
对应于4^4=256
,而不是16
。
粗略地说: _4 f
表示f . f . f . f
f . f . f . f
f . f . f . f
,即“执行f
四次,或”将f
乘以四“。因此, _4 _4 f
表示”将f
乘以四,四次“,因此为4^4
。
确实:
> 2^256 * 2 :: Integer
231584178474632390847141970017375815706539969331281128078915168015826259279872
看一下减少__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
相比
_16 (*2) 2 = _4 _4 (*2) 2
= (twice twice) (twice twice) (*2) 2
= twice (twice (twice twice)) (*2) 2
该通知__16
版本,你只是直接加倍你申请的次数(*2)
与各twice
。 如果你仔细观察,你会发现_16
版本的括号略有不同。 您首先将倍增操作本身加倍 ,然后将其应用于(*2)
和2
。
减少_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
= ...
最里面的twice (*2)
给你两个(*2)
s。 接下来的twice
加倍到4 (*2)
s,之后再加倍再加到8 (*2)
s,依此类推。 有八个twice
S IN上述表达式中,所以你最终用2 ^ 8 = 256 (*2)
S,所以结果是2 * (2^(2^8)) = 2 * (2^256) = 231584178474632390847141970017375815706539969331281128078915168015826259279872
。
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
一般来说,
(^.m) (^.n) f = f^.(n^m)
功能组合是乘法,应用是(反向)取幂。
因此,我们有
_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.