2

First of all I'm very new to haskell and functional programming in general, so there might (will) be some very dumb mistakes in my code.

I'm trying to replace a few characters in a string with one or more different characters without using any libraries. The string could look like this "w1w1w8/w7w1w1//w". I want to replace every number greater than 1 with the corresponding amount of ones and the '/' with ten ones.

After reading a few similar posts, I came up with this:

replace x = 
    let 
        repl '/' = "1111111111"
        repl '9' = "111111111"
        repl '8' = "11111111"
        repl '7' = "1111111"
        repl '6' = "111111"
        repl '5' = "11111"
        repl '4' = "1111"
        repl '3' = "111"
        repl '2' = "11"
    in  map repl x

Well, it doesn't work and I would appreciate some input on this or even a way to achieve my goal. Thanks in advance.

1
  • 2
    Hello and welcome to Stackoverflow. This is not so bad for a first question, but if you run into problems you need a more detailed description than "Well, it doesn't work"; Your question details should say what you want, what you did and what you observed (and how it is different from what you want). Commented Feb 2, 2018 at 14:18

2 Answers 2

4

First of all, we can simplify the repl function by using replicate:

import Data.Char(isDigit, digitToInt)

replace x = map repl x
    where repl '/' = "1111111111"
          repl x | isDigit x && xi > 1 = replicate xi '1'
              where xi = digitToInt x
          repl x = [x]

Here repl this is a function that transforms a Char to a String. For the slash character, it returns a String of ten '1's, for a character that isDigit x, then we replicate '1', xi times. The last line means that all other characters x, are converted to a string [x].

If we now use map, we will convert a [String] into a [[String]]. This is of course not what we want. But we can use concat :: [[a]] -> [a] to concatenate the sublists together:

import Data.Char(isDigit, digitToInt)

replace x = concat (map repl x)
    where repl '/' = "1111111111"
          repl x | isDigit x && xi > 1 = replicate xi '1'
              where xi = digitToInt x
          repl x = [x]

We can also use concatMap :: (a -> [b]) -> [a] -> [b], and use an eta reduction to remove the x parameter from your replace function:

import Data.Char(isDigit, digitToInt)

replace = concatMap repl
    where repl '/' = "1111111111"
          repl x | isDigit x && xi > 1 = replicate xi '1'
              where xi = digitToInt x
          repl x = [x]

This then produces for your sample input:

Prelude Data.Char> replace "w1w1w8/w7w1w1//w"
"w1w1w111111111111111111w1111111w1w111111111111111111111w"
Sign up to request clarification or add additional context in comments.

3 Comments

Your replace is "simpler" in the sense of denser when compared to OPs repl; but it's not going to be "simpler" in the sense of "easy to understand" for a complete beginner.
Thank you so much! That's really helpful and a better answer than I could have ever hoped for.
It's true that it is not super easy to understand, but I think I get most of it and will research the things I do not completely understand.
3

You have two problems in your code: The first is that you only defined repl for /,9,8,7,6,5,3 and 2. What should happen if you encounter anything that's not one of those things? Whatever the case may be, you will need to add a case for that to your function definition.

The other problem is that what you want in the end is a String, but map is a function that takes a function from a -> b and a list of a [a] and returns a list of b [b]. Your repl function is of type Char -> String, so map repl is of type String -> [String] (instead of String -> String like you want). You'll have to "flatten" the list-of-list to just a list.

There's a prelude function called concat :: [[a]] -> [a] that does this for you; If you don't want to use predefined functions you can try implementing that yourself.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.