繁体   English   中英

无法理解非部分应用函数作为参数提供的高阶函数调用的结果

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM