Print list of floats with format - haskell

In Haskell, how can I print a list of floats (or Fractional, rather) and also specify formatting? E.g. putStrLn $ magic "%.2f" [3.14159] should print [3.14].
As pointed out here there is Text.Printf (printf), but I don't understand how to use it with lists?
One thing that 'works' is
printf' :: [Double] -> [String]
printf' l = map (\x -> printf "%.2f" x) l
with
main = do
putStrLn $ show (printf' [3.14159])
but it's horrible, there must be another way.
The first two examples in this answer to a similar question don't work at all.
The answer here is neat enough, but as pointed out is not type-safe, plus it breaks Read/Show interop.
Are there any other alternatives? Thanks.

You can make use of intercalate :: [a] -> [[a]] -> [a] to put commas between the elements, and do some additional list processing to add a '[' in front and an ']' at the end, like:
import Data.List(intercalate)
main :: IO ()
main = putStrLn ('[' : intercalate "," (printf' [3.14159]) ++ "]")
this then yields:
Prelude Text.Printf Data.List> main
[3.14]
Note that you can simplify your printf' to just:
printf' :: [Double] -> [String]
printf' = map (printf "%.2f")

You can import the Numeric library to achieve this. I've quickly written a small program as an example, without the use of the printf function.
module Main where
import Numeric
main :: IO ()
main = putStrLn "hello world"
a = [1.111, 2.2222222222222, 3.33333333333333333333333]
printList :: [Double] -> [String]
printList xs = map format xs
format :: Double -> String
format x = showFFloat (Just 2) x ""
where the simple call printList a will result in:
["1.11","2.22","3.33"]

Related

Haskell: Convert String to [(String,Double)]

I parse an XML and get an String like this:
"resourceA,3-resourceB,1-,...,resourceN,x"
I want to map that String into a list of tuples (String,Double), like this:
[(resourceA,3),(resourceB,1),...,(resourceN,x)]
How is it possible to do this? I ve looked into the map function and also the split one. I am able to split the string by "-" but anything else...
This is the code i have so far:
split :: Eq a => a -> [a] -> [[a]]
split d [] = []
split d s = x : split d (drop 1 y) where (x,y) = span (/= d) s
it is just a function to split my string into a list of Stirng, but then i dont know how to continue.
What I want to do know is to loop over that new list that i have created with the split method and for each element create a tuple. I hace tried with the map function but i dont get it to compile even
So in Haskell you dont really mutate any value, instead you'll create a new list of pairs from the string you've described, so the solution would look something similar to the following:
import Data.List.Split
xmlList = splitOn "-" "resourceA,3-resourceB,4-resourceC,6"
commaSplit :: String -> [String]
commaSplit = splitOn ","
xmlPair :: [String] -> [(String, Double)] -- might be more efficient to use Text instead of String
xmlPair [x] = [(\x' -> ((head x') :: String, (read (last x')) :: Double )) (commaSplit x)]
xmlPair (x:xs) = xmlPair [x] ++ xmlPair xs
main :: IO ()
main = mapM_ (\(a,b) -> putStrLn (show a++" = "++ show b)) (xmlPair $ xmlList)
This is my quick and dirty way of showing things but I'm sure someone can always add a more detailed answer.

How do I read N lines in a file with Haskell?

I have a file in the form:
3
1 2
3 4
5 7
Where the first line is the number of lines
I know that:
getInt :: IO Int
getInt = readLn
main = do num <- getInt
print (num)
Reads the first line.
Next, I tried:
readInts :: IO [Int]
readInts = fmap (map read.words) getLine
For read a line and get a list: [a,b].
And I tried to use the above in a recursive loop
loop :: Int -> IO()
loop n = if 1 == n then do num <- readInts
print(num)
else loop (n-1)
I'm getting the first line only:
[5,3]
But I need to read the rest of lines, given N
The format of the input file looks a lot like the ones used in programming contests. Here is my standard setup for programming contests like that:
import Control.Monad
import Text.Printf
main :: IO ()
main = do
n <- readLn
forM_ [1 .. n] $ \i -> do
printf "Case %d: " (i :: Int)
solve
An example of solve might be:
solve :: IO ()
solve = do
nums <- map read . words <$> getLine
print (sum nums)
Adding to this helpful answer and comment, for some challenges you'll need to collect n lines and then emit a single result at the end based on an aggregation of the data. An approach for creating a list might use replicateM as follows:
import Control.Monad
toInt :: String -> Int
toInt x = read x :: Int
lineToInts :: String -> [Int]
lineToInts x = map toInt $ words x
main :: IO ()
main = do
n <- readLn
remainingLines <- replicateM n getLine
let list = map lineToInts remainingLines
print list
Sample run:
3
0 1
3 4
6 8
[[0,1],[3,4],[6,8]]
See also Read n lines input with Haskell
Have you looked into the function lines? It takes a string and returns the same string as a list separated by \n. Using this function you don't even have to have the number of lines.

Technique for reading in multiple lines for Haskell IO

Basically I would like to find a way so that a user can enter the number of test cases and then input their test cases. The program can then run those test cases and print out the results in the order that the test cases appear.
So basically I have main which reads in the number of test cases and inputs it into a function that will read from IO that many times. It looks like this:
main = getLine >>= \tst -> w (read :: String -> Int) tst [[]]
This is the method signature of w: w :: Int -> [[Int]]-> IO ()
So my plan is to read in the number of test cases and have w run a function which takes in each test case and store the result into the [[]] variable. So each list in the list will be an output. w will just run recursively until it reaches 0 and print out each list on a separate line. I'd like to know if there is a better way of doing this since I have to pass in an empty list into w, which seems extraneous.
As #bheklilr mentioned you can't update a value like [[]]. The standard functional approach is to pass an accumulator through a a set of recursive calls. In the following example the acc parameter to the loop function is this accumulator - it consists of all of the output collected so far. At the end of the loop we return it.
myTest :: Int -> [String]
myTest n = [ "output line " ++ show k ++ " for n = " ++ show n | k <- [1..n] ]
main = do
putStr "Enter number of test cases: "
ntests <- fmap read getLine :: IO Int
let loop k acc | k > ntests = return $ reverse acc
loop k acc = do
-- we're on the kth-iteration
putStr $ "Enter parameter for test case " ++ show k ++ ": "
a <- fmap read getLine :: IO Int
let output = myTest a -- run the test
loop (k+1) (output:acc)
allOutput <- loop 1 []
print allOutput
As you get more comfortable with this kind of pattern you'll recognize it as a fold (indeed a monadic fold since we're doing IO) and you can implement it with foldM.
Update: To help explain how fmap works, here are equivalent expressions written without using fmap:
With fmap: Without fmap:
n <- fmap read getLine :: IO [Int] line <- getLine
let n = read line :: Int
vals <- fmap (map read . words) getLine line <- getLine
:: IO [Int] let vals = (map read . words) line :: [Int]
Using fmap allows us to eliminate the intermediate variable line which we never reference again anyway. We still need to provide a type signature so read knows what to do.
The idiomatic way is to use replicateM:
runAllTests :: [[Int]] -> IO ()
runAllTests = {- ... -}
main = do
numTests <- readLn
tests <- replicateM numTests readLn
runAllTests tests
-- or:
-- main = readLn >>= flip replicateM readLn >>= runAllTests

Couldn't match type `[]' with `IO' -- Haskell

I'm beginner in Haskell. In this task i'm performing the split operation but i'm facing problem because of type mis match. I'm reading data from text file and the data is in table format. Ex. 1|2|Rahul|13.25. In this format. Here | is delimiter so i want to split the data from the delimiter | and want to print 2nd column and 4th column data but i'm getting the error like this
"Couldn't match type `[]' with `IO'
Expected type: IO [Char]
Actual type: [[Char]]
In the return type of a call of `splitOn'"
Here is my code..
module Main where
import Data.List.Split
main = do
list <- readFile("src/table.txt")
putStrLn list
splitOn "|" list
Any help regarding this will appreciate.. Thanks
The problem is that you're trying to return a list from the main function, which has a type of IO ().
What you probably want to do is print the result.
main = do
list <- readFile("src/table.txt")
putStrLn list
print $ splitOn "|" list
Not Haskell, but it looks like a typical awk task.
cat src/table.txt | awk -F'|' '{print $2, $4}'
Back to Haskell the best I could find is :
module Main where
import Data.List.Split(splitOn)
import Data.List (intercalate)
project :: [Int] -> [String] -> [String]
project indices l = foldl (\acc i -> acc ++ [l !! i]) [] indices
fromString :: String -> [[String]]
fromString = map (splitOn "|") . lines
toString :: [[String]] -> String
toString = unlines . map (intercalate "|")
main :: IO ()
main = do
putStrLn =<<
return . toString . map (project [1, 3]) . fromString =<<
readFile("table.txt")
If not reading from a file, but from stdin, the interact function could be useful.

Non-exhaustive patterns in lambda

I am getting Non-exhaustive patterns in lambda. I am not sure of the cause yet. Please anyone how to fix it. The code is below:
import Control.Monad
import Data.List
time_spent h1 h2 = max (abs (fst h1 - fst h2)) (abs (snd h1 - snd h2))
meeting_point xs = foldl' (find_min_time) maxBound xs
where
time_to_point p = foldl' (\tacc p' -> tacc + (time_spent p p')) 0 xs
find_min_time min_time p = let x = time_to_point p in if x < min_time then x else min_time
main = do
n <- readLn :: IO Int
points <- fmap (map (\[x,y] -> (x,y)) . map (map (read :: String->Int)) . map words . lines) getContents
putStrLn $ show $ meeting_point points
This is the lambda with the non-exhaustive patterns: \[x,y] -> (x,y).
The non-exhaustive pattern is because the argument you've specified, [x,y] doesn't match any possible list - it only matches lists with precisely two elements.
I would suggest replacing it with a separate function with an error case to print out the unexpected data in an error message so you can debug further, e.g.:
f [x,y] = (x, y)
f l = error $ "Unexpected list: " ++ show l
...
points <- fmap (map f . map ...)
As an addition to #GaneshSittampalam's answer, you could also do this with more graceful error handling using the Maybe monad, the mapM function from Control.Monad, and readMaybe from Text.Read. I would also recommend refactoring your code so that the parsing is its own function, it makes your main function much cleaner and easier to debug.
import Control.Monad (mapM)
import Text.Read (readMaybe)
toPoint :: [a] -> Maybe (a, a)
toPoint [x, y] = Just (x, y)
toPoint _ = Nothing
This is just a simple pattern matching function that returns Nothing if it gets a list with length not 2. Otherwise it turns it into a 2-tuple and wraps it in Just.
parseData :: String -> Maybe [(Int, Int)]
parseData text = do
-- returns Nothing if a non-Int is encountered
values <- mapM (mapM readMaybe . words) . lines $ text
-- returns Nothing if a line doesn't have exactly 2 values
mapM toPoint values
Your parsing can actually be simplified significantly by using mapM and readMaybe. The type of readMaybe is Read a => String -> Maybe a, and in this case since we've specified the type of parseData to return Maybe [(Int, Int)], the compiler can infer that readMaybe should have the local type of String -> Maybe Int. We still use lines and words in the same way, but now since we use mapM the type of the right hand side of the <- is Maybe [[Int]], so the type of values is [[Int]]. What mapM also does for us is if any of those actions fails, the overall computation exits early with Nothing. Then we simply use mapM toPoint to convert values into a list of points, but also with the failure mechanism built in. We actually could use the more general signature of parseData :: Read a => String -> Maybe [(a, a)], but it isn't necessary.
main = do
n <- readLn :: IO Int
points <- fmap parseData getContents
case points of
Just ps -> print $ meeting_point ps
Nothing -> putStrLn "Invalid data!"
Now we just use fmap parseData on getContents, making points have the type Maybe [(Int, Int)]. Finally, we pattern match on points to print out the result of the meeting_point computation or print a helpful message if something went wrong.
If you wanted even better error handling, you could leverage the Either monad in a similar fashion:
toPoint :: [a] -> Either String (a, a)
toPoint [x, y] = Right (x, y)
toPoint _ = Left "Invalid number of points"
readEither :: Read a => String -> Either String a
readEither text = maybe (Left $ "Invalid parse: " ++ text) Right $ readMaybe text
-- default value ^ Wraps output on success ^
-- Same definition with different type signature and `readEither`
parseData :: String -> Either String [(Int, Int)]
parseData text = do
values <- mapM (mapM readEither . words) . lines $ text
mapM toPoint values
main = do
points <- fmap parseData getContents
case points of
Right ps -> print $ meeting_point ps
Left err -> putStrLn $ "Error: " ++ err

Resources