patternMinor
Compile .tex and remove .div file from Haskell
Viewed 0 times
filecompiledivremovehaskelltexandfrom
Problem
As a practice for interacting with system commands, I wrote a Haskell program that compiles a .tex file specified by the argument.
When one execute this program:
This is what I wrote:
I appreciate any kind of feedback. I'm especially concerned about:
Side note: I don't use pdflatex because it is not as good as uplatex at Japanese typesetting and I haven't been catching up with the latest LaTeX families.
When one execute this program:
- If no argument is specified, print
"Specify a file!"then exit
- If the specified file does not exist, print
"File not found."then exit
- If the specified file does not have the extension
.tex, then print"Not a .tex file!"then exit
- If a
.texfile is specified (report.tex), execute the following commands
$ uplatex report.tex -o report.dvi
$ dvipdfmx report.dvi
$ rm report.dvi
- The program does not have to handle errors in the execution of tex-related commands.
This is what I wrote:
import qualified Control.Shell as S
import Data.Char (toLower)
import Data.List (dropWhileEnd)
import qualified System.Environment as E
main = do
args putStrLn "Specify a file!"
(filename:_) -> handler filename
isTeXFile :: S.FilePath -> Bool
isTeXFile = ( == ".tex") . map toLower . S.takeExtension
handler :: S.FilePath -> IO ()
handler f = do
(Right isfile) putStrLn l
(Right _) -> return ()
else
putStrLn "Not a .tex file!"
compile :: S.FilePath -> IO (Either String ())
compile f = S.shell $ do
S.run_ "uplatex" [f, "-o", dvifile] ""
S.run_ "dvipdfmx" [dvifile] ""
S.rm dvifile
where
basename = dropWhileEnd (/= '.') f
dvifile = basename ++ "dvi"I appreciate any kind of feedback. I'm especially concerned about:
- The body of
handlerseems unnecessarily complicated. How can I clean it up?
- Am I using
Control.Shellin the right way? Is there other function I should use instead? Maybe I should consider usingSystem.Process?
Side note: I don't use pdflatex because it is not as good as uplatex at Japanese typesetting and I haven't been catching up with the latest LaTeX families.
Solution
When you are using packages, please make sure to say which ones. I guessed
Given that you are quickly dismissing the cases you are not interested in, I inspected
Using the
Finally, I don't think it's good practice to test a file's type based on its extension. Given that you are already running external tools, you may want to use ̀
The rest is pretty much perfect as far as I'm concerned (modulo some cosmetic preferences which I won't bore you with).
shellmate btw. As for the code, it's quite readable except for the handler definition which I've rewritten as follows:handler :: S.FilePath -> IO ()
handler f = do
(Right isfile) >= either putStrLn returnGiven that you are quickly dismissing the cases you are not interested in, I inspected
not $ isTeXFile f and systematically written the if (...) then clauses on the same line. This avoids the crazy right-leaning nesting.Using the
either combinator of type (a -> c) -> (b -> c) -> Either a b -> c lets you rewrite the final case expression in a more concise fashion.Finally, I don't think it's good practice to test a file's type based on its extension. Given that you are already running external tools, you may want to use ̀
file for that job. It would look something like this:isTeXFile :: S.FilePath -> IO Bool
isTeXFile fp = do
(Right ans) IO ()
handler f = do
(Right isfile) >= either putStrLn returnThe rest is pretty much perfect as far as I'm concerned (modulo some cosmetic preferences which I won't bore you with).
Code Snippets
handler :: S.FilePath -> IO ()
handler f = do
(Right isfile) <- S.shell $ S.isFile f
if not isfile then putStrLn "File not found."
else if not $ isTeXFile f then putStrLn "Not a .tex file!"
else compile f >>= either putStrLn returnisTeXFile :: S.FilePath -> IO Bool
isTeXFile fp = do
(Right ans) <- S.shell $ S.run "file" [fp] ""
return $ " LaTeX " `isInfixOf` ans
handler :: S.FilePath -> IO ()
handler f = do
(Right isfile) <- S.shell $ S.isFile f
if not isfile then putStrLn "File not found."
else do
testTexFile <- isTeXFile f
if not $ testTexFile then putStrLn "Not a .tex file!"
else compile f >>= either putStrLn returnContext
StackExchange Code Review Q#74920, answer score: 3
Revisions (0)
No revisions yet.