Haskell 高阶函数和结合性

Tua*_*uan 3 haskell functional-programming ghc higher-order-functions

我正在学习 FP 并且在玩过 GHCi 后有一些困惑。

假设我有两个简单的功能:

twice :: (a -> a) -> (a -> a)
twice f a = f (f a) -- Equation 1

double :: Int -> Int
double = \x -> x * 2
Run Code Online (Sandbox Code Playgroud)

分解评估twice twice twice double 3(注意 3x twice+1x double),我会:

{-
   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
-}
Run Code Online (Sandbox Code Playgroud)
  • 这样对吗?
  • 根据这个,如果我的定义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
-}
Run Code Online (Sandbox Code Playgroud)

对?

  • 然而,最奇怪的是 GHC REPL 给了我196608(2^16*3)的答案:
> twice twice twice double 3
196608
Run Code Online (Sandbox Code Playgroud)

这让我很困惑。我会在哪里犯错?谢谢。

com*_*orm 5

正如评论所说,函数应用程序是左关联的,所以:

twice twice twice double 3 == (((twice twice) twice) double) 3

which is not the same as:     twice (twice twice double 3)
Run Code Online (Sandbox Code Playgroud)

根据您的评论中的要求:请注意,twice返回与其参数相同的类型。所以,类型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
Run Code Online (Sandbox Code Playgroud)

double^16 3 == 2^16 * 3当你发现。

  • 这个答案准确地解释了这 3 个“两次”如何通过不同的分组扩展为 4 个“两次”,以及如何扩展为调用“double”16 次。 (2认同)