Haskell compilation with an input file, error openFile: does not exist (No such file or directory) - haskell

I apologize if this is a simple question.
I have specified an input file which is in the same directory of the code source file.
isprime :: Int -> [Int] -> Bool
isprime ...
main = do
handle <- openFile "primes-to-100k.txt" ReadMode
contents <- hGetContents handle
i <- getLine
print $ isprime (read i::Int) $ map (\x->read x::Int) $ lines contents
hClose handle
The code runs well when I use "runhaskell Q111.hs" in shell,
but when I compile it with "ghc --make Q111.hs and run, I got an error message
Q111: primes-to-100k.txt: openFile: does not exist (No such file or directory)
logout
The point is that the code runs well with ghci and runhaskell, but the executable can't find the input txt.
Do I have to provide the input txt to compiler using someway?

How are you running the executable? The text file would have to be in the directory you run the program from, which may or may not be where the program is. If you are running ./Q111 from the command line, or if you are double-clicking Q111.exe in Windows, then the text file must be in the same folder as the executable. If you are in a different directory on the command line, then the text file would have to be wherever your current directory is, and not the directory where the executable is.
EDIT: Just saw from your other comment that you are on OS X, and (I assume) are double-clicking the program. From what you said I guess that OS X sets the current directory of such-executed programs to be your home. If you want to get the directory of your program, see the answers to this question. If you use the FindBin package they mention:
main = do
exedir <- getProgPath
handle <- openFile (exedir ++ "/primes-to-100k.txt") ReadMode
...

Try the curdDir <- getCurrentDirectory and paths <- getDirectoryContents and check the paths. If it contains the filename, the path is right(and try using contents <-readFile "file" for simpler programs, but this isn't neccessary).
Edit:
...and use isexist <- doesFileExist "f" for checking the existence.

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.

Haskell read multiple files

I'm trying to read multiples files at once using the following code.
The code compiles, however when executed I get the following exception:
*** Exception: ..: openFile: permission denied (Permission denied).
I have all the permissions as system administrator. Also, I was able to do the same in C# with no problem, meaning/suspecting that it's an issue with the code itself.
Thanks for help.
main :: IO()
main = do
putStrLn " Enter file path:"
content <- getLine >>= getDirectoryContents
x <- mapM readFile content
print x
Are you sure all of the files are actually files? It looks like you're trying to open a file called ...
Filter the results to only include actual files first.

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.

Get absolute path of current source file in Haskell

Is it possible to get the absolute path of the current source file in Haskell?
I could only find one relevant function: getCurrentDirectory from System.Directory, but it "returns an absolute path to the current directory of the calling process.", not the path of the current file.
(I need it to read sample inputs which are located in the same folder as the source file; If there's any better way to do it, that will be helpful too!)
You can use CPP. If you compile this file
{-# LANGUAGE CPP #-}
main = print __FILE__
it will print the path to the source as you passed it to ghc – which may or may not be the full path, though:
/tmp $ ghc --make mypath.hs
[1 of 1] Compiling Main ( mypath.hs, mypath.o )
Linking mypath ...
/tmp $ ./mypath
"mypath.hs"
/tmp $ ghc --make /tmp/mypath.hs
Linking /tmp/mypath ...
/tmp $ ./mypath
"/tmp/mypath.hs"
As an alternative, the file-embed package can be used here. It uses template haskell to embed files/directories.
This can be very useful to embed resources or configs in the executable. It may not be advisable to read the sample input this way though. data-files in cabal might be better alternative as already pointed out earlier in this thread.
The PseudoMacros package might be useful. According to the description, it provides C-like strings for the current file name etc.
UPDATE
The file name returned by PseudoMacros equals the path passed to ghc (same behaviour as #JoachimBreitner mentioned in his answer), so
import PseudoMacros
main :: IO ()
main = putStrLn ("Hello from " ++ $__FILE__ ++ ", line " ++ show $__LINE__ ++ "!")
will print
Hello from tmp.hs, line 5!
or
Hello from /tmp/tmp.hs, line 5!
depending on whether you provided a relative or absolute filename to ghc.

Prompt message disappears in compiled executable?

I have a Haskell program that shows a prompt and then accepts input from the command line. I'm doing this as:
main = do putStr "Please enter program source file name: "
programFileName <- getLine
programFileHandle <- openFile programFileName ReadMode
program <- hGetContents programFileHandle
putStr "Please enter initial file configuration file name: "
initConfigFileName <- getLine
initConfigFileHandle <- openFile initConfigFileName ReadMode
initConfigStr <- hGetContents initConfigFileHandle
print (evaluateProgram (lines program) (readReg initConfigStr))
When I run it on the GHCi interpreter, the prompts show up fine and I am able to enter my inputs (and everything else works).
e.g.
*Main> main
Please enter program source file name: sum.urm
Please enter initial file configuration file name: sum.conf
9
When I compile it though (on Mac OS X or Windows), it produces an executable that does not show my prompts. It waits for the two input strings, and then once I have put in the valid filenames, it prints the prompts and the result.
e.g.
$ ./a.out
sum.urm
sum.conf
Please enter program source file name: Please enter initial file configuration file name: 9
Any ideas why this is happening?
For the curious, I was implementing an Unlimited Register Machine in Haskell.
The standard output stream, stdout, is line buffered by default. That means that it will only be written to the console every time you output a \n character, or finally when the program terminates. You can fix this by importing System.IO and doing hFlush stdout after every putStr that doesn't contain a \n at the end.
This is a buffering issue. Here are related questions, with several choices for solutions:
Why isn't my IO executed in order?
Execution order with (>>=) not what I expected

Resources