1

I am trying to write a function in haskell that would take an integer and return a concatenated (number of times the input) string

For Instance,

Input: 3

Output: hi1\nhi2\nhi3

main = do 

    let str = func 2 ""
    putStrLn str

func :: Int -> String -> String
func i str = do
        if i>(-1)
            then do
                str ++ "hi" ++ (show i)
                func (i-1) str

        else str

Thanking you!

2
  • func i str = unlines $ map (\j -> str ++ "hi" ++ show j) [1..i] Commented Aug 14, 2016 at 18:24
  • thank you Alec, works :) Commented Aug 14, 2016 at 18:32

3 Answers 3

3

This is a much more idiomatic solution than using if-else

a function that would take an integer and return a concatenated (number of times the input) string

func :: Int -> String -> String
func 0 s = ""
func n s = s ++ func (n - 1) s

main = putStrLn (func 3 "hi")

Output

hihihi
Sign up to request clarification or add additional context in comments.

Comments

2

I wonder if 'logarithmic' solution is faster:

main = putStrLn $mul 7 "Hi"

mul :: Int -> String -> String
mul 0 _ = ""
mul 1 s = s
mul _ "" = ""
mul n s = let
            (q, r) = n `quotRem` 2
            s' = mul q s
    in (if r == 1 then s else "") ++ s' ++ s'

2 Comments

This performs fewer recursive calls, but the cost of s' ++ s' is O(n), which should negate the advantage. I would expect this to use a double amount of memory, if not worse. In the general case, calling ++ with a large left list argument is not a good idea, since that list must be duplicated to produce the result.
There is a much better way to concatenate lists: pack them into functions, combine them with the . operator, and apply [] when done. You can use id to represent empty strings and pack the string s into a function like this: (s ++). It helps because it makes sure only one call to ++ is on the call stack at any given time.
1

The easiest way to make your code "work" (I'll explain the double quotes later) is to call func with the concatenated string as a parameter directly, without intermediate steps:

func :: Int -> String -> String
func i str = do
        if i > (-1)
            then func (i-1) (str ++ "hi" ++ (show i) ++ "\n")       
            else str

I also added the newline character to the output, which means that the last character of the result will be a new line. Therefore it is better to write

let str = func 2 ""
putStr str

That way you'll avoid an extra new line at the end.

I wrote "works" in double quotes in the first sentence, because my code prints

hi2
hi1
hi0

You need to modify func so that the lines are printed in reverse order. Hint: you can store the lines in a list and reverse the list at the end.

P.S. I'm not sure whether zero should be a valid suffix. If not, then you have to change the condition in your if statement.

3 Comments

There is no need for any do notation in the implementation of func.
Thank you kapol :)
using if-else here is pretty bad style

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.