简体   繁体   English

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

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

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