Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Perl 6 custom operators

I am studying chemistry in the university and want to try writing textbook examples in Perl6 or Perl, like balancing the chemical formula or other processes!

Then I encountered the problem is on perl6 custom operator. I feel I have been repeating my code and myself when I use the feature. It is hard to read and write. How can I simplify this?

#!/usr/bin/env perl6
use v6;
#basic SI(International System of Units) type 


role MetricPrefix {
    method baseOn ( Str $base , Numeric $input ) {
        given $base {
            when 'pico' { return $input * 10**-12 }
            when 'namo' { return $input * 10**-9 }
            when 'micro' { return $input * 10**-6}
            when 'milli' { return $input * 10**-3 }
            when 'centi' { return $input * 10**-2 }
            when 'hecto' { return $input * 10**2 }
            when 'kilo' { return $input * 10**3 }
            when 'mega' { return $input * 10**6 }
            when 'giga' { return $input * 10**9 }
            when 'tera' { return $input * 10**12 }
            default { fail "you must input a metric prefix which allow pico to tera" }
        }
    }
}



class Mass does MetricPrefix {
    #basic Mass is g is different form si statda
    has $.g;

    submethod BUILD ( :$!g  ) {
    }

}

class Length does MetricPrefix {
    has $.Length ;

    submethod BUILD ( :$!Length  ) {
    }
}



multi postfix:<(kg)>( $input ) {
    return Mass.new( g => Mass.baseOn("kilo",$input) ) or fail "you Must input a number";
}

multi postfix:<(g)>( $input ) {
    return Mass.new( g => $input ) or fail "you Must input a number";
}

multi infix:<+>( Mass $inputOne , Mass $inputTwo ) is assoc<right> {
    return Mass.new( g => $inputOne.g + $inputTwo.g) or fail "error in there ";
}

multi infix:<->( Mass $inputOne , Mass $inputTwo ) is assoc<right> {
    return Mass.new( g => $inputOne.g - $inputTwo.g) or fail "error in there ";
}

multi infix:<*>( Mass $inputOne , Mass $inputTwo ) is assoc<right> is tighter( &infix:<+> ) is tighter( &infix:<-> ) is tighter( &infix:</>) {
    return Mass.new( g => $inputOne.g * $inputTwo.g) or fail "error in there ";
}

multi infix:</>( Mass $inputOne , Mass $inputTwo ) is assoc<right> is tighter( &infix:<+> ) is tighter( &infix:<-> )  {
    return Mass.new( g => $inputOne.g / $inputTwo.g) or fail "error in there ";
}





#the meterLeng
multi postfix:<(km)>( $input ) {
    return Length.new( Length => Length.baseOn("kilo",$input) ) or fail "you Must input a number";
}

multi postfix:<(m)>( $input ) {
    return Length.new( Length => $input ) or fail "you Must input a number";
}

multi infix:<+>( Length $inputOne , Length $inputTwo ) is assoc<right> {
    return Length.new( Length => $inputOne.Length + $inputTwo.Length) or fail "error in there ";
}

multi infix:<->( Length $inputOne , Length $inputTwo ) is assoc<right> {
    return Length.new( Length => $inputOne.Length - $inputTwo.Length) or fail "error in there ";
}

multi infix:<*>( Length $inputOne , Length $inputTwo ) is assoc<right> is tighter( &infix:<+> ) is tighter( &infix:<-> ) is tighter( &infix:</>) {
    return Length.new( Length => $inputOne.Length * $inputTwo.Length) or fail "error in there ";
}

multi infix:</>( Length $inputOne , Length $inputTwo ) is assoc<right> is tighter( &infix:<+> ) is tighter( &infix:<-> )  {
    return Length.new( Length => $inputOne.Length / $inputTwo.Length) or fail "error in there ";
}


#just a test
say 10(kg) + 1(g);
say 10(m) + 1(m);
like image 204
黃家億 Avatar asked Oct 30 '22 10:10

黃家億


1 Answers

I replaced fail messages with declaring types on the input. That will let Perl 6 worry about whether numbers are input and give appropriate error messages if they are not. I also built in the assumption that all lengths and masses are positive.

#!/usr/bin/env perl6
use v6;
#basic SI(International System of Units) type

role MetricPrefix {
    method baseOn ( Str $base , Numeric $input ) {
        given $base {
            when 'pico'  { return $input * 10**-12 }
            when 'namo'  { return $input * 10**-9  }
            when 'micro' { return $input * 10**-6  }
            when 'milli' { return $input * 10**-3  }
            when 'centi' { return $input * 10**-2  }
            when 'hecto' { return $input * 10**2   }
            when 'kilo'  { return $input * 10**3   }
            when 'mega'  { return $input * 10**6   }
            when 'giga'  { return $input * 10**9   }
            when 'tera'  { return $input * 10**12  }
            default { fail "you must input a metric prefix within the range of pico to tera" }
        }
    }
}

class Mass does MetricPrefix {
    #basic Mass is g is different form si statda
    has $.g where * > 0;
}

class Length does MetricPrefix {
    has $.Length where * > 0;
}

# Mass
multi postfix:<(kg)>( $input where * > 0) {
    return Mass.new( g => Mass.baseOn("kilo",$input) );
}

multi postfix:<(g)>( $input where * > 0) {
    return Mass.new( g => $input );
}

multi infix:<+>( Mass $inputOne , Mass $inputTwo ) is assoc<right> {
    return Mass.new( g => $inputOne.g + $inputTwo.g);
}

multi infix:<->( Mass $inputOne , Mass $inputTwo ) is assoc<right> {
    return Mass.new( g => $inputOne.g - $inputTwo.g);
}

multi infix:<*>( Mass $inputOne , Mass $inputTwo ) is assoc<right> is tighter( &infix:<+> ) is tighter( &infix:<-> ) is tighter( &infix:</>) {
    return Mass.new( g => $inputOne.g * $inputTwo.g);
}

multi infix:</>( Mass $inputOne , Mass $inputTwo ) is assoc<right> is tighter( &infix:<+> ) is tighter( &infix:<-> )  {
    return Mass.new( g => $inputOne.g / $inputTwo.g);
}

#Length
multi postfix:<(km)>( $input where * > 0) {
    return Length.new( Length => Length.baseOn("kilo",$input) );
}

multi postfix:<(m)>( $input where * > 0) {
    return Length.new( Length => $input );
}

multi infix:<+>( Length $inputOne , Length $inputTwo ) is assoc<right> {
    return Length.new( Length => $inputOne.Length + $inputTwo.Length);
}

multi infix:<->( Length $inputOne , Length $inputTwo ) is assoc<right> {
    return Length.new( Length => $inputOne.Length - $inputTwo.Length);
}

multi infix:<*>( Length $inputOne , Length $inputTwo ) is assoc<right> is tighter( &infix:<+> ) is tighter( &infix:<-> ) is tighter( &infix:</>) {
    return Length.new( Length => $inputOne.Length * $inputTwo.Length);
}

multi infix:</>( Length $inputOne , Length $inputTwo ) is assoc<right> is tighter( &infix:<+> ) is tighter( &infix:<-> )  {
    return Length.new( Length => $inputOne.Length / $inputTwo.Length);
}


#just a test
say 10(kg) + 1(g);
say 10(m) + 1(m);
like image 62
Christopher Bottoms Avatar answered Nov 15 '22 09:11

Christopher Bottoms