1

I am trying to figure out how I can recursively define a function while also calling a second function at one of the original integer max values. I don't want to add another integer input however I want to call the second function with the integer from the first function (but only once) I would happily also shorten this down into 1 function if that's better/possible

testFunction::Int->String
testFunction s 
 |s == 0 = ""
 |otherwise = "abc" ++ testFunction (s-1) ++ testFunction2 s

testFunction2::Int->String
testFunction2 s
 |s == 0 = "" 
 |otherwise = testFunction2 (s-1)++"cba"

For example, this will call testFunction recursively and then because it does this it will call testFunction2 multiple times with s-1 in the main function. I only want the content of testFunction2 to be called once and only with the initial value of S without adding any other int inputs. Say I called 'testFunction 2' it currently outputs 'abcabccbacbacba', however I only want cba outputted twice so I really want 'abcabccbacba' Thank you for the help :)

2
  • 1
    Your "but only once" sounds like you don't want testFunction to be recursive, but have it call another function recursively. testFunction ... = "abc" ++ helper (s-1) ++ testFunction2 s, where helper is the recursive one. Commented Dec 1, 2020 at 18:52
  • Another way to define this recursively with a single function is by thinking of the recursion as proceeding in the middle of the resulting string, concatenating strings on both the left and right sides at each step: f s | s <= 0 = "" | otherwise = "abc" ++ f (s - 1) ++ "cba", so f on increasing values of s would go: f 0 = [], f 1 = "abc" ++ [] ++ "cba", f 2 = "abc" ++ ("abc" ++ [] ++ "cba") ++ "cba", and so on. (This is pretty inefficient because it repeatedly appends strings, so in real code I’d use replicate.) Commented Dec 1, 2020 at 23:48

2 Answers 2

2

The usual way of doing this sort of thing is to break the function up into some non-recursive "top-level" processing and a recursive helper, usually defined in a where clause and given a generic name like go or step or loop.

So, you might write:

testFunction :: Int -> String
testFunction s
  | s == 0 = ""
  | otherwise
    -- here's the top-level processing
    = "abc" ++ go (s-1) ++ testFunction2 s
  where
    -- here's the recursive helper
    go s | s == 0 = ""
         | otherwise = "abc" ++ go (s-1)

In this example, this results in some repeated code. You can refactor to remove some of the duplication, though it may be difficult to remove all of it (e.g., the s == 0 handling):

testFunction :: Int -> String
testFunction s
  | s == 0 = ""
  | otherwise = go s ++ testFunction2 s
  where
    go s | s == 0 = ""
         | otherwise = "abc" ++ go (s-1)
Sign up to request clarification or add additional context in comments.

Comments

1

Your function looks like an equivalent of

testFunction s = concat (replicate s "abc") ++
                 concat (replicate (s*(s+1)`div`2) "cba")

and you apparently want

testFunction s = concat (replicate s "abc") ++ 
                 concat (replicate s "cba")

So, there it is, shortened down into one function. But it's not recursive (it's not clear to me if that's a hard requirement here, or not).

It could also be written

 = concat (replicate s "abc"  ++  replicate s "cba")
 = concat $ concatMap (replicate s) ["abc", "cba"]
 = ["abc", "cba"] >>= replicate s >>= id

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.