$context->functions->add( Tunneling => {class => 'context::Quantum::Tunneling'} );should be
$context->functions->add( Tunneling => {class => 'context::Quantum'} );The class must be a Perl
package
name, not a Perl function name. The class in your case is context::Quantum
. By setting the class to context::Quantum::Tunneling
, you have implied that there is a package
with that name, and when MathObjects tries to use that package, it runs into trouble (this is the error message about weaken
since it tries to call the weaken
method of the class you have specified for the function).
Here is the explanation of the errors you have received:
$tst = context::Quantum::Tunneling(1,2); # This one works just fineThis is because you are calling the function directly from Perl. MathObjects are not involved here.
$tst = Compute(Tunneling(1,2)); # This one throws the following error: Undefined subroutine &main::TunnelingThis is because Perl first must call
Tunneling(1,2)
and then pass that value to Compute(). But there is no Perl function called Tunneling()
(only one called context::Quantum::Tunneling()
, and a MathObject one called Tunneling
, but that is unknown to native Perl expressions), so Perl complains that it doesn't know what to do.
You may have meant to do
$tst = Compute("Tunneling(1,2)");which would have asked MathObjects to use its definition of Tunneling and create a value from that. (This would also fail because of the problem with how you added
Tunneling
to the context, but that is a different issue.)
parserFunction( "fTest(t)" => "context::Quantum::Tunneling(1,t)"); #This one throws the following error: 'context' is not defined in this context;The
parserFunction
command defines a new MathObject function by using a MathObject formula. So the things that appear in the second string can only be things that are meaningfull in the current Context()
, as that string will be parsed by MathObjects (via Compute()
). The error is because context::Quantum::Tunneling
is a Perl function, not a MathObjects one. When MathObject tries to parse the string you have given it, it identifies context
as the first token to be analyzed, but since it has no definition for that, it gives the error message you report. It has correctly told you that this identifier is unknown to it, and so it can't create the function you are requesting.
parserFunction( "fTest(t)" => "Tunneling(1,t)"); # This one throws the following error: Can't locate object method "weaken" via package "context::Quantum::Tunneling"This is a correct use of
parserFunction()
, since Tunneling
is defined in the context. The problem is that it is not defined correctly, and so when MathObjects tries to use the definition, it fails (as described above).
$tst2 = fTest(2);if the
parserFunction()
call succeeds, then this should also work, as parserFunction
also defines the needed Perl function that calls the MathObject one so that the function you are defining can be used in both MathObject and Perl expressions.
So fixing the main problem with the class
of the Tunneling function is the first thing you need to fix. There is also a second problem, however. The context::Quantum::Tunneling
function is actually a method of a Perl object, and so the first parameter passed to it will be the object itself, not the values of $n
and $r
(these are the second and third arguments). So the definition should be
sub Tunneling { my $self = shift; my ($n,$r) = @_; my $T=2.3*$n; return $T; }or just
sub Tunneling { shift; my ($n,$r) = @_; my $T=2.3*$n; return $T; }Of course, the function can be simplified as
sub Tunneling { shift; my ($n,$r) = @_; return 2.3*$n; }but perhaps there is more to come with the function (what do I know of quantum tunneling?).
This allows the Tunneling
subroutine to be used properly as a MathObject function. Note, however, that this will cause your first example to fail, since your direct call to the function doesn't include an object as its first parameter. You can correct that by using
$tst = context::Quantum->Tunneling(1,2);instead. This passes the class as the first parameter.
Hope that clears things up.
Yes, you can, but you should do it in the _init
routine for your macro file. For example, if your macro file is called myMacros.pl
, then you could use
sub _myMacros_init { PG_restricted_eval('sub Tunneling {Parser::Function->call("Tunneling",@_)}'); }to define your function. it is possible to put it in directly, but it is safer to do this, so that your macro file can be used in more general situations.