list of Data to String - haskell

So I have a list of Data, I know newtype is currently better but I will add more things to it. I would like to convert a list of Pack to a String.
unpack [Pack ('a','b'), Pack ('c','d') , Pack (' ', 'e') ] = "abcd e"
I was thinking about using a foldl but am stuck trying to figure it out.
data Pack= Pack (Char, Char) deriving ( Show)
unPack:: [Pack] -> String
unpack list = foldr (\Pack (a,b) -> show a + show b -> concat) "" list
Thx for the helping

To pattern-patch on Pack xyz in a lambda, you need to put it in parentheses:
foldr (\(Pack (a,b)) -> ...)
What you wrote would actually parse as two separate arguments
foldr (\(Pack) -> \(a,b) -> ...)
Next, you can't concatenate strings with +, that's for numbers. ++ or <> are for lists / strings.
Then, the -> concat isn't valid syntax. What you want to do is concatenate the remainder of the foldr computation to the shown a and b. That remainder is the second argument of the folding function:
foldr (\(Pack (a,b)) rest -> show a ++ show b ++ rest)
...or shorter,
foldr (\(Pack (a,b)) -> shows a . shows b)

Your Pack type is isomorphic to two-character strings:
pack2String :: Pack -> String
pack2String (Pack (a,b)) = a:[b]
string2Pack :: String -> Pack -- partial, since String isn't limited in length
string2Pack (a:[b]) = Pack (a, b)
(Note that Pack (a,b) already adds an unnecessary level of wrapping; data Pack = Pack Char Char is also isomorphic to Pack (Char, Char).)
As such, you don't actually need foldr; you can use the list monad instead.
unpack :: [Pack] -> String
unpack xs = xs >>= pack2String
If you aren't yet comfortable with monads, you can just use the concatMap function directly:
unpack :: [Pack] -> String
unpack = concatMap pack2String

Related

Haskell giving index for the items in list

In a function I should number the elements of a list, which should return like this: "n: rest of the string"
numberLines :: [String] -> [String]
["asd qwe", "-- Foo", "", "\thello world "]
-> ["1: asd qwe", "2: -- Foo", "3: ", "4: \thello world "]
I'm not allowed to use simple recursion, only higher order functions (if needed)
My problems:
I don't know how to make the counter
I don't know how to put an Int in front of the string ("counter: " ++ "string" will not work)
You can work with zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] that will concurrently enumerate through two lists and produce a list of items where ci is f ai bi for c = zipWith f a b. As first item you can for example feed it an infinite list [1..] and as second the list of lines, so:
numberLines :: [String] -> [String]
numberLines = zipWith f [1..]
where f idx st = …
where you still need to fill in the … parts.
A lot of people want you to use zipWith. While this will give the right answer, it consumes two lists, and so doesn't fully support list fusion, which can only work on one list at a time. Here's an alternative solution that can fully fuse:
numberLines :: [String] -> [String]
numberLines xs = foldr (\st acc idx -> …:acc (idx+1)) mempty xs 1
As in Willem Van Onsem's answer, you'll need to fill in the … part yourself.

Parse String to list of binary tuples

I'm trying to parse a string "A1B2C3D4" to [('A',1),('B',2),('C',3)] in Haskell.
I'm trying to use a map like this map (\[a, b] -> (a :: Char, b :: Int)) x where x is the string.
This is the function signature I need to follow :: String -> [(Char, Int)].
Unfortunately i'm getting type mismatches, can anyone give any hint how to solve this?
I'm in the right direction?
Well, map is really meant for applying a single function to every element of something, one-by-one. Splitting the string how you want requires context (knowing the next letter), so map isn't the best choice here.
However, you said your solution is required to be in terms of map. It can be done, but it's a bit roundabout. I couldn't think of any way to make map split the actual string, but it can certainly be used to transform it to the correct type:
isDigit :: Char -> Bool
isDigit c = elem c ['0'..'9']
split :: String -> [(Char, Int)]
split str = let chars = filter (not . isDigit) str
nums = filter isDigit str
zipped = zip chars nums in
map (\(a, b) -> (a, read [b])) zipped
There's a few problems.
The pattern [a, b] in map (\[a, b] -> ...) x only matches lists of two elements, so the compiler infers that the function \[a, b] -> ... has type [r] -> s for some r and s.
The compiler knows that map has the type (u -> v) -> [u] -> [v], so it unifies u with [r] and v with s to infer the type [[r]] -> [s] for map (\[a, b] -> ...).
This means x must have type [[r]], that is, it must be a list of lists. But you want x to be a String which is a synonym for [Char]. The compiler can't unify [[r]] and [Char], so it objects.
You're attempting to "cast" a to a Char and b to an Int like you would in C, but you can't do that in Haskell. If you want to convert a Char like '1' into the Int 1, you need a different approach, like read, which you can use to convert from a String to an Int.
Here's some advice. Don't use map. Try writing a recursive solution instead.
Start by considering a few cases:
what does myParser "" return?
what does myParser "a1" return?
what does myParser [a,b] return?
what does myParser (a:b:cs) return?
I came up with this but it's really not safe as it doesn't handle incorrect string like "AA11B2C3"!
splitingN :: Int -> [a] -> [[a]]
splitingN _ [] = []
splitingN n l
| n > 0 = take n l : splitingN n (drop n l)
| otherwise = error "uhhhhhh"
tuplify :: String -> (Char, Int)
tuplify a = (head a, read $ tail a)
stringy :: String -> [(Char, Int)]
stringy s = tuplify <$> splitingN 2 s
> stringy "A1B2C3D4" == [('A',1),('B',2),('C',3),('D',4)]
A much nicer way but still not fully safe would be:
stringy :: [a] -> [(a, a)]
stringy [] = []
stringy (a : b : rest) = (a, b) : splitting rest
stringy [a] = error "uhhhhh"
Should really check if a and b from (a : b : rest) are indeed Char & Int. Also this uses recursion and you mentioned using map so might not suffice and it's pretty polymorphic in it's types.
As others have pointed out, you need to understand that map applies the given function over each member of the list. Once you understand that, you will realize that there is no way you can get the conversion you want by applying a function on the existing list.
This leads to realization that once you have a list of "A1", "B2",... then you can take these and convert it using a map function.
I have given the code for function below. The split' function is not safe as it can blow up in lot of cases (expected a string which can be perfectly split into 2 chars). I am also using the function digitToInt, for which you need to import Data.Char. You did say you want no import, in that case you can write your own digitToInt function, look into the library code, it is fairly straightforward.
import Data.Char
split' :: String -> [String]
split' [] = []
split' (x:y:xs) = (x:[y]) : split' xs
convert :: String -> [(Char, Int)]
convert input = map (\s -> (s!!0 , digitToInt(s!!1) )) $ split' input

Haskell, List as input for a function, How?

I've been given the following question in my coursework;
Define a function
flatten :: [(Char,Int)] -> String
that flattens a list of pairs of characters and digits to a string. For example:
flatten [('a',5),('b',4),('c',2)]
"a5b4c2"
flatten [('d',9),('d',3)]
"d9d3"
My problem is that whenever I attempt to define this function i get a type error relating the the [(Char, Int)] input. For example;
Couldn't match type '(Char, Int)' with '[Char]'
Expected type: [[Char]]
Actual type: [(Char, Int)]
I've tried more ways of writing this definition in more ways than I can count, so I don't have any particular code to show, or any particular error ( I kept getting different ones...so many). All i have so far is;
flatten :: [(Char, Int)] -> String
flatten [] = []
i figure my next line should go something like;
flatten ???? = concat (????)
but I have no idea what to put in place of these question marks and Google search/class notes give no examples to follow.
any ideas?
Well it is clear that in the case the list is not empty, it is of the form ((ca,cb):cs) with ca the Char, cb the Int and cs the remainder of the list [(Char,Int)].
In that case we can simply construct a string for that sequence ca:(show cb) with show :: Show a => a -> String we convert an integer to its String counterpart. Next we concatenate the flattening of remainder of the list to that string, so:
flatten ((ca,cb):cs) = ca:(show cb ++ flatten cs)
Or in full:
flatten :: [(Char, Int)] -> String
flatten [] = []
flatten ((ca,cb):cs) = ca:(show cb ++ flatten cs)
First of all, we try to create a String from a (Char, Int). If we can do that we've almost done, since we can do that for all (Char, Int). So let's transform a single (Char, Int):
flattenSingle :: (Char, Int) -> String
flattenSingle (c, i) = c : show i
Now, we need to do that for all entries:
flattenAll :: [(Char, Int)] -> [String]
flattenAll xs = map flattenSingle xs
And last, but not least, we need to concat the [String] (which is a [[Char]]) to a String (which is a [Char]):
flatten :: [(Char, Int)] -> String
flatten xs = concat (flattenAll xs)
And we're done. How did we do that? Well, we've started with a much easier problem, namely how to get a single String from a (Char, Int), and used that to get our result.
Here's everything in a single function:
flatten = concat . map flattenSingle
where
flattenSingle (c, i) = c : show i
Since concat . map f is often used, there's a function for that, called concatMap:
flatten :: [(Char, Int)] -> String
flatten = concatMap flattenSingle
where
flattenSingle (c, i) = c : show i
Let’s think about what goes into flatten and what comes out of it.
flatten, takes a list of pairs of type: (Char, Int) and produces a [Char]; it produces a list from an existing list. Does this ring a bell?
flatten xs = [ c | (char, int) <- xs, c <-[char] ++ show int]
We can sequentially deconstruct each pair in the given list; for each pair, we turn each component into a string so we can concatenate them. Now we have a string for each pair, we just need to take each character out to produce the final string.
flatten = mconcat. map (\(c,i) -> [c] ++ show i)
You might also use foldl to make your intention very clear:
a=[('a',5),('b',4),('c',2)]
f b (x,y)=b++[x]++(show y)
result=foldl f "" a
Or you can make it a one-liner:
Solution 1:
foldl (\b (x,y)->b++[x]++(show y)) "" a
Solution 2:
concat $ map (\(x,y)->[x]++show y) a
Solution 3: (Being more efficient compared to solution 1)
foldr (\(x,y) b->b++[x]++(show y)) "" a

Notation for a recursive call on user defined type [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Iterating through a String and replacing single chars with substrings in haskell
I'm trying to implement a function that looks at a String ([Chars]) and checks for every letter whether this letter should be replaced with another string. For example we might have a [Chars] consisting of "XYF" and rules that says "X = HYHY", "Y = OO", then our output should become "HYHYOOF".
I want to use the following two types which I have defined:
type Letters = [Char]
data Rule = Rule Char Letters deriving Show
My idea is that the function should look something like the following below using guards. The problem is however I can't find any information on how to the recursive call should look like when i want browse through all my rules to see if any of them fits to the current letter x. I hope anyone can give some hints on how the notation goes.
apply :: Letters -> [Rule] -> Letters
apply _ _ = []
apply (x:xs) (Rule t r:rs)
| x /= t = apply x (Rule t rs)
| x == t = r++rs:x
| otherwise =
I would suggest a helper function to check whether a rule matches,
matches :: Char -> Rule -> Bool
matches c (Rule x _) = c == x
and then you check for each character whether there are any matching rules
apply :: Letters -> [Rule] -> Letters
apply [] _ = []
apply s [] = s
apply (c:cs) rules = case filter (matches c) rules of
[] -> c : apply cs rules
(Rule _ rs : _) -> rs ++ apply cs rules
If you try an explicit recursion on rules within apply, it will become too ugly, since you need to remember the full rules list for replacing later characters.
I'd suggest that you learn to do this with generic utility functions. Two key functions that you want here:
lookup :: Eq a => a -> [(a, b)] -> Maybe b. Finds a mapping in an association list—a list of pairs used to represent a map or dictionary.
concatMap :: (a -> [b]) -> [a] -> [b]. This is similar to map, but the function mapped over the list returns a list, and the results are concatenated (concatMap = concat . map).
To use lookup you need to change your Rule type to this more generic synonym:
type Rule = (Char, String)
Remember also that String is a synonym for [Char]. This means that concatMap, when applied to String, replaces each character with a string. Now your example can be written this way (I've changed argument orders):
apply :: [Rule] -> String -> String
apply rules = concatMap (applyChar rules)
-- | Apply the first matching rule to the character.
applyChar :: [Rule] -> Char -> String
applyChar rules c = case lookup c rules of
Nothing -> [c]
Just str -> str
-- EXAMPLE
rules = [ ('X', "HYHY")
, ('Y', "OO") ]
example = apply rules "XYF" -- evaluates to "HYHYOOF"
I changed the argument order of apply because when an argument has the same type as the result, it often helps to make that argument the last one (makes it easier to chain functions).
We can go further and turn this into a one-liner by using the utility function fromMaybe :: a -> Maybe a -> a from the Data.Maybe module (fromMaybe default Nothing = default, fromMaybe default (Just x) = x):
import Data.Maybe
apply rules = concatMap (\c -> fromMaybe [c] $ lookup c rules)
An exercise you can do to complement this is to write your version of all of these utility functions on your own by hand: lookup, concatMap (break it down into concat :: [[a]] -> [a] and map :: (a -> b) -> [a] -> [b]), and fromMaybe. That way you can understand the "full stack" involved in this solution.
My solution is structurally similar to the other ones, but uses monads:
import Control.Monad
import Data.Functor
import Data.Maybe
match :: Char -> Rule -> Maybe Letters
match c (Rule c' cs) = cs <$ guard (c == c')
apply :: Letters -> [Rule] -> Letters
apply cs rules =
[s | c <- cs
, s <- fromMaybe [c] $ msum $ map (match c) rules]
The first monad we're dealing with is Maybe a. It is actually a little bit more, a MonadPlus, which allows us to use msum (which boils down something like [Nothing, Just 2, Nothing, Just 3] to the first "hit", here Just 2).
The second monad is [a], which allows us to use a list comprehension in apply.

Swap characters between strings Haskell

if i say i have two strings or character lists,
list1 = ["c","a","t"]
list2 = ["d","o","g"]
and if i read a string using Input Output "ct" and pass it to the function,the function should return "dg".
Please give me any idea about such a function.
I would consider taking those two lists, zipping them together, use Data.Map.fromList to create a lookup Map, then map over the input String and use the Map to work out what to replace them with.
I'll first assume list1 and list2 have type [Char] (i.e. String), since that's what your text seems to indicate (your code has them as [String]s -- if you really want this, see the generalized version in the addendum).
If you zip the two lists, you end up with a list of pairs indicating how to translate characters. In your example, zip list1 list2 = [('c','d'), ('a','o'), ('t','g')]. We'll call this our lookup list. Now consider the function lookup:
lookup :: Eq a => a -> [(a, b)] -> Maybe b
In our case, we can specialize this to
lookup :: Char -> [(Char, Char)] -> Maybe Char
so we have something that takes a character and a lookup list and returns a substituted character if the input character is in the lookup list (otherwise a Nothing). Now we just need to glue the things we've found together: We essentially need to map \c -> lookup c lookupList (more elegantly written as flip lookup) over the input string while throwing out any characters not found in the lookup list. Well, enter mapMaybe:
mapMaybe :: (a -> Maybe b) -> [a] -> [b]
It does exactly what we want. Now your function can be written as
replace :: String -> String -> String -> String
replace list1 list2 = mapMaybe ((flip lookup) (zip list1 list2))
You'll need to import Data.Maybe.
Addendum, for when you understand the above: Observe how what we did above had nothing to do with the fact that we were working with lists of characters. We could do everything above with lists of any type for which equality makes sense, i.e. for (lists of) any type which is an instance of the Eq typeclass (cf the signature of lookup above). Moreover, we don't have to translate from that type to itself -- for example, each character above could be sent to say, an integer! So really, we can write
replace :: (Eq a) => [a] -> [b] -> [a] -> [b]
replace list1 list2 = mapMaybe ((flip lookup) (zip list1 list2))
and now our function works as long as list1 is a list of something for which equality makes sense. Replacement of characters just becomes a special case.
A quick example:
> replace "cat" "dog" "ct"
"dg"
> replace "cat" [1,2,3] "ct"
[1,3]
For two string you may do as follows:
patt :: String -> String -> String -> String
patt (x : xs) (y : ys) p'#(p : ps)
| p == x = y : patt xs ys ps
| otherwise = patt xs ys p'
patt _ _ [] = []
main :: IO ()
main = do
putStrLn $ patt "cat" "dog" "ct"

Resources