[英]Adding a function in LLVM (haskell bindings) when the number of parameters is not known at compile time
[英]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
,並且我想在編譯時預先計算mymodulus
的n
值為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.