多次调用 applyTwice 时无法理解结果
Can't understand result when calling applyTwice multiple times
有很多问题基于 applyTwice
,但 none 与我的问题相关。我知道 applyTwice
函数定义如下:
applyTwice :: (a -> a) -> a -> a
applyTwice f a = f (f a)
应用函数两次。所以如果我有一个增量函数:
increment x = x + 1
并做
applyTwice increment 0
我得到 2。但我不明白这些结果:
applyTwice applyTwice applyTwice increment 0 -- gives 16
applyTwice applyTwice applyTwice applyTwice increment 0 -- gives 65536
applyTwice applyTwice applyTwice applyTwice applyTwice increment 0 -- stack overflow
我也知道
twice = applyTwice applyTwice increment
applyTwice twice 0 -- gives 8
我简直无法理解这些结果,如果有人能解释一下,我会很高兴。如果这是基础知识,我深表歉意,因为我只是在学习 Haskell。
让我们使用非正式符号
iter n f = f . f . f . .... -- n times
你的 applyTwice
就是 iter 2
.
根据定义,我们立即得到:
(iter n . iter m) f
= iter n (iter m f)
= (f.f. ...) . ... . (f.f. ...) -- n times (m times f)
= iter (n*m) f
因此,eta 承包,
iter n . iter m = iter (n*m) -- [law 1]
我们还有
iter n (iter m)
= -- definition
iter m . iter m . .... . iter m -- n times
= -- law 1
iter (m*m* ... *m) -- n times
= -- power
iter (m^n) -- [law 2]
然后我们写 t
for applyTwice
:
t = iter 2
t t
= -- previous equation
iter 2 (iter 2)
= -- law 2
iter (2^2)
t t t
= -- left associativity of application
(t t) t
= -- previous equation
iter (2^2) (iter 2)
= -- law 2
iter (2^(2^2))
t t t t
= -- left associativity of application
(t t t) t
= -- previous equation
iter (2^(2^2)) (iter 2)
= -- law 2
iter (2^(2^(2^2)))
等等。
以不可见类型参数的形式隐藏在幕后的复杂性很多。如果我们用 -XTypeApplications
写出这些参数会发生什么?我已经缩短了一些名字。
以下twice
实例化在twice @Int
,类型为二阶
one :: Int
one = twice (+ 1) 0
^^^^^
|
twice @Int
:: (Int -> Int)
-> (Int -> Int)
当您将 twice
(order-3)应用于 twice
(order-2)时,类型签名变得更加复杂。
two :: Int
two = twice twice (+ 1) 0
^^^^^ ^^^^^
| |
| twice @Int
| :: (Int -> Int)
| -> (Int -> Int)
|
twice @(Int->Int)
:: ((Int->Int) -> (Int->Int))
-> ((Int->Int) -> (Int->Int))
以此类推,当你有 twice twice twice
时,它们分别是 order-4、order-3 和 order-2:
three :: Int
three = twice twice twice (+ 1) 0
^^^^^ ^^^^^ ^^^^^
| | |
| | twice @Int
| | :: (Int -> Int)
| | -> (Int -> Int)
| |
| twice @(Int->Int)
| :: ((Int->Int) -> (Int->Int))
| -> ((Int->Int) -> (Int->Int))
|
twice @((Int->Int)->(Int->Int))
:: (((Int->Int)->(Int->Int)) -> ((Int->Int)->(Int->Int)))
-> (((Int->Int)->(Int->Int)) -> ((Int->Int)->(Int->Int)))
你给出的最后一个例子变成了这个怪物,分别是 order-6、order-5、order-4、order-3、order-2...
{-# Language TypeApplications #-}
five :: Int
five = twice @((((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int)))->(((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int))))
(twice @(((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int))))
(twice @((Int->Int)->(Int->Int)))
(twice @(Int->Int))
(twice @Int)
(+ 1) 0
所以这是第一个的类型twice
!!
twice @((((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int)))->(((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int))))
:: (((((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> ((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> (((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> ((Int -> Int) -> Int -> Int)
-> (Int -> Int)
-> Int
-> Int)
-> ((((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> ((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> (((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> ((Int -> Int) -> Int -> Int)
-> (Int -> Int)
-> Int
-> Int
有很多问题基于 applyTwice
,但 none 与我的问题相关。我知道 applyTwice
函数定义如下:
applyTwice :: (a -> a) -> a -> a
applyTwice f a = f (f a)
应用函数两次。所以如果我有一个增量函数:
increment x = x + 1
并做
applyTwice increment 0
我得到 2。但我不明白这些结果:
applyTwice applyTwice applyTwice increment 0 -- gives 16
applyTwice applyTwice applyTwice applyTwice increment 0 -- gives 65536
applyTwice applyTwice applyTwice applyTwice applyTwice increment 0 -- stack overflow
我也知道
twice = applyTwice applyTwice increment
applyTwice twice 0 -- gives 8
我简直无法理解这些结果,如果有人能解释一下,我会很高兴。如果这是基础知识,我深表歉意,因为我只是在学习 Haskell。
让我们使用非正式符号
iter n f = f . f . f . .... -- n times
你的 applyTwice
就是 iter 2
.
根据定义,我们立即得到:
(iter n . iter m) f
= iter n (iter m f)
= (f.f. ...) . ... . (f.f. ...) -- n times (m times f)
= iter (n*m) f
因此,eta 承包,
iter n . iter m = iter (n*m) -- [law 1]
我们还有
iter n (iter m)
= -- definition
iter m . iter m . .... . iter m -- n times
= -- law 1
iter (m*m* ... *m) -- n times
= -- power
iter (m^n) -- [law 2]
然后我们写 t
for applyTwice
:
t = iter 2
t t
= -- previous equation
iter 2 (iter 2)
= -- law 2
iter (2^2)
t t t
= -- left associativity of application
(t t) t
= -- previous equation
iter (2^2) (iter 2)
= -- law 2
iter (2^(2^2))
t t t t
= -- left associativity of application
(t t t) t
= -- previous equation
iter (2^(2^2)) (iter 2)
= -- law 2
iter (2^(2^(2^2)))
等等。
以不可见类型参数的形式隐藏在幕后的复杂性很多。如果我们用 -XTypeApplications
写出这些参数会发生什么?我已经缩短了一些名字。
以下twice
实例化在twice @Int
,类型为二阶
one :: Int
one = twice (+ 1) 0
^^^^^
|
twice @Int
:: (Int -> Int)
-> (Int -> Int)
当您将 twice
(order-3)应用于 twice
(order-2)时,类型签名变得更加复杂。
two :: Int
two = twice twice (+ 1) 0
^^^^^ ^^^^^
| |
| twice @Int
| :: (Int -> Int)
| -> (Int -> Int)
|
twice @(Int->Int)
:: ((Int->Int) -> (Int->Int))
-> ((Int->Int) -> (Int->Int))
以此类推,当你有 twice twice twice
时,它们分别是 order-4、order-3 和 order-2:
three :: Int
three = twice twice twice (+ 1) 0
^^^^^ ^^^^^ ^^^^^
| | |
| | twice @Int
| | :: (Int -> Int)
| | -> (Int -> Int)
| |
| twice @(Int->Int)
| :: ((Int->Int) -> (Int->Int))
| -> ((Int->Int) -> (Int->Int))
|
twice @((Int->Int)->(Int->Int))
:: (((Int->Int)->(Int->Int)) -> ((Int->Int)->(Int->Int)))
-> (((Int->Int)->(Int->Int)) -> ((Int->Int)->(Int->Int)))
你给出的最后一个例子变成了这个怪物,分别是 order-6、order-5、order-4、order-3、order-2...
{-# Language TypeApplications #-}
five :: Int
five = twice @((((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int)))->(((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int))))
(twice @(((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int))))
(twice @((Int->Int)->(Int->Int)))
(twice @(Int->Int))
(twice @Int)
(+ 1) 0
所以这是第一个的类型twice
!!
twice @((((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int)))->(((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int))))
:: (((((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> ((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> (((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> ((Int -> Int) -> Int -> Int)
-> (Int -> Int)
-> Int
-> Int)
-> ((((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> ((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> (((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> ((Int -> Int) -> Int -> Int)
-> (Int -> Int)
-> Int
-> Int