compiler-construction - Haskell编译时函数计算

标签 compiler-construction haskell static code-generation metaprogramming

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

示例(实际函数比较复杂,没试过编译):

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

了解mymodulus n仅使用 n < 64 调用我想预先计算mymodulus对于 n 0..64 的值在编译时。原因是mymodulus会非常昂贵,并且会被重复使用多次。

最佳答案

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

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

{-# 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 的人应该能够使模式代码更简单。

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

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

关于compiler-construction - Haskell编译时函数计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2475828/

相关文章:

haskell - 如何理解类型 a 和 forall r。 (a -> r) -> r 是同构的

windows - 查看第 3 方 DLL 中的可用消息字符串(来自 mc.exe)

list - 元组列表中的模式匹配和列表理解

c++ - 如何编译 Boost.Process 库?

list - Haskell- 在列表中查找元素并返回其位置

c# - 来自泛型函数的静态方法调用

java - 以这种方式构造对象是否不符合常规? (关于同一个构造函数的几个问题)

java - 静态或静态最终

compiler-construction - 编写编程语言的建议?

c++ - 将正则表达式转换/编译为 C 代码