Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Function that returns another function

    Hi,
    I'm trying to implement a function in Mata that takes an input n and returns a function that takes in inputs x and returns x^n.
    Since nested functions are not allowed in Mata, I'm struggling to see how to do this. Is there any workaround to this?

    I am using Stata 18.5
    Last edited by Jai Singh; 17 Jul 2024, 19:11. Reason: added version of Stata I use

  • #2
    Originally posted by Jai Singh View Post
    Is there any workaround to this?
    A bit of a kludge, but you could try something like the following. Instead of a function, it returns an object that has the customized function as a public method.

    Mata's class constructors won't allow arguments, and so you'll have to use an initialize() public method to set exponent, n, before delivery. If you want to prevent someone from accidentally (or maliciously) changing the function's exponent after creation, then you should add a trap as shown.
    Code:
    version 18.0
    
    clear *
    
    mata:
    mata set matastrict on
    
    /* First define a class that contains your "nested function" */
    class MyCustomFunction {
        private:
            void new()
            real scalar n, initialized
        public:
            void initialize()
            real scalar fxn()
    }
    void function MyCustomFunction::new() initialized = 0
    void function MyCustomFunction::initialize(real scalar n) {
        if (!initialized) {
            this.n = n
            initialized = 1
        }
        else {
            errprintf("already initialized\n")
            exit(3498)
        }
    }
    real scalar function MyCustomFunction::fxn(real scalar x) return(x^n)
    
    /* then write a simple factory—this is your "function in Mata that takes an
       input n and returns a function that takes in inputs x and returns x^n.") */
    class MyCustomFunction scalar createMyCustomFunction(real scalar n) {
        class MyCustomFunction scalar e
        e.initialize(n)
        return(e)
    }
    
    /* example of usage */
    void function test() {
    
        // create custom function f(x) = x^2
        class MyCustomFunction scalar squareEm
        squareEm = createMyCustomFunction(2)
    
        printf("my custom function 'squareEm(x)' = %1.0f when x = %1.0f\n",
            squareEm.fxn(2), 2)
    
        // create custom function f(x) = x^3
        class MyCustomFunction scalar cubeEm
        cubeEm = createMyCustomFunction(3)
    
        printf("my custom function 'cubeEm(x)' = %1.0f when x = %1.0f\n",
            cubeEm.fxn(2), 2)
    }
    
    test()
    
    end
    
    exit
    If you don't worry about someone's altering the exponent afterward, then you could omit the trap code.

    You can also get around the inability to supply arguments to Mata's class constructors by using a so-called external global as in the following. It calls for working with a pointer to the object in order to avoid its premature instantiation. It's more Rube Goldberg than even the initialize() approach above, but it's an alternative that also avoids accidental or malicious alteration of the function's exponent after creation and delivery.
    Code:
    version 18.0
    
    clear *
    
    mata:
    mata set matastrict on
    
    class MyCustomFunction {
        private:
            real scalar n
            void new()
        public:
            real scalar fxn()
    }
    void function MyCustomFunction::new() {
        pointer(real scalar) scalar n_ptr
        n_ptr = findexternal("pass_n")
        n = *n_ptr
    
        rmexternal("pass_n")
    }
    real scalar function MyCustomFunction::fxn(real scalar x) return(x^n)
    
    pointer(class MyCustomFunction scalar) scalar function createMyCustomFunction(
        real scalar n) {
    
        pointer(real scalar) scalar n_ptr
        rmexternal("pass_n") // (safety)
        n_ptr = crexternal("pass_n")
        *n_ptr = n
    
        transmorphic scalar e
        e = MyCustomFunction()
    
        assert(findexternal("pass_n") == NULL)
    
        return(&e)
    }
    
    void function test() {
    
        // create custom function f(x) = x^2
        pointer(class MyCustomFunction scalar) scalar squareEm
        squareEm = createMyCustomFunction(2)
    
        printf("my custom function 'squareEm(x)' = %1.0f when x = %1.0f\n",
            squareEm->fxn(2), 2)
    
        // create custom function f(x) = x^3
        pointer(class MyCustomFunction scalar) scalar cubeEm
        cubeEm = createMyCustomFunction(3)
    
        printf("my custom function 'cubeEm(x)' = %1.0f when x = %1.0f\n",
            cubeEm->fxn(2), 2)
    }
    
    test()
    
    end
    
    exit
    Others on the list who have more experience and insight might chime in with more direct approaches.

    Comment


    • #3
      Here is a variation bypassing classes. You can only have one custom function at a time.
      Code:
      version 18
      
      mata :
      
      mata set matastrict   on
      mata set mataoptimize on
      
      
      // the custom function
      real scalar to_the_power_of(real scalar x) return(x^(*findexternal("n")))
      
      
      // create the custom function
      pointer(function) scalar init_to_the_power_of(
          
          real scalar n,
        | real scalar reset
          
          )
      {
          if (args() < 2)
              reset = 0
          
          if (findexternal("n") != NULL) {
              if ( !reset )
                  _error(3498,"external n already exists")
              rmexternal("n")
          }
          (*crexternal("n")) = n
          return(&to_the_power_of())
      }
      
      // test
      squareEm = init_to_the_power_of(2)
      (*squareEm)(2)
      
      cubeEm = init_to_the_power_of(3,1) // <- allow external to be overwritten
      (*cubeEm)(2)
      
      squareEMagain = init_to_the_power_of(2) // <- error
      
      end
      yields
      Code:
      : // the custom function
      : real scalar to_the_power_of(real scalar x) return(x^(*findexternal("n")))
      
      :
      :
      : // create the custom function
      : pointer(function) scalar init_to_the_power_of(
      >    
      >     real scalar n,
      >   | real scalar reset
      >    
      >     )
      > {
      >     if (args() < 2)
      >         reset = 0
      >    
      >     if (findexternal("n") != NULL) {
      >         if ( !reset )
      >             _error(3498,"external n already exists")
      >         rmexternal("n")
      >     }
      >     (*crexternal("n")) = n
      >     return(&to_the_power_of())
      > }
      
      :
      : // test
      : squareEm = init_to_the_power_of(2)
      
      : (*squareEm)(2)
        4
      
      :
      : cubeEm = init_to_the_power_of(3,1) // <- allow external to be overwritten
      
      : (*cubeEm)(2)
        8
      
      :
      : squareEMagain = init_to_the_power_of(2) // <- error
        init_to_the_power_of():  3498  external n already exists
                       <istmt>:     -  function returned error
      (1 line skipped)
      ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
      r(3498);

      Why would you want to do this anyway?
      Last edited by daniel klein; 18 Jul 2024, 09:54.

      Comment


      • #4
        Why would you want to do this anyway?
        I'm curious about this too. Usually people use this kind of abstraction in functional languages when you have some kind of closure. You have a function that does something to every element in a list (let's say), but you don't define what actually happens to every element within that function. This would be like map() in JavaScript or lapply() in R. With a function like this, you let whoever calls the function pass in another function (usually an anonymous function) that defines what happens to each element. You could do the same with a for loop over the list, but that comes with other (abstract) concerns, and there are other cases where a for loop would not work as a replacement for a closure. Passing a function out of a function as a return value is a bit more rare. I've seen this kind of thing before in settings where you want to write a framework. In that case, rather than writing code to do something, you're writing code that let's your user write code to do something in a way that is more convenient than doing everything from scratch. In a framework, you do this kind of function passing when you want a convenient way for the user of your framework to chain functions together. Usually the idea is to make function composition syntax natural and easy to implement. Think like TensorFlow, where you might build a machine learning model using function composition. I guess another use case might be if you wanted a type agnostic system where you pass two values into a function, it detects the type, then returns a function appropriate for those two values. That might be useful if the return type depends on the parameter types and the language is explicitly and statically typed.

        I'm wondering if perhaps OP has a use case like that in mind and is just trying to figure out the general design pattern using a toy example.

        Comment

        Working...
        X