I'm trying to write my first IO program in haskell, but I can't seem to run it from the command line I want the command cabal run 5 > result.txt to print a 5 in binary in result.txt. I found some conversion code but when I implement it I get an error:
src/Main.lhs:23:28: error:
• Couldn't match type ‘Int’ with ‘Char’
Expected type: String
Actual type: [Int]
• In the second argument of ‘writeFile’, namely ‘(toBin (args))’
In a stmt of a 'do' block: writeFile "file.txt" (toBin (args))
In the expression:
do { args <- getArgs;
writeFile "file.txt" (toBin (args)) }
src/Main.lhs:23:34: error:
• Couldn't match expected type ‘Int’ with actual type ‘[String]’
• In the first argument of ‘toBin’, namely ‘(args)’
In the second argument of ‘writeFile’, namely ‘(toBin (args))’
In a stmt of a 'do' block: writeFile "file.txt" (toBin (args))
Here is my code:
module Main where
import System.Environment
import Data.List
import Data.Maybe
import qualified Data.Map as M (Map, empty, insert, lookup)
import Data.Char (ord)
toBin:: Int -> [Int]
toBin 0 = [0]
toBin n = reverse (helper n)
helper:: Int -> [Int]
helper 0 = []
helper n = let (q,r) = n `divMod` 2 in r : helper q
main :: IO ()
main = do
args <- getArgs
writeFile "file.txt" (toBin(args))
First, your function toBin
expects an Int
parameter, but args
is of type [String]
- i.e. a list of strings. So you need to take the first argument (from your description) and convert it to an Int
. The cheapest, dirtiest way to do that is with head
to take first and then read
to convert to Int
:
writeFile "file.txt" (toBin . read . head $ args)
Note however that this code will crash at runtime if (1) the list of arguments is empty (i.e. doesn't have a "first" element) or (2) the first argument is not a number. If you're not ok with crashing, consider using safer alternatives, such as headMay
or reads
.
Second, your function toBin
returns a list of Int
s, but writeFile
expects an argument of type String
. The cheapest, dirtiest way to convert is via show
:
writeFile "file.txt" (show . toBin . read . head $ args)
However, the implementation of show
for lists will yield a string that doesn't look like a binary number. It will look like "[0, 1, 1, 0, 1]"
. If you're not ok with this representation, you will have to write your own function for converting the list to a string that looks like a binary number. The cheapest, dirtiest way of doing that is by applying show
to each element of the list and then gluing the resulting strings together:
binToStr :: [Int] -> String
binToStr = concat . map show
...
writeFile "file.txt" (binToStr . toBin . read . head $ args)
Or it could be simplified to concatMap
:
binToStr = concatMap show