PerlJam2015 has asked for the wisdom of the Perl Monks concerning the following question:

I'm quite new to Perl, and I'm writing a script to use Simpson's Rule to evaluate integrals numerically over closed intervals (The homework is to do it by paper, and the instructor will allow me to use programs to do the work if I write it myself since it is INCREDIBLY tedious and he states it is best left to computers) and coming to the realization that I don't how to take user input of a function f(x) in the form "argumentx" such as "1/x" or "3-x" or "(1-x)/(sin**2(2x)" and turn that into a subroutine which would then work over any defined x.

The workaround is to write the function into the code as a subroutine, but what I was thinking is that if the proper amount of parenthesis were used, then the user could enter the argument in that format and then I could search-and-replace any literal 'x' with '@_'.

I'm getting a little lost in this thought process, and I'm sure someone has already done this much. I'll be playing around with it more, but I'm curious if anyone knows if the search-and-replace approach would result in obvious problems.

So far, I have this...

use warnings; use strict; #Take any function input in the correct format, and turn it into a sub +routine. print "Enter a function in the 'expression(x)' format"; chomp(my $function = <STDIN>); $function = s/x/@_/g sub function{ $function; } my $tobedone = 53; #Example number my $done = &function($tobedone);

Replies are listed 'Best First'.
Re: An Approach to Function to Subroutine using Regular Expression
by BrowserUk (Patriarch) on Feb 22, 2015 at 02:50 UTC

    If you're prepared to modify the way you input your function -- ie. use * instead of implied multiplication; add brackets to functions etc -- then something like this might get you started:

    sub genFunc{ my $expr = shift; $expr =~ s[x][\$x]g; print "'$expr'"; return eval "sub{ my \$x = shift; return $expr; }"; };; my $f = genFunc( '(1-x)/(sin()**2*(2*x))' );; '(1-$x)/(sin()**2*(2*$x))' print "$_: ", $f->( $_ ) for 1 .. 10;; 1: 0 2: -0.302362609265759 3: -16.7379227868029 4: -0.65473590385359 5: -0.435002112398393 6: -5.33688415389075 7: -0.992910704853273 8: -0.446962308202578 9: -2.61681663614942 10: -1.52048103620111

    Note: I'm fully aware that my attempt at modifying your function is wrong (sin() with out an argument?), but I couldn't make better sense of your intent.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
    In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
Re: An Approach to Function to Subroutine using Regular Expression
by LanX (Saint) on Feb 22, 2015 at 04:56 UTC
    Careful sinē(x) must be coded as sin($x)**2 :)

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)

    PS: Je suis Charlie!

Re: An Approach to Function to Subroutine using Regular Expression
by LanX (Saint) on Feb 23, 2015 at 07:32 UTC
    if I were you I'd rather stick with writing real Perl code with $x variables

    This regex approach is quite dangerous, since any x will be replaced, for instance exp(x) could become e$xp($x)

    so at least try to replace at word boundaries \b with $str =~ s/\bx\b/\$x/g

    demonstration:

    DB<134> "ex p"=~s/\bx\b/\$x/r => "ex p" DB<135> "e x p"=~s/\bx\b/\$x/r => "e \$x p"

    There are some ways to tweak Perl's parser though, but they are far too advanced for your level now.

    i.e. using a function sub a {$a} to replace x with a (x is already an operator) and maybe catch and translate stuff like sin2 in AUTOLOAD.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)

    PS: Je suis Charlie!