Haskell 如何在Shake中编写定点构建规则,例如Latex
使用Shake Haskell构建库,如何使用需要到达固定点的程序编写规则?假设我有一个程序Haskell 如何在Shake中编写定点构建规则,例如Latex,haskell,shake-build-system,Haskell,Shake Build System,使用Shake Haskell构建库,如何使用需要到达固定点的程序编写规则?假设我有一个程序foo,它接受一个文件输入,并生成一个输出文件,该文件应该反复应用foo,直到输出文件不变。我怎么能用Shake写呢 此模式的典型示例是LaTeX。首先,请注意重复调用LaTeX并不总是产生一个固定点,因此请确保在迭代中有一个边界。此外,一些发行版(MikTex)提供了Latex版本,可以自动运行任意次数,因此如果您使用这些版本,问题就会消失 编写自己的foo_transitivecommand 假设每次
foo
,它接受一个文件输入
,并生成一个输出文件,该文件应该反复应用foo
,直到输出文件不变。我怎么能用Shake写呢
此模式的典型示例是LaTeX。首先,请注意重复调用LaTeX并不总是产生一个固定点,因此请确保在迭代中有一个边界。此外,一些发行版(MikTex)提供了Latex版本,可以自动运行任意次数,因此如果您使用这些版本,问题就会消失 编写自己的
foo_transitive
command
假设每次运行foo
都有相同的依赖项,解决问题的最简单方法是在构建系统之外解决问题。只需编写一个foo_transitive
命令,作为shell脚本或Haskell函数,当提供输入文件时,通过反复运行并检查其是否已达到固定点来生成输出文件。构建系统现在可以使用foo_transitive
,并且不存在依赖性问题
在构建系统中对其进行编码
你需要写两条规则,一条是一个步骤,另一条是找出哪一个步骤是正确的:
let step i = "tempfile" <.> show i
"tempfile.*" *> \out -> do
let i = read $ takeExtension out :: Int
if i == 0 then
copyFile "input" out
else
let prev = step (i-1)
need [prev]
-- perhaps require addition dependencies, depending on prev
system' "foo" [prev,out]
"output" *> \out -> do
let f i = do
old <- readFile' $ step (i-1)
new <- readFile' $ step i
if old == new || i > 100 then copyFile (step i) out else f (i+1)
f 1
让步骤i=“tempfile”显示i
“tempfile.*”>\out->do
让我=读取$takeExtension::Int
如果i==0,那么
复制文件“输入”输出
其他的
设上一步=步骤(i-1)
需要[上]
--可能需要添加依赖项,具体取决于prev
系统“foo”[prev,out]
“输出”*>\out->do
让f i=do
旧的100然后复制文件(步骤i)出其他f(i+1)
F1
第一条规则从tempfile.1
生成tempfile.2
,依此类推,因此我们可以需要[“tempfile.100”]
来获得第100次迭代。如果依赖项在每个步骤中发生变化,我们可以查看前面的结果来计算新的依赖项
第二条规则循环检查序列中的每一对值,当它们相等时停止。如果您在生产构建系统中实现此功能,您可能希望避免对每个元素调用两次readFile'
(一次为i-1
,一次为i
)。展开的答案,下面是foo\u transitive
的示例代码。话虽如此,对于这种特殊情况,我只会使用latexmk
,它做正确的事情™.
import Control.Monad.Fix (fix, mfix)
import Control.Monad.IO.Class (MonadIO(liftIO))
import Text.Printf (printf)
type SHA = Int
data TeXCompilationStage
= Init
| BibTeX
| Recompile SHA
deriving (Show, Eq)
data TeXResult
= Stable SHA
| Unstable
deriving (Show, Eq)
f retry x budgetLaTeXCalls
| budgetLaTeXCalls <= 0
= do
liftIO $ putStrLn "Budget for LaTeX depleted; result didn't converge"
return Unstable
| otherwise
= case x of
Init -> do
liftIO $ do
putStrLn "Init"
putStrLn " # latex"
retry BibTeX (budgetLaTeXCalls-1)
BibTeX -> do
liftIO $ do
putStrLn "BibTeX"
putStrLn " # bibtex"
retry (Recompile 0) budgetLaTeXCalls
Recompile previousSHA -> do
let budgetLaTeXCalls' = budgetLaTeXCalls - 1
calculcatedSHA = 3
liftIO $ do
printf "Recompile (budget: %d)\n" budgetLaTeXCalls
printf " Prevous SHA:%d\n Current SHA:%d\n" previousSHA calculcatedSHA
if calculcatedSHA == previousSHA
then do
liftIO $ putStrLn " Stabilized"
return $ Stable calculcatedSHA
else do
liftIO $ putStrLn " Unstable"
retry (Recompile (previousSHA+1)) (budgetLaTeXCalls-1)
latex :: Int -> IO TeXResult
latex = fix f Init
import Control.Monad.Fix(Fix,mfix)
进口管制.Monad.IO.Class(MonadIO(liftIO))
导入Text.Printf(Printf)
类型SHA=Int
数据编译阶段
=Init
|BibTeX
|重新编译SHA
推导(显示,等式)
数据传输结果
=稳定SHA
|不稳定
推导(显示,等式)
f重试x次呼叫
|我打电话给你
liftIO$do
putStrLn“初始化”
putStrLn“#乳胶”
重试BibTeX(budgetLaTeXCalls-1)
BibTeX->do
liftIO$do
putStrLn“BibTeX”
putStrLn“#bibtex”
重试(重新编译0)budgetLaTeXCalls
重新编译PreviousHA->do
让budgetLaTeXCalls'=budgetLaTeXCalls-1
CalcultatedSha=3
liftIO$do
printf“重新编译(预算:%d)\n”预算调用
printf“Previous SHA:%d\n当前SHA:%d\n”previousSHA CalcultatedSHA
如果CalcultatedSha==previousSHA
那就做吧
liftIO$putStrLn“稳定”
返回$Stable calcultatedsa
否则会
liftIO$putStrLn“不稳定”
重试(重新编译(previousSHA+1))(budgetLaTeXCalls-1)
latex::Int->IO TeXResult
latex=fix f Init