I'm trying to print out a list of integers in this format
[1]
[2]
[3]
So my function takes a list of integers and returns an IO () like so:
import System.IO
printVector :: [Integer] -> IO ()
printVector (x:xs) = putStr("[" ++ show(x) ++ "]" ++ "\n") : printVector xs
But ghc gives me the error:
lin-test.hs:5:22:
Couldn't match expected type `IO ()' with actual type `[a0]'
In the expression:
putStr ("[" ++ show (x) ++ "]" ++ "") : printVector xs
In an equation for `printVector':
printVector (x : xs)
= putStr ("[" ++ show (x) ++ "]" ++ "") : printVector xs
Failed, modules loaded: none.
Now it is my understanding that the function would run through the list, taking the first item 'x' first, and then with : printVector xs it would recursively call the rest of the list applying the same putStr function to each item in the list.
But I think my problem is where I do : printVector xs?
Can anyone point out what i'm doing wrong here?
You need to map over the list but, as these are IO actions, you also need to execute them (as map will return a list of IO action without executing them, see following example).
sequence $ map (putStrLn . show) [1,2,3,4]
There is a function doing that already, it's mapM. So the example can be simplify as :
mapM (putStrLn . show) [1,2,3,4]
Another thing you can do is using mapM_ which uses sequence_ instead and will ignore the result of executing the IO action to each of the elements. Therefore, the return type will be IO () instead of IO [()] (previous example).
mapM_ (putStrLn . show) [1,2,3,4]
Related
I am trying to shuffle a list of any a using random numbers. The reason I ask this here is because I have already made a function and I can't figure out why exactly it isn't working.
pick :: [a] -> IO a
pick xs = do
n <- randomRIO (0, length xs - 1)
return $ xs !! n
shuffle :: [a] -> [IO a]
shuffle ls = do
x <- pick ls
let y = remove x ls
(return x) : shuffle y
-- Remove an element from a list (Only first appearance)
remove :: (Eq a) => a -> [a] -> [a]
remove _ [] = []
remove r (x:xs) = if x == r then xs else x : remove r xs
The error I get:
num.hs:31:10: error:
* Couldn't match type `IO' with `[]'
Expected type: [a]
Actual type: IO a
* In a stmt of a 'do' block: x <- pick ls
In the expression:
do x <- pick ls
let y = remove x ls
(return x) : shuffle y
In an equation for `shuffle':
shuffle ls
= do x <- pick ls
let y = ...
(return x) : shuffle y
|
31 | x <- pick ls
| ^^^^^^^
What doesn't make sense to me is that it says it received a type [a] instead of IO a for pick, but ls is defined as [a]?
If there is something fundamentally wrong with this that I just don't understand, is there another way to shuffle a list in Haskell that is this simple? Preferably without any imports.
What's happening is that the type signature for shuffle implies that its do-block has type [IO a]. This means that the monad for this do-block isn't IO as you intend, but rather the monad instance for lists [], as that's the "outermost" type constructor here. The expression pick ls is therefore required, by the do-block, to have type [t] for some type t, but the type signature for pick implies that pick ls has type IO a for some type a. GHC is complaining that it expected pick ls to have a list type [a] (because of the type of the do-block) but its actual type was IO a (because of the type signature of pick).
I believe the conceptual mistake you've made is that you're thinking of IO as a kind of modifier on a type that makes it IO-friendly. So, if IO a is an a that can be generated using an effectful IO computation, then it must be true that [IO a] is a list of as each of which can be generated using an effectful IO computation. But this is wrong!
Instead, you should think of IO a as an IO action (like a recipe) that, when executed, can produce an a. If you want a list of such as, you don't want a list of actions/recipes, each of which produces a single a (i.e., you don't want [IO a]). Instead, you want a single action/recipe that produces a list of as, so you want an IO [a].
So, shuffle should have type signature:
shuffle :: [a] -> IO [a]
Making this change will result in another error for the last expression:
(return x) : shuffle y
The issue here comes from the same conceptual mistake: you're taking a (trivial) action/recipe for generating x and trying to create a list of actions/recipes (though now shuffle y isn't a list anymore, so there's a type mismatch). Instead, you want to replace this with:
xs <- shuffle y -- use `shuffle y :: IO [a]` action to get `xs :: [a]`
return (x:xs) -- make an action to return the whole list (type `IO [a]`)
You'll also find you need to add an Eq a constraint to shuffle because it's required to invoke remove; also, this will hang unless you properly handle the empty list case. The final version of shuffle would be:
shuffle :: (Eq a) => [a] -> IO [a]
shuffle [] = return []
shuffle ls = do
x <- pick ls
let y = remove x ls
xs <- shuffle y
return (x:xs)
and that should work:
> shuffle [1..10]
[6,8,7,2,5,10,1,9,4,3]
You probably are looking for a function like:
shuffle :: [a] -> IO [a]
shuffle [] = return []
shuffle ls = do
x <- pick ls
fmap (x:) (shuffle (remove x ls))
You thus first pick an element from ls and then you recurse on the list of the list. Then we can return a list (x:xs).
The above can made more elegant. I leave this as an exercise. It is for example usually not a good idea to calculate the length of a list each iteration, since that makes the algorithm O(n2). Furthermore you might want to rewrite pick as a function that returns the item and the list after removal.
I'm new at haskell and I'm trying to print the elements of a list in a same line . For example:
[1,2,3,4] = 1234
If elements are Strings I can print it with mapM_ putStr ["1","2","3","\n"]
but they aren't.. Someone knows a solution to make a function and print that?
I try dignum xs = [ mapM_ putStr x | x <- xs ] too buts don't work ..
You can use show :: Show a => a -> String to convert an element (here an integer), to its textual representation as a String.
Furthermore we can use concat :: [[a]] -> [a] to convert a list of lists of elements to a list of elements (by concatenating these lists together). In the context of a String, we can thus use concat :: [String] -> String to join the numbers together.
So we can then use:
printConcat :: Show a => [a] -> IO ()
printConcat = putStrLn . concat . map show
This then generates:
Prelude> printConcat [1,2,3,4]
1234
Note that the printConcat function is not limited to numbers (integers), it can take any type of objects that are a type instance of the Show class.
I am trying to print list with comma.
I have list like ["1","2","3"] and I want to print 1,2,3
How can I do that?
I tried:
printList xs = mapM_ (\(a) -> do
putStr a
putStr (",")) xs
But I dont know how to remove the last comma.
You can use intercalate. It'll insert the comma between each element of the list and concatenate the resulting list of strings to turn it into a single string.
import Data.List
toCommaSeparatedString :: [String] -> String
toCommaSeparatedString = intercalate ","
ghci> toCommaSeparatedString ["1","2","3"]
"1,2,3"
This is a bit of an XY problem: as Benjamin Hodgson shows, you’re better off turning your list into a string, and then printing that – you want as much of your logic outside of the IO monad as possible.
But of course, even if your question is somewhat in the wrong direction from the start, it has an answer! Which is that, for example, you could write this:
printList :: [String] -> IO ()
printList [] = return ()
printList [x] = putStr x
printList (x:xs) = do
putStr x
putStr ","
printList xs
Benjamin’s answer is better. But this one might elucidate IO monad code and do-notation a bit more.
Currently working with Haskell on a function that takes a String in parameters and return a list of (Char, Int) The function occur works with multiple type and is used in the function called word.
occur::Eq a=>a->[a]->Int
occur n [] = 0
occur n (x:xs) = if n == x
then 1 + occur n xs
else occur n xs
word::String->[(String,Int)]
word xs = [(x,y) | x<-head xs, y<-(occur x xs)]
Get me this error
ERROR "file.hs":31 - Type error in generator
*** Term : head xs
*** Type : Char
*** Does not match : [a]
What am I doing wrong ? How can I make this code run properly , type-wise ?
The problem is you say that xs has type String, so head xs has type Char, and then you try to iterate over a single Char, which can't be done. The a <- b syntax only works when b is a list. You have the same problem in that y <- occur x xs is trying to iterate over a single Int, not a list of Int. You also had a problem in your type signature, the first type in the tuple should be Char, not String. You can fix it with:
word :: String -> [(Char, Int)]
word xs = [(x, occur x xs) | x <- xs]
Here we loop over the entire string xs, and for each character x in xs we compute occur x xs.
I would actually recommend using a slightly stronger constraint than just Eq. If you generalize word (that I've renamed to occurrences) and constrain it with Ord, you can use group and sort, which allow you to keep from iterating over the list repeatedly for each character and avoid the O(n^2) complexity. You can also simplify the definition pretty significantly:
import Control.Arrow
import Data.List
occurrences :: Ord a => [a] -> [(a, Int)]
occurrences = map (head &&& length) . group . sort
What this does is first sort your list, then group by identical elements. So "Hello, world" turns into
> sort "Hello, world"
" ,Hdellloorw"
> group $ sort "Hello, world"
[" ", ",", "H", "d", "e", "lll", "oo", "r", "w"]
Then we use the arrow operator &&& which takes two functions, applies a single input to both, then return the results as a tuple. So head &&& length is the same as saying
\x -> (head x, length x)
and we map this over our sorted, grouped list:
> map (head &&& length) $ group $ sort "Hello, world"
[(' ',1),(',',1),('H',1),('d',1),('e',1),('l',3),('o',2),('r',1),('w',1)]
This eliminates repeats, you aren't having to scan the list over and over counting the number of elements, and it can be defined in a single line in the pointfree style, which is nice. However, it does not preserve order. If you need to preserve order, I would then use sortBy and the handy function comparing from Data.Ord (but we lose a nice point free form):
import Control.Arrow
import Data.List
import Data.Ord (comparing)
occurrences :: Ord a => [a] -> [(a, Int)]
occurrences = map (head &&& length) . group . sort
occurrences' :: Ord a => [a] -> [(a, Int)]
occurrences' xs = sortBy (comparing ((`elemIndex` xs) . fst)) $ occurrences xs
You can almost read this as plain English. This sorts by comparing the index in xs of the first element of the tuples in occurrences xs. Even though elemIndex returns a value of type Maybe Int, we can still compare those directly (Nothing is "less than" any Just value). It simply looks up the first index of each letter in the original string and sorts by that index. That way
> occurrences' "Hello, world"
returns
[('H',1),('e',1),('l',3),('o',2),(',',1),(' ',1),('w',1),('r',1),('d',1)]
with all the letters in the original order, up to repetition.
This may be a silly question, but I'm very new to Haskell. (I just started using it a couple of hours ago actually.)
So my problem is that I have a list of 4 elements and I need to print two on one line and two on a new line.
Here's the list:
let list1 = ["#", "#", "#", "#"]
I need the output to look like this:
##
##
I know that i could use the following to print every element on a new line:
mapM_ putStrLn list1
but I'm not sure how to adapt this for only printing part of the list on a new line.
You want something like Data.Text.chunksOf for arbitrary lists, which I've never seen anywhere so I always reimplement it.
import Data.List (unfoldr)
-- This version ensures that the output consists of lists
-- of equal length. To do so, it trims the input.
chunksOf :: Int -> [a] -> [[a]]
chunksOf n = unfoldr (test . splitAt n) where
test (_, []) = Nothing
test x = Just x
Then we can take your [String] and turn it into [[String]], a list of lists each corresponding to String components of a line. We map concat over that list to merge up each line from its components, then use unlines to glue them all together.
grid :: Int -> [String] -> String
grid n = unlines . map concat . chunksOf n
Then we can print that string if desired
main :: IO ()
main = putStrLn $ grid 2 list1
Edit: apparently there is a chunksOf in a fairly popular library Data.List.Split. Their version is to my knowledge identical to mine, though it's implemented a little differently. Both of ours ought to satisfy
chunksOf n xs ++ chunksOf n ys == chunksOf n (xs ++ ys)
whenever length xs `mod` n == 0.
You can do:
mapM_ putStrLn [(take 2 list1), (drop 2 list1)]
where take and drop return lists with the expected number of elements. take 2 takes two elements and drop 2 drops the first two elements.
Looking at tel link Data.List.Split, another solution can be built on using chop.
Define as follow into the lib,
chop :: ([a] -> (b, [a])) -> [a] -> [b]
chop _ [] = []
chop f as = b : chop f as'
where (b, as') = f as
Then following's simeon advice we end with this one liner,
let fun n = mapM_ putStrLn . chop (splitAt n)
chop appears to be a nice function, enough to be mentioned here to illustrate an alternative solution. (unfoldr is great too).
Beginner attempt:
myOut :: [String] -> IO ()
myOut [] = putStr "\n"
myOut (x:xs) =
do if x=="#"
then putStrLn x
else putStr x
myOut xs
ghci>myOut ["#", "#", "#", "#"]
##
##
ghci>