import System.Environment (getArgs)import Randommain = do  args <- getArgs  let len = length args  let n = if len < 1 then 10000 else  read (args !! 0) :: Int  let fileName = if len < 2 then show n ++ -output.txt  else args !! 1  str <- rndStr n  writeFile fileName (str)--  writeFile fileName (rndStr n)-- Couldn't match expected type `[Char]' with actual type `IO String'rndStr :: Int -> IO StringrndStr n  = sequence . replicate n . randomRIO $ (' ', '~')This code works. It creates size n file of random chars. That's good.I have 2 questions:1. Is my argument sanitizing ok? If not, how to make it better?2. Swapping writeFile str for writeFile (rndStr n) produces [Char] vs IO String error.Why? Shouldn't it be the same?I manage this to work by accident, not because I know what I did.
Haskell: rndFile and [Char] vs IO String error
strings;haskell;random
Congratulations on your progress, :) Welcome to monadsFirst thing you have to keep in mind is to restrict the time spent in imperative world. So take out as much stuff as you can from the do ..., and refactor them into smaller non-IO code.import System.Environment (getArgs)import System.Randomimport Control.MonadAnother advice is to avoid magic numbers in your code. If there are any, they should be declared in a highly visible area along with their purpose rather than buried deep in the code.minLen = 10000main = do    args <- getArgs    writeFile (getFileName args) =<< rndStr (getFileSize args)  where getFileSize [] = minLen        getFileSize (x:xs) = read x :: Int        getFileName [x] = x ++ -output.txt        getFileName (x:y:[]) = yAs you can see, the reason you can't use rndStr directly is that rndStr uses IO. So it cannot be directly used as a function. You can think of it this way. rndStr returns some thing that is wrapped in a box. You need special constructs to unbox it, and the special construct is either <- . You might also notice that main has the same kind of signature. That isn't a really good analogy, and I am not the best teacher :). So if you really want to understand what happens, it might be better to read any simple monad tutorial.rndStr :: Int -> IO StringrndStr n  = sequence . replicate n . randomRIO $ (' ', '~')Try this approach if it makes better sense to you. When you start ghci, use this flagghci -XImplicitParamsOn the prompt after loading your program, try to execute writeFile which was not accepting (rndStr number) earlier, but this time, instead of that expression, replace it by ?check> writeFile (getFileName [5] ) ?checkYou will get back some thing like<interactive>:0:32:  Unbound implicit parameter (?check::String)    arising from a use of implicit parameter `?check'    In the second argument of `writeFile', namely `?check'    In the expression: writeFile (getFileName [5]) ?check    In an equation for `it': it = writeFile (getFileName [5]) ?checkIgnore every thing except the second line, the Unknown implict .. tells you that ghc expected any exprssion in place of ?check would be a string.Now try finding the type of our expression (rndStr number)> :t rndStr 5rndStr 5 :: IO StringAs you can see, rndStr number has a different type IO String than the expected String. This is the reason you cant use rndStr number there, and why we have to do all that above.Note that my statement writeFile (getFileName args) =<< rndStr (getFileSize args) is really same asdostr <- rndStr (getFileSize args)writeFile (getFileName args) strTry to work out how it is so.