'where`块中的全局CAF - Haskell

时间:2016-09-20 00:31:07

标签: haskell caching functional-programming lazy-evaluation

我将实现一个函数,该函数接收Integer并输出一个懒惰的,无限的互质Integer列表。

coprime 2 = [1,3..]
coprime 3 = [1,2,4,5,7,8,....]

我希望这些列表会被多次访问,所以我希望它们的值存储为CAF。 (如果我错误地使用该术语,请原谅我)好吧,这很好,因为这将由编译器自动完成(我认为)。但是保证具有相同输出的不同输入呢?例如:

coprime 2 = [1,3..]
coprime 4 = [1,3..]

如何确保这两种模式调用相同的CAF,以便不必重新计算结果?

我的第一个想法是尝试实现coprime,以便coprime 2coprime 4实际上使用相同的参数调用本地函数。一个最小的例子:

coprime n
  | n == 4    = realcoprime 2
  | otherwise = realcoprime n
    where
      realcoprime n = .....

但是,对coprime的所有来电是否都与{{​​1}}相关联的CAF值相同?如果是这样,它们不会过早收集垃圾,因为它们不在全球范围内吗?

2 个答案:

答案 0 :(得分:2)

一般来说,函数无法记忆(at least in general they can't)。如果你希望Haskell记忆函数,这意味着它必须在运行时保持已经看到的输入字典及其相应的输出,但是函数调用涉及在这个字典中查找!

但是,有些图书馆提供此功能:例如memoizedata-memocombinators。例如,使用后者,我可以用

记住你的例子
import com.android.build.gradle.internal.pipeline.TransformTask

def deleteDuplicateJniFiles() {
    def files = fileTree("${buildDir}/intermediates/exploded-aar/com.facebook.react/react-native/0.31.0/jni/") {
        include "**/libgnustl_shared.so"
    }
    files.each { it.delete() }
}

tasks.withType(TransformTask) { pkgTask ->
    pkgTask.doFirst { deleteDuplicateJniFiles() }
}

然后关于你的第二个问题,现在它 适合制作第二个函数,最终调用第一个函数。

答案 1 :(得分:0)

我撤回了我接受的'来自@ Alec的回答是因为我发现上面显示的方法只会记住coprime函数的输入。正如问题中所述,我需要在记忆之前对输入参数进行一些简化,否则我将为多个参数存储完全相同的数据。所以这是我第一次尝试解决这个问题:

cprimes :: [Integer] -> [Integer]
cprimes relnums = cprime' (mySimplify relnums)
  where
    mySimplify relnums = ....
    cprimes' = (Memo.list Memo.integral) cprimes''
    cprimes'' relnums = ....

但是,这里的记忆似乎至少不在全局背景中进行。使用相同的参数调用cprimes时,将重新计算结果。我怀疑结果是在对cprimes的一次调用中被记忆,然后进行了垃圾收集,因为cprimes'块中定义了where

这是我第二次尝试解决方法:

cprimes :: [Integer] -> [Integer]
cprimes relnums       = cprimetables (mySimplify relnums)
cprimetables = (Memo.list Memo.integral) cprimes'
  where
    mySimplify relnums = ...
    cprimes'   relnums = ...

现在这可以按预期工作了。但是,它会将cprimestable函数暴露给导入此模块的任何内容,这不是我想要的。它是一个内部实现,并不打算被外界称呼。这就是为什么我首先尝试将它放在where块中。

所以最后,我结合使用了第二种方法,明确地说明了我模块的导出。它是这样的:

module PrimeStuff ( cprimes,
                    ...
                  )
  where

 ...

cprimes :: [Integer] -> [Integer]
cprimes relnums       = cprimetables (mySimplify relnums)
cprimetables = (Memo.list Memo.integral) cprimes'
  where
    mySimplify relnums = ...
    cprimes'   relnums = ...

这样,似乎cprimestable中的memoized结果不会过早收集垃圾。它还隐藏了这个实现,因此导入该模块的任何东西都只知道函数cprimes,该函数将整数列表作为参数。

来自stackoverflow.com的有用资源,了解如何执行此操作,this用于了解有关记忆的信息,this用于了解有关实施隐藏的信息。