-
Notifications
You must be signed in to change notification settings - Fork 8
[feature request] Support for mutual recursion where the functions have different signatures. #27
Copy link
Copy link
Open
Labels
Description
I'm currently writing a program that utilizes copy-on-write semantics, which means writing a lot code that looks something like this:
class COWList(var v:Int, var n:COWList) {
var shared:Boolean = false
def clone():COWThing = { shared = true; this }
def write(newV:Int = v, newN:COWList = n):COWThing = {
if(shared){ new COWThing(newV, newN) }
else { v = newV; n = newN; this }
}
@tailrec def final addAndFind(test:Int, delta:Int):COWList = {
val nullTail = (n == null)
val newSelf = write(v + delta + (if(nullTail){ 1 } else { 0 }))
if(nullTail){ None }
else if(newSelf.v == test){ Some(newSelf) }
else { newSelf.n.addAndFind(test, newSelf.v) }
}
}The implementation of a method like addAndFind is error prone since it's easy to forget to place newSelf. everywhere it should be used, and is a natural fit for mutual tail recursion, since we can fake this = newSelf by calling a method on newSelf immediately.
@mutualrec def final addAndFind(test:Int, delta:Int):COWList = {
val nullTail = (n == null)
write(v + delta + (if(nullTail){ 1 } else { 0 })).addAndFindPost(test, nullTail)
}
@mutualrec def final addAndFindPost(test:Int, nullTail:Boolean):COWList = {
if(nullTail){ None }
else if(v == test){ Some(newSelf) }
else { n.addAndFind(test, v) }
}
There are definitely some work-arounds here, but none of them are nearly as elegant, and there isn't an intuitive reason why this shouldn't work, since it's essentially a resugaring from something that tailrec was happy with.
Reactions are currently unavailable