rincon matematico matematicas funciones exponencial escribir ecuaciones definir convertir como haskell shake-build-system

haskell - matematico - Cómo escribir reglas de construcción de punto fijo en Shake, por ejemplo, látex



exponencial en latex (2)

Ampliando la de , a continuación hay un código de ejemplo de foo_transitive . Dicho esto, para este caso en particular, solo usaría latexmk que hace lo correcto ™.

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

Usando la biblioteca de compilación Shake Haskell, ¿cómo puedo escribir una regla usando un programa que necesita alcanzar un punto fijo? Imagina que tengo un programa foo que toma una input archivo y produce un archivo de salida, que debería haber aplicado foo repetidamente hasta que el archivo de salida no cambie. ¿Cómo puedo escribir eso en Shake?

El ejemplo típico de este patrón es LaTeX.


En primer lugar, tenga en cuenta que llamar a Latex repetidamente no siempre produce un punto fijo, así que asegúrese de tener un límite en las iteraciones. Además, algunas distribuciones (MikTex) proporcionan versiones de Latex que se ejecutan automáticamente tantas veces como sea necesario, por lo que si las usa, el problema desaparece.

Escribe tu propio comando foo_transitive

La forma más fácil de resolver el problema, suponiendo que cada ejecución de foo tenga las mismas dependencias, es resolver el problema fuera del sistema de compilación. Simplemente escriba un comando foo_transitive , ya sea como un script de shell o como una función de Haskell, que cuando se suministra un archivo de entrada produce un archivo de salida ejecutándose repetidamente y verificando si ha alcanzado un punto fijo. El sistema de compilación ahora puede usar foo_transitive y no hay problemas con las dependencias.

Codificarlo en el sistema de compilación.

Necesita escribir dos reglas, una que da un paso y otra que determina qué paso es el correcto de usar:

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

La primera regla genera tempfile.2 desde tempfile.1 y así sucesivamente, por lo que podemos need ["tempfile.100"] para obtener la iteración número 100. Si las dependencias cambian en cada paso, podemos ver el resultado anterior para calcular las nuevas dependencias.

La segunda regla recorre todos los pares de valores en la secuencia y se detiene cuando son iguales. Si está implementando esto en un sistema de compilación de producción, es posible que desee evitar llamar a readFile'' en cada elemento dos veces (una vez como i-1 y una vez como i ).