3

I'm trying to concatenate a string with a certain amount of times, but I feel like I've cheated a bit (or at least not actually understood how it's supposed to be done) by using a higher-order function:

let repeat s n = 
String.replicate n s |> printfn "%s"

repeat "a" 10

Obviously gives me "aaaaaaaaaa", but how could I do this without a higher-order function? I feel like it's a very simple problem but I can't seem to wrap my head around it, the F# syntax, or way of thinking, is still troublesome for me.

Left4Cookies
  • 567
  • 2
  • 7
  • 19
  • Well, one aim of functional programming is to use higher order functions... You could for example examine the [source](https://github.com/Microsoft/visualfsharp/blob/master/src/fsharp/FSharp.Core/string.fs#L76) for String.replicate to see what it does. – s952163 Oct 28 '16 at 07:21
  • 4
    You're not giving a function as an argument to repeat or replicate, and they don't output functions either, so there's no higher-order function here. – CodeMonkey Oct 28 '16 at 07:24
  • 1
    @s952163 While I agree with your comment about using higher-order functions, the source for `String.replicate` isn't helpful, since it's using `StringBuilder` internally. A better place to look for the general approach is [`List.replicate`](https://github.com/Microsoft/visualfsharp/blob/master/src/fsharp/FSharp.Core/list.fs#L172-L178). – Mark Seemann Oct 28 '16 at 07:26
  • Yes, indeed. I was trying to hint at the fact that there are a lot of ways to replicate a string. I assume the OP would like to have a recursive solution. – s952163 Oct 28 '16 at 07:31
  • 2
    By the way, this has a nice list of answers: [Multiplying string](http://stackoverflow.com/questions/9112485/multiplying-a-string-in-f). – s952163 Oct 28 '16 at 09:02

2 Answers2

4

If you just want a recursive solution, how about this?

let rec repeat s n =
    match n with
    | _ when n <= 0 -> ""
    | _ -> s + (repeat s (n-1))

repeat "a" 10

or in a more "classic" style with an if-expression:

let rec repeat s n =
    if n <= 0 then
        ""
    else
        s + (repeat s (n-1))

repeat "a" 10
CodeMonkey
  • 4,067
  • 1
  • 31
  • 43
  • 1
    Am I right when I say those are tail-recursive as they don't make any more computations after the recursive call? If so, how would a continuation-based recursive version of it look? I know that it would require an extra argument (let's say `c`) that works as a function, but I'm not quite sure on the exact syntax. Something like adding `(fun res -> c ...)` in the else after the recursive `repeat` call right? – Left4Cookies Oct 28 '16 at 10:11
  • 2
    There is an addition next to the function call.... you can try and check if indeed it is tail recursive or not by repeating a large string a large number of times and see if the stack gets exhausted or not. Another way would be to examine the IL to see if the compiler is optimizing it or not with a tail call. – s952163 Oct 28 '16 at 10:24
  • 2
    That's correct, it's not a tail call. See here: https://blogs.msdn.microsoft.com/fsharpteam/2011/07/08/tail-calls-in-f/ – CodeMonkey Oct 28 '16 at 10:33
  • 2
    @Left4Cookies I added a tail recursive version. The above link by CodeMonkey explains it quite well. Generally (outside of exercises) recursion is not that much used. ymmv. See the [Conclusion](http://codebetter.com/matthewpodwysocki/2009/02/14/fun-with-folds/). – s952163 Oct 28 '16 at 15:07
3

And here's one way using list comprehension and fold, which is the go to function for recursion:

[for i in 1..10 -> "a"] |> List.fold (+) ""

Tail Recursive version

let repeat2 s n =
    let rec loop acc n =
        match n with 
        | _ when n > 0 -> loop (acc + s) (n - 1)
        | _ -> acc
    loop "" n

repeat "oijdfsaoijdoyasjd" 100000 // Process is terminated due to StackOverflowException.
[for i in 1..100000 -> "oijdfsaoijdoyasjd"] |> List.fold (+) "" // no stack overflow
repeat2 "oijdfsaoijdoyasjd"  100000 // no stack overflow

But prepared for massive amounts of gen2 GC and a few min. of runtime.

s952163
  • 6,276
  • 4
  • 23
  • 47