AmberL0uise
AmberL0uise

Reputation: 35

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?

Upvotes: 1

Views: 6308

Answers (5)

Aleph0
Aleph0

Reputation: 6084

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

Upvotes: 1

user12457
user12457

Reputation: 191

flatten = mconcat. map (\(c,i) -> [c] ++ show i)

Upvotes: 1

ƛƛƛ
ƛƛƛ

Reputation: 892

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.

Upvotes: 2

Zeta
Zeta

Reputation: 105965

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

Upvotes: 3

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477684

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)

Upvotes: 4

Related Questions