繁体   English   中英

Haskell编译时函数计算

[英]Haskell compile time function calculation

我想在编译时预先计算函数的值。

示例(实际功能更复杂,没有尝试编译):

base = 10
mymodulus n = n `mod` base -- or substitute with a function that takes
                            -- too much to compute at runtime
printmodules 0 = [mymodulus 0]
printmodules z = (mymodulus z):(printmodules (z-1))

main = printmodules 64

知道只有n < 64才能调用mymodulus n ,并且我想在编译时预先计算mymodulusn值为0..64 原因是mymodulus非常昂贵并且会多次重复使用。

你应该使用Template Haskell 使用TH,您可以在编译时以编程方式生成代码。 在这种情况下,你的mymodulus实际上是一个“模板”。

例如,我们可以按如下方式重写您的程序,以静态计算您的函数。 首先,主代码像往常一样,但它不是调用你的模数函数,而是调用一个函数,它的主体是一个将在编译时生成的拼接:

{-# LANGUAGE TemplateHaskell #-}

import Table

mymodulus n = $(genmodulus 64)

main = mapM_ (print . mymodulus) [0..64]

以及静态生成表的代码:

{-# LANGUAGE TemplateHaskell #-}

module Table where

import Language.Haskell.TH
import Language.Haskell.TH.Syntax

genmodulus :: Int -> Q Exp
genmodulus n = return $ CaseE (VarE (mkName "n"))
                              [ Match (LitP (IntegerL i))
                                      (NormalB (LitE (IntegerL (i `mod` base))))
                                      []
                              | i <- [0..fromIntegral n] ]
    where
        base = 10

这描述了case表达式的抽象语法,它将在编译时生成。 我们只是生成一个大开关:

    genmodulus 64
  ======>
    case n of {
      0 -> 0
      1 -> 1
      2 -> 2
      3 -> 3
      4 -> 4
      ...
      64 -> 4 }

您可以看到使用-ddump-splices生成的代码。 我以直接的方式编写了模板代码。 更熟悉TH的人应该能够使模式代码更简单。

另一种选择是离线生成值表,并只导入该数据结构。

您也可以说为什么要这样做。 我假设你有一个非常复杂的表驱动函数?

我不知道有任何方法可以将它预编译到表查找中(尽管你可能对TH有一些好运)​​。 另一种方法是在运行时使用类似的方法生成查找表

mymodulus' x = lt ! x
    where lt = array (0, 64) [(i, mymodulus i) | i <- [0..64]]

我记得有一些特殊的行为附加到顶级定义。 如果你试试简单的例子:

primes = 2 : 3 : filter isPrime [5, 7 .. 1000000]
isPrime x = walk (tail primes) where
    walk (y:ys) | (y*y > x) = True
                | (x `mod` y) /= 0 = walk ys
    walk _ = False
main = do
    print $ last primes
    print . last $ init primes

你会看到(最后一个素数)的第一次调用将启动素数的计算,第二行将重用这些计算。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM