Haskell 高阶函数和结合性
Haskell Higher Order Functions and Associativity
我正在学习 FP,在玩过 GHCi 后有一些困惑。
假设我有 2 个简单的函数:
twice :: (a -> a) -> (a -> a)
twice f a = f (f a) -- Equation 1
double :: Int -> Int
double = \x -> x * 2
分解评价twice twice twice double 3
(注意是3xtwice
+1xdouble
),我会:
{-
twice twice twice double 3
== (twice twice twice double) 3
== (twice twice (twice double)) 3
== (twice (twice (double double 3)))
== (twice ((double double) (double double 3)))
== (((double double) (double double)) ((double double) (double double 3)))
== 768
-}
- 这是正确的吗?
- 根据this,如果我对
twice
的定义改为twice f a = f f a -- Equation 2
,我应该分解求值,左结合性,如:
{-
twice (twice twice double) 3
== (twice twice double) (twice twice double) 3
== ((twice double)(twice double)) ((twice double)(twice double)) 3
== ((double double)(double double)) ((double double)(double double)) 3
== (double (double (double (double (double (double (double (double 3 ) ) ) ) ) ) )
== 768
-}
对吗?
- 然而,最奇怪的是 GHC REPL 给了我
196608
(2^16*3) 的答案:
> twice twice twice double 3
196608
这让我很困惑。我会在哪里犯错?
谢谢。
正如评论所说,函数应用是左关联的,所以:
twice twice twice double 3 == (((twice twice) twice) double) 3
which is not the same as: twice (twice twice double 3)
根据您评论中的要求:请注意 twice
returns 与其参数的类型相同。所以,twice twice
的类型就是 ((a -> a) -> (a -> a))
现在,让我们展开整个表达式:
(((twice twice) twice) double) 3 ==> ((twice (twice twice)) double) 3
==> (((twice twice) ((twice twice) double)) 3
==> (twice (twice ((twice twice) double))) 3
==> (twice (twice (twice (twice double)))) 3
twice double ==> double^2
twice (twice double) ==> double^4
twice (twice (twice double)) ==> double^8
twice (twice (twice (twice double))) == double^16
和 double^16 3 == 2^16 * 3
如您所见。
假设n
是一个自然数,g n
定义如下,非正式地:
g n = \f x -> f (f (f (.... (f x)))) -- n times f on x
在你的情况下,twice f x = g 2 f x
。
那么,可以证明
g n (g m) f x = g (m^n) f x
的确如此,
g n (g m) f x =
(g m (g m (g m (g m .... (g m f))))) x = -- n times (g m) on f
所以它采用“m
次重复 f
”函数,然后重复 m
次以形成另一个函数,然后重复 m
-再次,...每一步将f
的应用次数乘以m
,所以我们得到m^n
.
回到你的案例
twice twice twice double 3 =
g 2 (g 2) (g 2) double 3 =
g (2^2) (g 2) double 3 =
g (2^(2^2)) double 3 =
double (double (double .... 3)) -- 2^(2^2) = 2^4 = 16 times
所以,我们得到 3
双 16
倍,得到 3 * 2^16 = 196608
.
我正在学习 FP,在玩过 GHCi 后有一些困惑。
假设我有 2 个简单的函数:
twice :: (a -> a) -> (a -> a)
twice f a = f (f a) -- Equation 1
double :: Int -> Int
double = \x -> x * 2
分解评价twice twice twice double 3
(注意是3xtwice
+1xdouble
),我会:
{-
twice twice twice double 3
== (twice twice twice double) 3
== (twice twice (twice double)) 3
== (twice (twice (double double 3)))
== (twice ((double double) (double double 3)))
== (((double double) (double double)) ((double double) (double double 3)))
== 768
-}
- 这是正确的吗?
- 根据this,如果我对
twice
的定义改为twice f a = f f a -- Equation 2
,我应该分解求值,左结合性,如:
{-
twice (twice twice double) 3
== (twice twice double) (twice twice double) 3
== ((twice double)(twice double)) ((twice double)(twice double)) 3
== ((double double)(double double)) ((double double)(double double)) 3
== (double (double (double (double (double (double (double (double 3 ) ) ) ) ) ) )
== 768
-}
对吗?
- 然而,最奇怪的是 GHC REPL 给了我
196608
(2^16*3) 的答案:
> twice twice twice double 3
196608
这让我很困惑。我会在哪里犯错? 谢谢。
正如评论所说,函数应用是左关联的,所以:
twice twice twice double 3 == (((twice twice) twice) double) 3
which is not the same as: twice (twice twice double 3)
根据您评论中的要求:请注意 twice
returns 与其参数的类型相同。所以,twice twice
的类型就是 ((a -> a) -> (a -> a))
现在,让我们展开整个表达式:
(((twice twice) twice) double) 3 ==> ((twice (twice twice)) double) 3
==> (((twice twice) ((twice twice) double)) 3
==> (twice (twice ((twice twice) double))) 3
==> (twice (twice (twice (twice double)))) 3
twice double ==> double^2
twice (twice double) ==> double^4
twice (twice (twice double)) ==> double^8
twice (twice (twice (twice double))) == double^16
和 double^16 3 == 2^16 * 3
如您所见。
假设n
是一个自然数,g n
定义如下,非正式地:
g n = \f x -> f (f (f (.... (f x)))) -- n times f on x
在你的情况下,twice f x = g 2 f x
。
那么,可以证明
g n (g m) f x = g (m^n) f x
的确如此,
g n (g m) f x =
(g m (g m (g m (g m .... (g m f))))) x = -- n times (g m) on f
所以它采用“m
次重复 f
”函数,然后重复 m
次以形成另一个函数,然后重复 m
-再次,...每一步将f
的应用次数乘以m
,所以我们得到m^n
.
回到你的案例
twice twice twice double 3 =
g 2 (g 2) (g 2) double 3 =
g (2^2) (g 2) double 3 =
g (2^(2^2)) double 3 =
double (double (double .... 3)) -- 2^(2^2) = 2^4 = 16 times
所以,我们得到 3
双 16
倍,得到 3 * 2^16 = 196608
.