Let the allocation of the problematic part of the function begin:
open System open System.Collections.Generic let handleBackspaces textToProcess : string = let stack = Stack<char>() for c in textToProcess do if c = '\b' then stack.Pop() |> ignore else stack.Push c stack |> Seq.rev |> Seq.toArray |> String
This has one mutable variable ( stack ). Whenever you have a variable, you can replace it with the battery value in a recursive function. Here is one way to do this:
open System let handleBackspaces' textToProcess : string = let rec imp acc = function | [] -> acc | '\b'::cs -> imp (acc |> List.tail) cs | c::cs -> imp (c::acc) cs textToProcess |> Seq.toList |> imp [] |> List.rev |> List.toArray |> String
You will notice that I named the battery value for acc . The imp function is of type char list -> char list -> char list , and it corresponds to the incoming char list : if it is empty, it returns the drive; if it has '\b' as the head, it removes the previous char from the battery using List.tail ; and in all other cases, it transfers the first char to the battery and calls itself recursively.
Here's a (hopefully satisfactory) FSI session:
> handleBackspaces' "b\bfoo";; val it : string = "foo" > handleBackspaces' "foo";; val it : string = "foo" > handleBackspaces' "bar\bz";; val it : string = "baz" > handleBackspaces' "bar\b\boo";; val it : string = "boo" > handleBackspaces' "b\bfa\boo";; val it : string = "foo"
Once someone understands how to model something as a recursive function, it should be possible to implement it using a fold instead, as Ryan U Gough points out. Here is one way to do this:
let handleBackspaces'' textToProcess : string = textToProcess |> Seq.fold (fun acc c -> if c = '\b' then acc |> List.tail else c::acc) [] |> List.rev |> List.toArray |> String
Mark seemann
source share