Why is getArgs evaluated after fmap method argument? - haskell

Why does getArgs gets evaluated after the method argument of fmap?
main::IO()
main=do
fpath<-fmap head getArgs
putStrLn fpath
I get the error :
Exception: Prelude.head: empty list
It seems it applies head on something that has not been computed yet.
I first assumed that it might be another rule about lazyness that i am not aware of being new to Haskell so i tried with :
a<-fmap head getLine # no problem
a<-fmap head (readFile [filename]) # again no problem
So why is getArgs special that gets evaluated after ?

If head breaks on empty list, that means that getArgs did already evaluate, because the value [] was produced and matched by head.
Most probably you ran your program from ghci, which can produce such an effect. Since head is unsafe, you should check whether there's at least one argument on the list present.

Related

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.

Implicit pattern matching the first 2 items of a list

Is there a way to do this in an implicit way:
(originalPath:extractPath:ignoredArgs) <- getArgs
considering I only need the first two args and will ignore the others anyway.
This is just a curiosity/exploring/learning question (just started with Haskell), ignoredArgs does not harm if it's left like this.
I tried
(originalPath:extractPath) <- getArgs
But it fails since extractPath will be of [String] type (instead of String)
Use a wildcard, _
(originalPath:extractPath:_) <- getArgs
to ignore everything after the first two arguments.
You need to have something there to have the two names be bound to Strings, and a wildcard pattern (underscore) is the way to tell the compiler and human readers of the code that you are not interested in further arguments.

Error reading and writing same file simultaneously in Haskell

I need to modify a file in-place. So I planned to read file contents, process them, then write the output to the same file:
main = do
input <- readFile "file.txt"
let output = (map toUpper input)
-- putStrLn $ show $ length output
writeFile "file.txt" output
But the problem is, it works as expected only if I uncomment the 4th line - where I just output number of characters to console. If I don't uncomment it, I get
openFile: resource busy (file is locked)
Is there a way to force reading of that file?
The simplest thing might be strict ByteString IO:
import qualified Data.ByteString.Char8 as B
main = do
input <- B.readFile "file.txt"
B.writeFile "file.txt" $ B.map toUpper input
As you can see, it's the same code -- but with some functions replaced with ByteString versions.
Lazy IO
The problem that you're running into is that some of Haskell's IO functions use "Lazy IO", which has surprising semantics. In almost every program I would avoid lazy IO.
These days, people are looking for replacements to Lazy IO like Conduit and the like, and lazy IO is seen as an ugly hack which unfortunately is stuck in the standard library.

Haskell: Conditionally execute external process with Maybe FilePath

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

Haskell -- "The last statement in a 'do' construct must be an expression"

Like it says in the title: What does The last statement in a 'do' construct must be an expression mean? I ended my do block with a putStrLn like it shows in several examples I've seen, and i get an error.
Code:
main = do args <- getArgs
file <-readFile "TWL06.txt"
putStrLn results
Most of the time, it's because your code is mis-aligned and compiler assumes that your "do" block ended prematurely (or has extra code that dont really belong there)
Your last line isn't something like someVar <- putStrLn "hello", by any chance, is it? You'll get that error if you try to do a variable binding on the last line, because it's equivalent to putStrLn "Hello" >>= \someVar -> — it expects there to be an expression at the end.
Incorrect indentation can lead to this error. Also, is good not to use tabs, only spaces.

Resources