The below code gives back a list of String but I want it work on multiple cases. The problem is that I can't create the same exact result with recursion.
The program gives back the following result:
replaceTabs 6 ["\thello world"]
=> [" hello world"]
Now this should work with a longer list like:
replaceTabs 6 ["asd dsa","\thello world"]
=> ["asd dsa"," hello world"]
Simple concat doesn't work, because it will give back undefined pattern.
replaceTab' :: Int -> [[Char]] -> [Char]
replaceTab' n [[x]] =
if x == '\t' then replicate n ' '
else [x]
replaceTabs :: Int -> [String]-> [String]
replaceTabs n [""] = [""]
replaceTabs n (x:xs) = (return . concat $ [replaceTab' n [a] | a <- (map (:[]) (x))])
This
replaceTab' :: Int -> [[Char]] -> [Char]
is the same as,
replaceTab' :: Int -> [String] -> String
What you should focus on is implementing a function,
replaceTab :: Int -> String -> String
which "fixes" a single String. Then replaceTabs is simply,
replaceTabs :: Int -> [String] -> [String]
replaceTabs n = map (replaceTab n)
Related
I am trying to run the Hopscotch practice exercise in Haskell and I am getting this error when compiling it. Would appreciate any help.
I checked the parameters and the output and they seem correct.
THIS IS THE ERROR MESSAGE:
Histogram1.hs:11:16: error:
* Couldn't match type `[Int] -> String' with `[Char]'
Expected type: String
Actual type: [Int] -> String
* Probable cause: `(.)' is applied to too few arguments
THIS IS THE HASKELL CODE:
module Histogram where
import qualified Data.Map as M
--- Type Aliases
type Count = Int
type Counts = M.Map Int Count
type Indices = [Int]
histogram :: [Int] -> String
histogram xs = histogram' . toCounts
where
histogram' :: Counts -> String
histogram' xs =
let (maxs, xs') = trim xs
in if null maxs
then footer
else asterisks maxs ++ histogram' xs'
footer :: String
footer = unlines ["=========="
, "0123456789"
]
toCounts :: [Int] -> Counts
toCounts = foldr insertOrAdjust M.empty
asterisks :: [Int] -> String
asterisks ns = map (\n -> if n `elem` ns then '*' else ' ') [0..9] ++ "\n"
The issue is in this line
histogram xs = histogram' . toCounts
it should either be
histogram xs = histogram' $ toCounts xs
or
histogram = histogram' . toCounts
What you wrote was function composition which yields [Int] -> String but then you have declared another variable.
How to draw lists of characters from a string?
For example, for a string "abcdefghi", return three strings "adg" "deh" "cfi".
for the first string, it's the 1st, n+1th and n+2th characters from the original string, n is the number of strings to generate.
Two solutions:
First: cryptic and short
drawlist :: Int -> String -> [String]
drawlist n s = [map fst $ filter snd $ zip str [mod c n == i | c<-[0..] ] | i <- [0..(n-1)]]
Second: long and maybe clearer
initlist :: Int -> [String]
initlist 0 = []
initlist n = "":(initlist (n-1))
addtonth :: [String] -> Int -> Char -> [String]
addtonth (x:xc) 1 c = (x++[c]):(addtonth xc 0 c)
addtonth (x:xc) i c = x:(addtonth xc (i-1) c)
addtonth [] i c = []
drawlist' :: Int -> String -> Int -> [String] -> [String]
drawlist' n (x:xs) i s = drawlist' n xs (mod (i+1) n) $ addtonth s (i+1) x
drawlist' n [] i s = s
drawlist :: Int -> String -> [String]
drawlist n s = drawlist n s 0 $ initlist n
Test:
Prelude> str = "abcdefghi"
Prelude> drawlist 2 str
["acegi","bdfh"]
Prelude> drawlist 3 str
["adg","beh","cfi"]
Prelude> drawlist 4 str
["aei","bf","cg","dh"]
Prelude> drawlist 5 str
["af","bg","ch","di","e"]
I am writing some code that creates a histogram based on the values in a list of tuples.
The list looks like this:
[("her",4),("she",2),("friend",1)]
This is my code so far:
-- creates a histogram string of each tuple
makeHistogramRow :: (String, Int) -> String
makeHistogramRow (str, int) = replicate int '*' ++ " -> " ++ str ++ "\n"
-- creates a histogram for each tuple in the list
makeHistogram :: [(String, Int)] -> String
makeHistogram (str, int) = concat (map makeHistogramRow (str, int))
main = do
putStrLn $ show $ makeHistogram [("her",4),("she",2),("friend",1)]
I am trying to map each value in the tuple to the
makeHistogramRow
function but it doesnt seem to be working, i know im missing an anonymous function or something but i cant seem to figure it out...
The output should look like this:
**** -> her
** -> she
* -> friend
Does anyone know what im missing? Thanks
As mentioned in comments,
makeHistogram :: [(String, Int)] -> String
makeHistogram (str, int) = concat (map makeHistogramRow (str, int))
will not type check because (str,int) is a pattern of type (a,b) rather than [(a,b)].That is, it is a tuple, not a list of tuples. To make your code work you could say
makeHistogram :: [(String, Int)] -> String
makeHistogram ls = concat (map makeHistogramRow ls)
or, better
makeHistogram :: [(String, Int)] -> String
makeHistogram ls = concatMap makeHistogramRow ls
or even better
makeHistogram :: [(String, Int)] -> String
makeHistogram = concatMap makeHistogramRow
This question already has an answer here:
In Haskell how can you multiply a list of string? [closed]
(1 answer)
Closed 5 years ago.
I'm trying to write a function that takes a String and an Int and returns that every element of string is multiplyed "int" times. That is:
duplicate :: String -> Int -> String
duplicate " abc " 2
the output should be
Main >> " aabbcc "
You should look at the following functions in Prelude:
map :: (a -> b) -> [a] -> [b] to "do someting" with every element of a list
replicate :: Int -> a -> [a] to replicate an item n times
concat :: Foldable t => t [a] -> [a] to concat, e.g a list of lists into a single list
Actually there are many ways to achieve what you want:
You could either do it recursively...
duplicate :: String -> Int -> String
duplicate (c:s) n
| s == [] = replicate n c
| otherwise = replicate n c ++ duplicate s n
... or as the others pointed out, by using some of the Prelude functions ...
duplicate' :: String -> Int -> String
duplicate' s n = concatMap (replicate n) s
... or by using fold ...
duplicate'' :: String -> Int -> String
duplicate'' s n = foldr1 (\c acc -> replicate n c ++ acc) "" s
You would use these functions like:
main :: IO ()
main = do
print $ duplicate "abc" 3 -- "aaabbbccc"
print $ duplicate' "abc" 3 -- "aaabbbccc"
print $ duplicate'' "abc" 3 -- "aaabbbccc"
I am making a frame that print a character frame around a character as I show below.
This is example of frame. Example to understand what I actual frame is and What i am want from all these function right, left, up and down:
a is list of string that is A.
Main> showMatDownAttach '#' a
aaaaa
a a
a a
aaaaaaa
a a
a a
a a
#########
Main> showMatDownAttach '#' a
aaaaa
a a
a a
aaaaaaa
a a
a a
a a
#########
I also have for right and left. Now I want to make a function that can combine all of them in one function. How I can do this?
a = [" aaaaa "," a a "," a a "," aaaaaaa "," a a "," a a "," a a "]
--badar = putStr( concat (map (++ "\n")(letter 'a')))
--showMat :: Char -> IO()
--showMat ch = putStr (concat ( map(++ "\n") (letter 'a')))
replicateIt :: Int -> [Char] -> [Char]
replicateIt x ls=take x (cycle ls)
--repeatIt :: Int -> [Char] -> [[Char]]
repeatIt num []=[]
repeatIt num (x:sx)= replicateIt num [x]:(repeatIt num sx)
hStretchChar :: Int -> Char -> String
hStretchChar i ch = replicate i ch
hStretchString :: Int -> String -> String
hStretchString i sts = concat ( map ( hStretchChar i) sts)
hStretchListOfString :: Int -> [String] -> [String]
hStretchListOfString i stlist = map (hStretchString i ) stlist
vStretchString :: Int -> String -> String
vStretchString i str = concat (replicate i (str ++ "\n"))
vStretchListOfString :: Int -> [String] -> [String]
vStretchListOfString i strList = map (vStretchString i) strList
stretch :: Int -> Int -> [String] -> [String]
stretch i j strList = vStretchListOfString i (hStretchListOfString j strList)
showMat' :: [String] -> IO()
showMat' strList = putStr (concat (stretch 1 1 strList))
--Left Attach Character
leftattach :: Char -> [String] -> [String]
leftattach a strlist = map ( a: ) strlist
showMatCharAttachLeft :: Char -> [String] -> IO()
showMatCharAttachLeft a strList = putStr (concat (stretch 1 1 ( leftattach a strList)))
charToString :: Char -> String
charToString a = a:[]
--Right Attach Character
rightattach :: Char -> [String] -> [String]
rightattach a strlist = map (++(charToString a)) strlist
showMatCharAttachRight :: Char -> [String] -> IO()
showMatCharAttachRight a strList = putStr (concat (stretch 1 1 ( rightattach a strList)))
--Up Attach Character
upattach :: Char -> [String] -> [String]
upattach a strList = take (length (head strList)) (cycle (charToString a)) : strList
showMatUpAttach :: Char -> [String] -> IO()
showMatUpAttach a strList = putStr (concat (stretch 1 1 (upattach a strList)))
--Down Attach Character
downattach :: Char -> [String] -> [String]
downattach a strList = strList ++ listOfCharTolistOfString (take (length (head strList)) (cycle (charToString a)))
showMatDownAttach :: Char -> [String] -> IO()
showMatDownAttach a strList = putStr (concat (stretch 1 1 (downattach a strList)))
--test0 a strList = listOfCharTolistOfString (take (length (head strList)) (cycle (charToString a)))
listOfCharTolistOfString :: [Char] -> [String]
listOfCharTolistOfString a = a:[]
IO () is a very opaque type; there isn't much you can do with it, and there isn't any meaningful way to convert it to [String]. Once you're in IO, you can't get out of it.
Generally in Haskell you write most of your code without using IO. Here's a solution to the problem to demonstrate what I mean. Notice that all of the "frame" code is defined with pure functions, and IO doesn't get introduced until main at the very end.
import Data.Foldable (traverse_)
import Data.List (repeat)
frame1 :: a -> [a] -> [a]
frame1 f xs = [f] ++ xs ++ [f]
frame2 :: a -> [[a]] -> [[a]]
frame2 f grid = frame1 edge $ frame1 f <$> grid
where edge = take (width grid + 2) $ repeat f
width :: [[a]] -> Int
width [] = 0
width (x:_) = length x
a :: [[Char]]
a = [ " aaaaa "
, " a a "
, " a a "
, " aaaaaaa "
, " a a "
, " a a "
, " a a "
]
main :: IO ()
main = traverse_ putStrLn $ foldr frame2 a "* &"
Output:
***************
* *
* &&&&&&&&&&& *
* & aaaaa & *
* & a a & *
* & a a & *
* & aaaaaaa & *
* & a a & *
* & a a & *
* & a a & *
* &&&&&&&&&&& *
* *
***************
So, IO () encapsulates all side-effects and is not just about console output. So pedantically there is no way to "change IO () to [String]"
With that said, I believe System.Posix.Redirect is what you are looking for. You just want to call showMatDownAttach to capture stdout to get the [String] you want.
A quick Google search reveals a couple more packages to do this as well:
https://hackage.haskell.org/package/io-capture
https://hackage.haskell.org/package/silently
Now doing this is not very idiomatic Haskell and if you have access to showMatDownAttach you'll want to change it to something like what https://stackoverflow.com/a/40701235/111021 suggests. But since you ask this question I believe you already considered that and somehow that's not an option.