Haskell: Conditionally execute external process with Maybe FilePath - haskell

I am struggling to understand a block of code which is extremely easy in imperative world.
That's what I need to do: given an executable full path, which is a Maybe FilePath type, I need to execute it conditionally.
If the path is a Nothing - print an error, if the path is Just Path - execute it and print message that the file has been executed. Only "Hello, World" can be easier,right?
But in Haskell I dug my self into numerous layers of Maybe's and IO's and got stuck.
Two concrete questions arise from here:
How do I feed a Maybe FilePath into a system or rawSystem? liftM does not work for me here.
What is the correct way of doing this kind of conditional branching?
Thanks.

Simple pattern matching will do the job nicely.
case command of
Just path -> system path >> putStrLn "Done"
Nothing -> putStrLn "None specified"

Or, if you'd rather not pattern-match, use the maybe function:
maybe (putStrLn "None specified") ((>> putStrLn "Done") . system) command
That may occasionally be nicer than matching with a case, but not here, I think. The composition with the printing of the success message is clunky. It fares better if you don't print messages but return the ExitCode in both branches:
maybe (return $ ExitFailure 1) system command

This is exactly what the Traversable type class was made for!
Prelude Data.Traversable System.Cmd> traverse system Nothing
Nothing
Prelude Data.Traversable System.Cmd> traverse system (Just "echo OMG BEES")
OMG BEES
Just ExitSuccess

Related

Haskell: Parse error: module header, import declaration or top-level declaration expected

I am saving some commands in a Haskell script in a .hs file while working thru a Haskell textbook. Here's a small example.
fst (1,2)
snd (1,2)
When I run these commands from the prelude in GHCi, they work fine. When I try to compile the .hs file with these two lines, I get the following:
ch4_test.hs:2:1: error:
Parse error: module header, import declaration
or top-level declaration expected.
|
2 | fst (1,2)
| ^^^^^^^^^
Failed, no modules loaded.
I've googled this error and can't find any explanation what I'm doing wrong.
From a newbie to future newbies: The interactive environment ghci would lead you to believe that you can punch some expressions into an .hs file and run the thing (in a similar fashion to languages like swift and ruby). This is not the case.
Haskell needs an entrypoint called main. Quoting:
Here is a simple program to read and then print a character:
main :: IO ()
main = do c <- getChar
putChar c
The use of the name main is important: main is defined to be the entry point of a Haskell program (similar to the main function in C), and must have an IO type, usually IO ()
Source: https://www.haskell.org/tutorial/io.html
You can't just put any expression in a hs file.
As the error message says, you need a declaration here. For example:
main =
print (fst (1,2)) >>
print (snd (1,2))
I am getting this error but the cause appears to be completely different from anything posted here. And the error message is not at all helpful.
Using Cabal version 3.6.2.0 with GHCI 8.10.7 on MacOS High Sierra (10.13)
I'm working from this page: https://www.tutorialspoint.com/haskell/haskell_modules.htm
specifically the "custom modules" section. There you can see the code I copied and pasted.
Besides the tutorial not mentioning I needed to add "other-modules: Custom" to myfirstapp.cabal, and besides the fact that the sample Custom.hs file includes "if x 'rem' 2 == 0" rather than "if x rem 2 == 0", here is the problem:
Indentation matters!
This line (inside the quotes) does NOT work "if x rem 2 == 0".
This line DOES work " if x rem 2 == 0"!
Indenting by one space is the difference between success and failure.
I'm totally new to Haskell. I've programmed extensively in PHP, Javascript, and Applescript, and dabbled in a dozen others, and this is the first time I've seen white space matter. I assume this is commonly known amongst Haskell veterans, but it would certainly be nice if that was included prominently in the documentation.

Using "printf" on a list in Haskell

How can i use printf over a list?
I have a list of numbers and i want to print them all by respecting a format (ex: %.3f). I tried to use map over printf, but it does not work. So, i have no idea. Can somebody help me with this? Any ideas are acceptable. Is there a way to create a string from a list respecting a custom format?
printf can produce strings instead of just printing them to stdout. This
is because it is overloaded on its result type (it's also part of machinery
that makes it variadic).
import Text.Printf
main :: IO ()
main = putStrLn . unwords $ printf "%.3f" <$> ([1..10] :: [Double])
That should do the trick.
BTW, printf is not type safe and can blow at run time. I recommend you use
something like
formatting.

Disable printing of IO results in GHCi?

When running IO actions in GHCi prompt it automatically runs the action and shows result, this is nice, but not for students trying to understand difference between IO and non-IO. Is there a way to change configuration of GHCi so that it runs the action, but shows something like <<IO Int action>> instead? Something more like result for ST actions (but action should be performed):
now it does:
> return 1 :: IO Int
1
> return 1 :: ST s Int
<<ST action>>
i would like:
> return 1 :: IO Int
<<IO Int action>>
> putStrLn "bla"
bla
<<IO () action>>
Edit:
I just found that IO is probably the only thing handled specially by GHCi, ST actually has instance for Show (ST s a) which returns "<<ST action>>". So maybe if I could disable this special treatment of IO it would be sufficient.
As for allowed code changes: manually changing evaluated expression is not an option. Change in libraries might be, but I would prefer not to do that (I considered creating wrapped IO type, but then interpreter will not run the action). If GHCi could automatically wrap IO actions somehow, that would be an option.
This is an interesting question. The only thing I can come up with is writing some kind of custom prelude module that exports a type called IO, but which isn't "the" I/O type that GHCi is special-casing.
Of course, this is no help at all unless the student remembers to import this rather than the real prelude. I suppose you could write that into the GHCi config file, but... well, it's certainly not perfect.
The only other way I can think of is to use the GHC-API to basically reimplement GHCi yourself. But that sounds like waaaay too much work...

How to handle runtime errors in Haskell?

I'm trying to learn Haskell by writing a simple console chess game. It displays a chess board and gets moves from standard input in SAN notation. Here's what I've got so far:
import System.IO
import Chess
import Chess.FEN
main = do
putStrLn "Welcome to Console Chess!"
putStrLn $ show defaultBoard
gameLoop defaultBoard
gameLoop board = do
putStr "Your move: "
hFlush stdout
move <- getLine
let newBoard = moveSAN move board
case newBoard of
Left _ -> do
putStrLn "Invalid move, try again..."
gameLoop board
Right b -> do
putStrLn $ show b
gameLoop b
The problem is that the call to the moveSAN function sometimes crashes the program, losing all progress made in the game. For instance, pressing Enter at the "Your move:" prompt produces:
Your move:
cchess: Prelude.head: empty list
Otherwise, entering a two-digit number produces:
Your move: 11
cchess: Error in array index
Entering two periods gives:
Your move: ..
cchess: Char.digitToInt: not a digit '.'
I would like to catch these errors and inform the user that the move they have entered is not in valid SAN notation. How can I do that?
In an ideal world, you would avoid functions like head and not have runtime errors at all. Runtime errors are fundamentally awkward, especially in Haskell.
In this case, you want to catch the runtime error. If you're content to turn it into a Maybe, you can use the spoon package.
Exceptions in Haskell are subtle thanks to laziness. Particularly, if you don't evaluate the part of the structure that has the exception, it won't fire. This is handled in spoon with two different functions:
spoon, which evaluates a structure deeply but requires an instance of a special typeclass
teaspoon which only evaluates your structure part of the way to weak head normal form
For your case, I think teaspoon should be fine. Try checking the result of the parse with:
teaspoon (moveSAN move board)
which should give you a Maybe value.
If that doesn't work, it means you need to evaluate more of the structure to hit the exception. It looks like Board does not implement the typeclass needed to deeply evaluate it with spoon, so your best bet is a bit hacky: use spoon on the result of show:
spoon (show $ moveSAN move board)
This will give you a Maybe String. If it's Just, the move parsed correctly; if it's Nothing, there was an error.
It's worth noting that the spoon package doesn't really do much: each function it has is only a couple of lines. At some point, it's worth figuring out how to handle exceptions in Haskell yourself, but for now spoon is just a bit more convenient and should work properly for you.

Compiling / testing Haskell without a main function

I'm working on an assignment in Haskell. However, the base code I am working with does not have a main function defined, and from the wording of the assignment I believe I am not expected to have to write any code outside of the solution to the problem. However, when I try to compile my code, I receive the error:
The IO function 'main' is not defined in module 'Main'
I assume this is because the function does not have a main function. However, when I try to write my own main function:
main :: IO ()
main = solve easy // easy is an array
I get the error:
Couldn't match expected type 'IO()' with actual type '[Int]'
The solve function's type is declared as follows:
solve :: [Int] -> [Int]
So it takes an array and returns an array. What am I doing wrong in writing my main function? Even when I try changing the declaration of main to things like:
main :: [Int]
or
main :: IO [Int]
I still can't get it to compile.
Without writing a proper main with a correct type, as described by #G Philip, you can load your file in ghci by writing ghci file.hs in your terminal, or by invoking :l file.hs inside ghci.
Firstly: the function main must have type IO t for some type t. When the program is executed, the computation defined by main is executed, and its result (of type t) is thrown away; see here.
So, in particular, you cannot have the type of main as [Int] and have the compiler not complain.
Depending on whether you want to see the results of solving the easy case or not, you can try one of the following:
If you want to see the results: print them!
main :: IO ()
main = putStrLn $ show (solve easy)
If you are not interested in seeing the results, throw them away:
main :: IO ()
main = let solution = solve easy
in putStrLn ""
Edit: Note, however, that if you do the latter, then (as #yatima2975 mentions in a comment) the "solve easy" part will not be evaluated.
Just to add to the other answers:
you don't need to write a main function and can still compile the file into a lib and the easiest way to do this is just giving a module name (that is not Main):
module MyCode where
solve :: ...
But of course compiling it might not make any sense anymore (as you will not be able to run it - and of course even if you have not specified what to output anyway).
So in this case rather load the file into ghci:
ghci MyFile.hs
and then everytime you changed something in your code you can do :r inside ghci to reload it.
Or even better set up your favorite editor (emacs and vi are quite easy but sublime text and some other works great too) to give you integrated ghci - this explains what you need to do to setup emacs with haskell-mode if you are interested.
Consider
main :: IO ()
main = do
let res = solve easy // easy is an array
return ()
where return () yields a result of type Unit which conveys with the type signature of main. Note solve easy is bound to res which is not used further.

Resources