IanLisle

73 Reputation

3 Badges

13 years, 67 days

MaplePrimes Activity


These are answers submitted by IanLisle

Best workaround I can find is something like this:

   error "invalid input: object %1 is wrong", sprintf("%a", M)

The sprintf forces printing of the object using its ModuleDeconstruct; the resulting string becomes parameter %1 for the error statement. Seems to work ok.  And will work even when M happens to NOT be an object.

Thanks Joe, but it turns out things are not so pessimistic. We tried various approaches and now have a good solution to getting an object that is appliable via ModuleApply.  The behaviour of thismodule remains a mystery to us, the solution below uses a different mechanism.  Our goal is really bigger than getting an appliable object, it is to have a ModuleApply with a split personality:

  • Prototype object ModuleApply to act as constructor -- this is good programming style as described in Maple docs.
  • Instance object ModuleApply to enable object to act as appliable operator.

So for example, suppose we want to build operators that differentiate wrt a certain variable.  (Yes I know there are easier ways to do this.)  We make a PDeriv object that stores a local variable x, that says what variable.  We might hope to use syntax like this:

ddt := PDeriv(t);
# Now ddt should be a PDeriv object that 'differentiates wrt t'
ddt (cos(t));
# ddt should be appliable, so this line to return -sin(t)

Outline of how to achieve this:

  • In definition of PDeriv object, have a non-static ModuleApply method that acts as a constructor
  • In ModuleCopy of the PDeriv object, have code that redefines ModuleApply as a proc that acts as operator, so that instance objects are appliable.

The signature of ModuleCopy is something like

    export ModuleCopy::static := proc(new::PDeriv, proto::PDeriv, otherArgs)

The redefinition of ModuleApply occurs within scope of ModuleCopy, so an object reference is available via the 'new' object that has just been made by cloning.  This avoids using thismodule (which can't be used here because ModuleCopy is static).   Example sheet below...

restart;

PDeriv object with dual-purpose ModuleApply; prototype uses as constructor, instance as appliable operator

M := module()

option package;

  export PDeriv;

 

  PDeriv := module()

  option object;

    local x := "Prototype PDeriv object";

 

    local applyOp::static := proc(self::PDeriv, e::scalar)

      # Apply self as an operator to expression e

      return diff(e, self:-x);

    end proc;

 

    export ModulePrint::static := proc(self::PDeriv)

      local y;

      if self:-x::name then

        unapply( Diff(y,self:-x), y);

      else

        self:-x

      end if;

    end proc;

 

    export ModuleApply := proc(x::name)

      # N.b. not static

      # Constructor version of ModuleApply, used in prototype object

      # Will be overwritten by ModuleCopy for object instances

      return Object(PDeriv, x);

    end proc;

 

    export ModuleCopy::static := proc(new::PDeriv, proto::PDeriv, x::name)

      new:-x := x;

      new:-ModuleApply := proc(e::scalar)

        # Operator version of ModuleApply

        # For use in object instances

        return applyOp(new, e);

      end proc;

    end proc;

 

  end module;

 

end module;

module () export PDeriv; option package; end module

(1)

# Create a mla library file into local directory

# Location of the lib file,  It creates "M.mla" if mla does not exist.

savelibname := cat(".", kernelopts(dirsep),"M.mla");

# Save module to the current lib.

LibraryTools:-Save('M');

 

".\M.mla"

(2)

This uses the above typed code

with(M);

[PDeriv]

(3)

Prototype prints as

PDeriv;

thismodule

(4)

Construct new object, uses prototype ModuleApply...

ddt := PDeriv(t);

thismodule

(5)

Now ddt acts as an operator, via updated ModuleApply...

ddt(cos(t));

-sin(t)

(6)

Force restart and load package M from the .mla....

restart;

with(M);

[PDeriv]

(7)

Prototype...

PDeriv;

thismodule

(8)

Construct new object...

ddt := PDeriv(t);

thismodule

(9)

Now ddt acts as operator...

ddt(cos(t));

-sin(t)

(10)

 



Slightly tricky programming, but very natural user interface result.  Works from command line and from .mla.  We have tested this approach on a couple of objects and it works great.

Ian

 

Download Demo-ObjectModuleApp.mw

 

Page 1 of 1