How to get the path for openFile in Haskell? - macos

I have the following program which throws a runtime exception:
import System.IO
main :: IO ()
main = do
handle <- openFile "palindrome.txt" ReadMode
input <- hGetContents handle
hClose handle
It type checks, but whenever I try to run main, I'll get an error:
What am I doing wrong?

Your current program uses a relative path. As such, the file must be in the same directory where you started GHCi. Given that your workspace is $HOME/Desktop/Haskell, it probably checks only for $HOME/Desktop/Haskell/palindrome.txt. If you want to use the palindrome.txt in $HOME/Desktop/Haskell/u03/3-1/`, you need to either use the absolute path in your code, or run GHCi in that directory.
Note that you can change the current directory in GHCi with :cd, so the following commands in GHCi should work:
Prelude> :cd /path/to/your/directory
Prelude> :l palindrom-a.hs
*Main> :main

Related

How to make a change to the source code in Haskell using GHCi?

I am new to Haskell and am using GHCi to edit and run Haskell files. For some reason, I am not able to edit the source code of the file. The behavior I am getting is extremely odd.
Below is a screenshot of what is happening. I am loading the file lec3.hs and am attempting to edit this file to add the following function: myfun = \w -> not w. For some reason, this function successfully runs when I call it immediately after: myfun False. I do not need to reload the file.
It is clear that the function is not being added to the source code. When I reload the file, I am getting an error stating that myfun does not exist.
Could someone help me understand why GHCi is behaving this way, and how to fix such behaviour? I have already spent an hour trying to figure this out. I would sincerely appreciate any help.
Typing things into GHCi isn't supposed to add them to the source. But if you have loaded a file into GHCi you can edit it using the :e command, and when you close the editor it will be automatically reloaded.
You can use :e filename.hs if you are dealing with more than one file and you need to specify.
Generally it's easier to work in a separate editor and just reload into GHCi with :r, but :e is occasionally useful.
To answer
Is it possible to edit a .hs file from GHCi?
It technically speaking is possible, since Haskell has like any other language file-IO operations. Concretely, appendFile allows you to add content to a file.
$ cat >> Foo.hs # Creating a simple Haskell file
foo :: Int
foo = 3
$ ghci Foo.hs
GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/sagemuej/.ghc/ghci.conf
Loaded GHCi configuration from /home/sagemuej/.ghci
[1 of 1] Compiling Main ( Foo.hs, interpreted )
Ok, one module loaded.
*Main> foo
3
*Main> appendFile "Foo.hs" $ "myfun = \\w -> not w"
*Main> :r
[1 of 1] Compiling Main ( Foo.hs, interpreted )
Ok, one module loaded.
*Main> myfun False
True
But this really is not a good way to edit files. It makes much more sense to have two windows open, one with a text editor and one with the REPL, i.e. with GHCi. It can be either two completely separate OS windows, or two sub-windows of your IDE or whatever, but in either case GHCi will be used only for evaluation and one-line prototyping, not for actually adding/editing code. (The one-line prototypes can be copy&pasted into the editor, if it helps.)

Haskell error on text file as input on Mac

I have a Main.hs file with two functions.
Module Main where
import Data.List
main :: IO()
main = interact reverse
functionThatWorks = putStrLn "Ajax"
After I set the directory and load Main.hs I have no problem with calling functionThatWorks.
Except when I want to take a text file as input like so:
Main<in.txt or ./Main<in.txt
I get an error saying 'parse error on input 'in' '
Does anyone know I can make this work in the Terminal?
p.s. I use a Mac.
Unfortunately ghci doesn't understand input redirection like the shell does.
I would suggest running your program with runhaskell:
runhaskell Main.hs < in.txt

Haskell Noob In Need of Assistance

This is a bit long, so bear with me!
I'm having a bit of trouble working with a Haskell program, that I have to use as part of a uni project. For reference, it's Casper.
So, you're supposed to execute a script, which is actually a Bash script to invoke Hugs interpreter like this:
exec $HUGSBIN/hugs $HUGSARGS +p"Casper> " $FILES
Where $FILES points to a Main.lhs file.
After this, I need to invoke a function "compile" with a path to a file, in the interpreter.
I need to perform the above in a scripted manner. I need this automated because I'm writing a program that will call on Casper in the background.
So I compiled the .lhs file. Now I want to execute the "compile" function but I have no idea how this is done. I try:
./Main compile <a path>
from the command line but it returns me an error about a file "test" not found. Upon investigation, I see these lines in the Main.lhs file:
>main :: String -> IO()
>main = compile "test"
>compile :: String -> IO()
>compile s = catch (compile0 False s) handler
[...snipped]
The 2nd line solves this question. Now my question is, how do I invoke the "compile" function and pass a path to it after I have compiled main.lhs? From the interpreter, I just type "compile " and it works, but I can't get the same to work after compiling the main.lhs and executing from the command line? Any ideas why? Is there any way I can script Hugs if all else fails?
Thank you for any assistance!
You may access the command-line arguments passed to a Haskell program via getArgs. For example, it sounds like you want a main function that does something like this:
>main = do
> args <- getArgs
> case args of
> [] -> putStrLn "What file did you want me to compile?"
> [filename] -> compile filename
> _ -> putStrLn "I only compile one file at a time."
Modify to taste.
Replace main with
main = getArgs >>= \(arg1:_) -> compile arg1
This will pass the first command line argument (arg1) to compile instead of "test", and ignore the rest (_). You may need to add
import System
or
import System.Environment
I can't remember what is needed in hugs for this.

How to debug Haskell code?

I have a problem. I wrote a big Haskell program, and it always works with small input. Now, when I want to test it and generate a bigger input, I always get the message:
HsProg: Prelude.head: empty list
I use Prelude.head many times. What can I do to find out more or get a better error output to get the code line in which it happens?
The GHCi option -fbreak-on-exception can be useful. Here's an example debugging session. First we load our file into GHCi.
$ ghci Broken.hs
GHCi, version 7.0.2: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
[1 of 1] Compiling Main ( Broken.hs, interpreted )
Ok, modules loaded: Main.
Now, we turn on -fbreak-on-exceptions and trace our expression (main in this case for the whole program).
*Main> :set -fbreak-on-exception
*Main> :trace main
Stopped at <exception thrown>
_exception :: e = _
We've stopped at an exception. Let's try to look at the code with :list.
[<exception thrown>] *Main> :list
Unable to list source for <exception thrown>
Try :back then :list
Because the exception happened in Prelude.head, we can't look at the source directly. But as GHCi informs us, we can go :back and try to list what happened before in the trace.
[<exception thrown>] *Main> :back
Logged breakpoint at Broken.hs:2:23-42
_result :: [Integer]
[-1: Broken.hs:2:23-42] *Main> :list
1
2 main = print $ head $ filter odd [2, 4, 6]
3
In the terminal, the offending expression filter odd [2, 4, 6] is highlighted in bold font. So this is the expression that evaluated to the empty list in this case.
For more information on how to use the GHCi debugger, see the GHC User's Guide.
You may want to take a look at Haskell Wiki - Debugging, which contains many useful approaches to your problem.
One promising tool is LocH, which would would help you locate the head invocation in your code which triggered the empty list error.
Personally, I recommend the safe package, which allows to annotate most partial functions from the Prelude (and thus leads to a more conscious use of those partial functions) or better yet, use the total variants of functions such as head which always return a result (if the input value was defined at least).
Since GHC 8, you can use the GHC.Stack module or some profiling compiler flags detailed on a Simon's blog.
You can use this library:
Debug.Trace
You can replace any value a with the function:
trace :: String -> a -> a
unlike putStrLn there is no IO in the output, e.g.:
>>> let x = 123; f = show
>>> trace ("calling f with x = " ++ show x) (f x)
calling f with x = 123
123
The trace function should only be used for debugging, or for monitoring execution. The function is not referentially transparent: its type indicates that it is a pure function but it has the side effect of outputting the trace message.

Create background process in windows without visible console window

How do I create a background process with Haskell on windows without a visible command window being created?
I wrote a Haskell program that runs backup processes periodically but every time I run it, a command window opens up to the top of all the windows. I would like to get rid of this window. What is the simplest way to do this?
You should really tell us how you are trying to do this currently, but on my system (using linux) the following snippet will run a command without opening a new terminal window. It should work the same way on windows.
module Main where
import System
import System.Process
import Control.Monad
main :: IO ()
main = do
putStrLn "Running command..."
pid <- runCommand "mplayer song.mp3" -- or whatever you want
replicateM_ 10 $ putStrLn "Doing other stuff"
waitForProcess pid >>= exitWith
Thanks for the responses so far, but I've found my own solution. I did try a lot of different things, from writing a vbs script as suggested to a standalone program called hstart. hstart worked...but it creates a separate process which I didn't like very much because then I can't kill it in the normal way. But I found a simpler solution that required simply Haskell code.
My code from before was a simple call to runCommand, which did popup the window. An alternative function you can use is runProcess which has more options. From peeking at the ghc source code file runProcess.c, I found that the CREATE_NO_WINDOW flag is set when you supply redirects for all of STDIN, STOUT, and STDERR. So that's what you need to do, supply redirects for those. My test program looks like:
import System.Process
import System.IO
main = do
inH <- openFile "in" ReadMode
outH <- openFile "out" WriteMode
runProcess "rsync.bat" [] Nothing Nothing (Just inH) (Just outH) (Just outH)
This worked! No command window again! A caveat is that you need an empty file for inH to read in as the STDIN eventhough in my situation it was not needed.
The simplest way I can think of is to run the rsync command from within a Windows Shell script (vbs or cmd).
I don't know anything about Haskell, but I had this problem in a C project a few months ago.
The best way to execute an external program without any windows popping up is to use the ShellExecuteEx() API function with the "open" verb. If ShellExecuteEx() is available to you in Haskell, then you should be able to achieve what you want.
The C code looks something like this:
SHELLEXECUTEINFO Info;
BOOL b;
// Execute it
memset (&Info, 0, sizeof (Info));
Info.cbSize = sizeof (Info);
Info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
Info.hwnd = NULL;
Info.lpVerb = "open";
Info.lpFile = "rsync.exe";
Info.lpParameters = "whatever parameters you like";
Info.lpDirectory = NULL;
Info.nShow = SW_HIDE;
b = ShellExecuteEx (&Info);
if (b)
{
// Looks good; if there is an instance, wait for it
if (Info.hProcess)
{
// Wait
WaitForSingleObject (Info.hProcess, INFINITE);
}
}

Resources