0

I have a recursive function and I want one execute some statement only for the outermost call to the function. How do I achieve this functionality?

func fact(n int) int {
   if n == 0 {
      return 1
   }
   fact := n * fact(n-1)
   if outer_most{
       fmt.Printf(strconv.Itoa(n))
   }
   return fact 
}
func main() {
  fact(4)
}

This should print only 4

4 Answers 4

1

To answer the question itself: if for some reason you really want to run something that is only for outermost func call and don't want to change api, Golang has a runtime lib for that. You may do it as:

package main

import (
    "fmt"
    "runtime"
    "strconv"
)

func outer_most() bool {
    pc:=make([]uintptr,2)
    runtime.Callers(2,pc) //skip: 1 - runtime.Caller, 2 - outer_most itself
    return runtime.FuncForPC(pc[0])!=runtime.FuncForPC(pc[1]) // test if the caller of the caller is the same func, otherwise it is the outermost
}

func fact(n int) int {
   if n == 0 {
      return 1
   }
   fact := n * fact(n-1)
   if outer_most() {
       fmt.Printf(strconv.Itoa(n))
   }
   return fact 
}

func main() {
  fact(4)
}

playground: https://play.golang.org/p/ro1ZOn6yIR7 It is no good practice, but solve the question most straightfowardly.

Note: Use a global variable is very likely to cause glitches. You need to set it every time you call the func, and if there is concurency, data race would be involved.

And if you are unconfortable with the fact that the extra bool argument get allocated every recursive call (which could be countless time), you may look at @Adrian 's answer or wrap it as a method of a bool.

Sign up to request clarification or add additional context in comments.

Comments

1

You could pass something like a depth that gets incremented at each call. Eg:

func fact(depth int, n int) int {
   if n == 0 {
      return 1
   }
   fact := n * fact(depth + 1, n-1)
   if depth == 0 {
       fmt.Println(fact)  // I assume you meant to print fact here.
   }
   return fact 
}
func main() {
  fact(0, 4)
}

If this is really your use case, you're much better off doing:

func fact(n int) int {
  if n == 0 {
     return 1
  }
  return n * fact(n-1)
}
func main() {
  fmt.Println(fact(4))
}

Comments

1

Answer to edited question:

You can use he second pattern below again:

func fact(n int, outerMost bool) int {
   if n == 0 {
      return 1
   }
   fact := n * fact(n-1, false)
   if outerMost {
       fmt.Printf(strconv.Itoa(n))
   }
   return fact 
}

func main() {
    fact(4, true)
}

Again, you can use closures or helper functions to clean this up.

Original answer:

Try using a global variable:

var outerMost bool = true

func fact(n int) int {
    if outerMost {
        fmt.Printf(strconv.Itoa(n))
        outerMost = false
    }
    if n == 0 {
       return 1
    }
    return n * fact(n-1)
}

func main() {
    fact(4)
}

There are other ways to achieve this. For example, you can use similar technique with closures as well. Or add another parameter to fact:

func fact(n int, outerMost bool) int {
    if outerMost {
        fmt.Printf(strconv.Itoa(n))
        outerMost = false
    }
    if n == 0 {
       return 1
    }
    return n * fact(n-1, outerMost)
}

func main() {
    fact(4, true)
}

1 Comment

I posted question different than what I needed. Sorry about that. Please have a look at the edited question.
1

A simple anonymous function is probably the cleanest, as it does not add a parameter, complicating the API for external callers just to implement internal logic.

func fact(n int) int {
    var facto func(n int) int
    facto = func(n int) int {
        if n == 0 {
            return 1
        }
        fact := n * facto(n-1)
        return fact
    }
    n = facto(n)
    fmt.Printf("%d", n)
    return n
}

This achieves the same functionality, but the caller doesn't have to know to pass an additional bool or int value that's irrelevant to it. Full example here: https://play.golang.org/p/7vHwPDN2_FL

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.