Read file line by line and execute those lines in Haskell - haskell

i want to read from a file (contains haskell commands per line). I want to read line by line and execute those and display the result
my following code is not working... print is not processing the command, it is just displaying it:
import System.IO
import Control.Monad
main = do
fileContents <- readFile "Instructions.txt"
mapM_ f (lines fileContents)
f line = do
putStrLn ("Processing Instruction:" ++ line)
print line
instruction file contains haskell commands.

You're probably looking for unsafeEval
http://hackage.haskell.org/packages/archive/plugins/1.5.1.3/doc/html/System-Eval-Haskell.html
But this is almost certainly definitely always a very bad idea for any real program, and not only goes against every guideline and rule of programming but also the fundamental principles of haskell programming.
If you just want something to read a file line by line and output the result, ghc already does this for you pretty well.
ghc -e "command" will execute the command and output to stdout, so it would be pretty easy to write a simple bash script to do this for you:
#!/bin/bash
# linebyline.sh
while read line; do
ghc -e "$line"
done
which you can run by:
cat myfile.txt | linebyline.sh
or you don't even need a separate script:
cat myfile.txt | while read line; do ghc -e "$line"; done

The solution is pretty simple: change print in f to a function which will interpret the line and execute it.
Iit is very easy to use system from System.Cmd and run commands via ghc - e. Your code then becomes
import System.IO
import System.Cmd
import Control.Monad
main = do
fileContents <- readFile "Instructions.txt"
mapM_ f (lines fileContents)
f line = do
putStrLn ("Processing Instruction:" ++ line)
system $ "ghc -e " ++ show line
You still need to add error checking and stuff like that but I'll leave those parts to you since they are not central to the question.

Related

Why doesn't my Haskell cmd line program get arguments from Vim Bang?

Vim has the possibility to let you replace selected text with the output of an external program. I'd like to take advantage of this with programs that I'd write in Haskell. But it doesn’t get the selected text as args.
-- show-input.hs
module Main where
import System.Environment
main = do
input <- getArgs
putStr ("Input was: " ++ (show input))
When I run it from the command line (NixOS GNU/Linux, BASH), I get the expected behavior:
$ ./show-input test
Input was: ["test"]
When I select some text in Vim and invoke :'<,'>!~/show-input, I get this :
Input was: []
There is something weird here, but I can't tell if it is from the way Vim passes arguments or from the way Haskell gets them. I have tried with both console Vim and graphical gVim (8.0.1451), with the same result.
NB: I can successfully use Vim Bang! with other external programs, such as grep. It works great.
---
Correct version after chepner's answer
So, for anyone interested, just replace getArgs with getContents and you get your input all in a string (instead of a list of strings).
module Main where
import System.Environment
main = do
input <- getContents
putStr ("Input was: " ++ (show input))
The ! command sends the seleted text to the program via standard input, not as a command line argument. The command line equivalent would be somecommand | ./show-input.

Why does my Haskell program not accept standard input redirection?

I'm trying to read a file in Haskell by supplying the file name as a command line argument.
I have read that you can accomplish this by:
./program < input.txt
I wrote this code:
main = do
[fileName] <- getArgs
file <- readFile fileName
print file
But I get this error: "pattern match failure in do expression". If I omit the < sign it works, is this the only way to accomplish this? I would much rather not omit it. What should I change?
./program < input.txt calls the program with 0 arguments and redirects stdin to the contents of input.txt.
So you get a pattern matching error because getArgs is empty. So if you want your program to always read from stdin, don't use the command line arguments at all and read from stdin instead of a file.
If you want your program to read from stdin only if no file name was given, check the length of the arguments first and then read from the given file name or from stdin depending on that.
If you run ./program arg then arg is passed as an argument. The standard input is left on its default -- usually reading from keyboard from a terminal.
If you run ./program < filename then no arguments are passed to the program. The standard input now is redirected so to read from file filename.
This is just how the OS shell works.
In Haskell, getArgs gets the program arguments. In the second case, they are empty, and [fileName] <- getArgs fails with your runtime error.

IO monad and ordering [duplicate]

I have the following code:
main = do
putStr "Test input : "
content <- getLine
putStrLn content
When I run it (with runhaskell) or compile it (ghc 6.10.4) the result is like this:
asd
Test input : asd
Why is Test input : asd being printed after asd?
In the code sample on http://learnyouahaskell.com/, which uses putStr, the getLine's presented output is different than mine. When I use putStrLn the program works as expected (print, then prompt, and print).
Is it a bug in ghc, or it is the way that it should work?
This is because ghci disables buffering, while a program compiled with ghc has line buffering by default. You can see this by running this:
import System.IO
main = print =<< hGetBuffering stdout
In ghci you see NoBuffering while with runghc you get LineBuffering. Since the newline character doesn't print until after the user input, the prompt doesn't either.
Fix it by adding hFlush stdout after your prompt (or disable buffering with hSetBuffering stdout NoBuffering, but that’s probably bad).

Deleting items in stdin with haskell

I have a bit of code in my haskell program like so:
evaluate :: String -> IO ()
evaluate = ...
repl = forever $ do
putStr "> " >> hFlush stdout
getLine >>= evaluate
Problem is, when I press the delete key (backspace on windows), instead of deleting a character from the buffer, I get a ^? character instead. What's the canonical way of getting delete to delete a character when reading from stdin? Similarly, I'd like to be able to get the arrow keys to move a cursor around, etc.
Compile the program and then run the compiled executable. This will give the correct behavior for the Delete key. For some reason interpreting the program screws up the use of Delete.
To compile the program, just invoke ghc like this:
$ ghc -O2 myProgram.hs
This will generate a myProgram executable that you can run from the command line:
$ ./myProgram
That will then give the correct behavior for Delete.

Prevent Haskell's getArgs from parsing glob expressions

I'm using getArgs in my Haskell program to parse arguments from the command line. However, I've noticed that I have problems when I call my program like this:
runhaskell Main *.hs .
As you can imagine, Main looks at *.hs files in the . directory.
But there's a problem. The code below doesn't behave as I'd expect.
import System
main :: IO ()
main = do
args <- getArgs
print args
I want to see
args = ["*.hs","."]
but instead I see
args = ["file1.hs","file2.hs","file3.hs","."]
My program needs to expand the glob expression itself because it does it in multiple directories. But how can I have getArgs return the raw list of arguments instead of trying to be magical and do the parsing itself?
This isn't haskell, this is your shell.
Normally file globs (like *.hs) are interpreted by the shell before the command is passed to haskell.
To see this try running
runhaskell Main '*.hs' .
The single quotes will prevent your shell from interpreting the glob, and pass the argument as-is to runhaskell.
getArgs doesn't parse the glob expressison - getArgs never sees the glob expression. The glob expression is parsed and expanded by your shell before your program even starts.
There's nothing you can do inside your program to prevent this - your only option is to escape the glob in the shell (by adding a backslash before the * for example or surrounding the argument with single quotes).

Resources