创建一个没有上一个指针的新表达式

时间:2019-02-19 12:09:20

标签: haskell

我正在阅读https://www.packtpub.com/application-development/haskell-high-performance-programming这本书,试图弄清楚这两个功能之间的区别是什么:

此功能确实会记住中间数字:

fib_mem :: Int -> Integer
fib_mem = (map fib [0..] !!)
            where fib 0 = 1
                  fib 1 = 1
                  fib n = fib_mem (n-2) + fib_mem (n-1) 

而不是:

fib_mem_arg :: Int -> Integer
fib_mem_arg x = map fib [0..] !! x
                where fib 0 = 1
                      fib 1 = 1
                      fib n = fib_mem_arg (n-2) + fib_mem_arg (n-1) 

作者尝试解释如下:

  

运行fib_mem_arg时除了很小的参数外,都可以   确认它没有备注。即使我们可以看到那个地图   [0 ..]并不取决于参数编号,可以记住,   不会,因为将参数应用于函数将创建   一个新的表达式,它不能隐式地具有指向表达式的指针   来自以前的功能应用程序

用粗体标记的句子是什么意思?有人可以给我一个简单的例子吗?

为什么fib_memconstant applicative form

1 个答案:

答案 0 :(得分:3)

  

为什么fib_mem恒定的适用形式

不是fib_mem,而是(map fib [0..] !!)。它是CAF,因为它是部分应用的功能(!!)。因此,它会保留内存。

(另请参见:What are super combinators and constant applicative forms?

由于类型是单态的,因此即使在调用fib_mem之间也将其保留在内存中,实际上就像map fib [0..]被“浮动”到顶层一样,就像定义为

fib_mem_m :: Int -> Integer
fib_mem_m = (the_list !!)
            where fib 0 = 1
                  fib 1 = 1
                  fib n = (the_list !! (n-2)) + (the_list !! (n-1))
the_list = map fib [0..]

如果类型是多态的,则不可能浮动到顶层,但在每次调用fib_mem的过程中仍会保留,就像定义为

fib_mem_p :: Num a => Int -> a
fib_mem_p = (the_list !!)
            where fib 0 = 1
                  fib 1 = 1
                  fib n = (the_list !! (n-2)) + (the_list !! (n-1))
                  the_list = map fib [0..]

要查看差异,请在GHCi属性下对fib_mem_m 10000进行两次评估。第二次尝试将花费0秒。但是fib_mem_p 10000每次调用将花费相同的时间。它仍然会像第一个一样快,因此仍然存在备忘录,只是在两次调用之间没有保留。

采用这种定义方式,fib_mem_arg中的完整应用程序也会被记住-就像上面的那样,不在两次fib_mem_arg的调用之间,而仅在每次调用期间。 / p>

fib_mem_arg :: Num a => Int -> Integer  -- or polymorphic, makes no difference
fib_mem_arg x = the_list !! x
            where fib 0 = 1
                  fib 1 = 1
                  fib n = (the_list !! (n-2)) + (the_list !! (n-1))
                  the_list = map fib [0..]