开发者

Getting started with strings in Haskell

I need to write a function that takes a string of gggggggeeeeetttttt and can count how many times the letter repeats and o开发者_Python百科utput as g7e5t6.

I've only just started Haskell so not really sure at all where to start.


The function group will group together identical elements in a list. Since a string is a list of characters, we have:

group "ggggeeetttt" = ["gggg","eee","tttt"]

To get the letter, we can use map head, since head takes the first element of a string (or any list):

map head ["gggg","eee","tttt"] = ['g','e','t']

Now, we want to know how many elements there are in each substring. This can be done using map length:

map length ["gggg","eee","tttt"] = [4,3,4]

Let's turn these numbers back into strings:

map show [4,3,4] = ["4","3","4"]

Now we need to combine the original list and length list somehow. We can do this as follows:

zipWith (:) ['g','e','t'] ["4","3","4"]

zipWith will apply the specified function to paired elements in the two lists. Here I've used (:), which adds an element to the start of the list.

This gives you all the building blocks you need to do what you want. For example, this should work, although I haven't tested it:

f s = concat $ zipWith (:) letters lengths
    where
        groups  = group s
        letters = map head groups
        lengths = map (show . length) groups


Variant with comprehensions, imo a bit prettier (considering previous explanations just code):

ghci> let s = "gggggggeeeeetttttt"
ghci> putStrLn $ concat [head g: show (length g) | g <- group s]
g7e5t6


The best way to start, is to figure out your problem. I would suggest the following method:

  1. Split the string into substrings of equal characters. So, you need a function which takes a String and returns, a list of strings ([String]).
    Example: splitStr "gggggggeeeeetttttt" should return ["ggggggg","eeeee","tttttt"]
    Happily, the module Data.List already provides such a function, it's named group.
  2. Calculate the number of repetitions and the letter which is repeated. The number of repetition is simply the length of the sublist, use length for that.
  3. Get the repeated character and stick it in front of the number of repetitions. For the repeated character, we may use any one of the list, we take the first one. To calculate the first element of a list (aka string), you can use head. Eg. head "abc" yields 'a'.
    To stick this in front of the length, you can use a small helper function and show, which turns most stuff into a string. Our helper looks like this: makeRepetitions string = head string : show (length string). : aka cons adds an element to the front of a list.
  4. Apply the helper of step (3) to all elements of the list of string in (1). We use map for that. map applies a function to a list of values and returns the list of results
  5. concat the sublists together to your result. We can use concat for this. Actually, we can combine (4) and (5) using concatMap. This function maps a function to a list of values and concats the results - just as we want it.

Now, your code looks like this:

import Data.List

runlength :: String -> String
runlength string = concatMap makeRepetitions (group string)) where
  makeRepetitions string = head string : show (length string)

Because that much brackets are annoying, Haskellers often use ..The dot combines two functions to create a new one. You can think of f = functionA . functionB is equal to f x = functionA (functionB x). Using the dot, we can reformat the program a bit:

import Data.List

runlength :: String -> String
runlength = concatMap makeRepetitions . group where
  makeRepetitions string = head string : show (length string)

IMO, This representation is more readable. You can see runlength as a pipeline. First apply group, then we use concatMap to map makeRepetitions onto the input and concat the results.


Abuse of arrows and pointfree :)

f = group >>> concatMap (head &&& (show . length) >>> uncurry (:))

And here's with applicative:

f = concatMap ((:) <$> head <*> (show . length)) . group
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜