使用 Perl 6 自定义运算符

Posted

技术标签:

【中文标题】使用 Perl 6 自定义运算符【英文标题】:Using Perl 6 custom operators 【发布时间】:2017-03-28 13:21:04 【问题描述】:

我在大学学习化学,想尝试用 Perl6 或 Perl 编写教科书示例,比如平衡化学公式或其他过程!

然后我遇到的问题是关于perl6自定义运算符。当我使用该功能时,我觉得我一直在重复我的代码和我自己。 很难读和写。我该如何简化呢?

#!/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);

【问题讨论】:

这感觉像是一个代码审查问题,而不是你需要解决的问题。您可能(请先查看他们的帮助中心)在我们的姊妹网站codereview.stackexchange.com 上发现它更合适 submethod BUILDs 是不必要的,因为您将属性声明为公共。 是的,当我没有使用任何对象构造时,这个子方法BUILD是不必要的; 【参考方案1】:

我用在输入上声明类型替换了失败消息。这将使 Perl 6 担心是否输入了数字并在没有输入时给出适当的错误消息。我还建立了所有长度和质量都是正数的假设。

#!/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);

【讨论】:

以上是关于使用 Perl 6 自定义运算符的主要内容,如果未能解决你的问题,请参考以下文章

Perl 使用自定义文件句柄打开外部命令

Perl:将本地 .pm 文件中的自定义模块“安装”到 Perl 执行环境中?

为 SublimeLinter 添加自定义路径到 Perl 库

perl 6集合操作中用户定义的比较函数

如何为不与内置或 CPAN 包名称冲突的自定义 Perl 模块选择包名称?

如何使用反射调用自定义运算符