17

Shake Haskell ビルド ライブラリを使用して、固定点に到達する必要があるプログラムを使用してルールを作成するにはどうすればよいですか? fooファイルinputを取得して出力ファイルを生成するプログラムがありfoo、出力ファイルが変更されなくなるまで繰り返し適用する必要があると想像してください。Shakeでそれをどのように書くことができますか?

このパターンの典型的な例が LaTeX です。

4

2 に答える 2

13

まず、Latex を繰り返し呼び出しても常に固定点が生成されるとは限らないことに注意してください。そのため、反復に制限があることを確認してください。また、一部のディストリビューション (MikTex) では、必要な回数だけ自動的に実行される Latex バージョンが提供されているため、代わりにそれらを使用すると問題は解決します。

foo_transitive独自のコマンドを書く

問題を解決する最も簡単な方法は、 の各実行に同じ依存関係があると仮定してfoo、ビルド システムの外部で問題を解決することです。foo_transitiveコマンドをシェル スクリプトまたは Haskell 関数として記述するだけで、入力ファイルが提供されると、繰り返し実行して固定点に到達したかどうかを確認することで、出力ファイルが生成されます。ビルド システムが使用できるようfoo_transitiveになり、依存関係に関する問題はありません。

ビルドシステムでエンコードする

1 つのステップを作成するルールと、どのステップを使用するのが正しいかを判断するルールの 2 つのルールを作成する必要があります。

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

最初のルールはtempfile.2fromtempfile.1などを生成need ["tempfile.100"]するため、100 回目の繰り返しを取得できます。各ステップで依存関係が変化する場合は、前の結果を見て新しい依存関係を計算できます。

2 番目のルールは、シーケンス内の値の各ペアをチェックし、それらが等しいときに停止するようにループします。これをプロダクション ビルド システムで実装する場合はreadFile'、各要素を 2 回 ( asi-1とas で 1 回ずつi) 呼び出すことを避けたい場合があります。

于 2013-01-31T09:18:47.620 に答える
2

@Neil Mitchellの回答を拡張すると、以下はfoo_transitive. そうは言っても、この特定のケースでは、latexmkwhich Does The Right Thing™ を使用します。

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
于 2016-10-07T22:30:59.867 に答える