0

I wrote my own recursive definition of a foldLeft and I'd like to use it with this function joinTerminateLeft which takes a list of strings and a terminator and creates a new string with those strings all separated by the terminator.

For example List("a", "b", "c", "d") with terminator ; would end up being a;b;c;d;

Here is my foldLeft which I think is fine but my terminateLeft doesn't work for some odd reason, any idea?

def foldLeft [A,B] (xs:List[A], e:B, f:(B,A)=>B) : B = {
  def auxFoldLeft(xs: List[A], e: B) : B = {
    xs match {
      case Nil => e
      case x::xs => auxFoldLeft(xs, f(e, x))
    }
  }
  auxFoldLeft(xs, e)
}

def joinTerminateLeft (xs : List[String], term : String) : String = {
  def f(s: String, s2: String) : String = s + s2
  xs match {
    case Nil => ""
    case x::xs => x + foldLeft(xs, term, f)
  }
}

When I run joinTerminateLeft with a,b,c,d it stops after B for some reason and outputs the strings c,d but not with the terminator.

Chirlo
  • 5,989
  • 1
  • 29
  • 45
mocode9
  • 229
  • 3
  • 16
  • So this is a practice? Because `mkString(";")` works perfectly fine. – Psidom Jan 23 '17 at 20:43
  • Yes it's for practice. I need to accomplish joinTerminateLeft using my foldLeft without any additional methods besides string concatenation I'm assuming is necessary. – mocode9 Jan 23 '17 at 20:44
  • Plus I don't think `foldLeft` is the proper function for this, because here you don't need an initial value, to join the list as a string. A function with similar signature of `reduce` might be better suited. – Psidom Jan 23 '17 at 20:46
  • It's for a homework assignment so it must be do-able. Most definitely not the best way of doing it, but the way I'm being forced to unfortunately. – mocode9 Jan 23 '17 at 20:47

2 Answers2

1

What happens is that you are using term as a starting value. But e is an accumulator, each iteration adds onto the last. So go through once, and you get ; + b but the next time the accumulator is the value of that so you get |b + c

What you need is a different function. Instead of adding The value to the accumulator, you need to add term to the value, then add that to the accumulator.

def joinTerminateLeft (xs : List[String], term : String) : String = {
  def f(s: String)(s2: String, s3: String) : String = s2 + s + s3
  xs match {
    case Nil => ""
    case x::xs => x + foldLeft(xs, "", f(term))
  }
}
puhlen
  • 8,400
  • 1
  • 16
  • 31
  • Thanks for the suggestion, but if called with a list of only one parameter it doesn't seem to work. assert (joinTerminateLeft (List ("a"), ";") === "a;") This returns just "a" any idea? – mocode9 Jan 23 '17 at 20:57
  • The way it currently is, it will put a delimiter between values, when there is only one value, there is no "in between" space to put a delimeter. If you simply want to enter the value after every string, change your function to put the term at the end of a string instead of the beginning `s2 + s3 +s` And instead of passing only the tail to foldLeft and adding the head on after, simple apply foldLeft to the entire list. – puhlen Jan 23 '17 at 21:00
0

Here is a snippet that works:

def joinTerminateLeft (xs : List[String], term : String) : String = {
    def f(s: String, s2: String) : String = s + term + s2
    xs match {
        case Nil => ""
        case x::xs => x + foldLeft(xs, "", f)
    }
}

The term should only be used inside f. The second parameter of foldLeft is the initialization value which should be empty in this case (reduce or something similar would be more appropriate instead of fold left here).

nmat
  • 7,430
  • 6
  • 30
  • 43