【问题标题】:Is there a 'clamp' method/sub for ranges/Num etc in Raku (i.e. Perl6)?Raku(即 Perl6)中是否有范围/Num 等的“钳位”方法/子?
【发布时间】:2019-03-19 22:09:18
【问题描述】:

Perl6 中是否有“clamp”或等效方法或子方法?

例如

my $range= (1.0 .. 9.9)
my $val=15.3;

my $clamped=$range.clamp($val);
# $clamped would be 9.9

$val= -1.3;
$clamped=$range.clamp($val);
# $clamped would be 1.0

【问题讨论】:

  • 哈哈线噪版:my ($i,$l,$ll)=(50,1,10); say $i>$l??$l!!$i <$ll??$ll!!$i;

标签: raku clamp


【解决方案1】:

您可能想探索的另一种技巧是使用Proxy,它允许您在从容器中获取或存储值时定义“钩子”

sub limited-num(Range $range) is rw {
    my ($min, $max) = $range.minmax;
    my Numeric $store = $min;
    Proxy.new(
        FETCH => method () { $store },
        STORE => method ($new) {
            $store = max($min, min($max, $new));
        }
    )
}

# Note the use of binding operator `:=`
my $ln := limited-num(1.0 .. 9.9);
say $ln;     # OUTPUT: 1

$ln += 4.2;  
say $ln;     # OUTPUT: 5.2

$ln += 100;  
say $ln;     # OUTPUT: 9.9

$ln -= 50;   
say $ln;     # OUTPUT: 1

$ln = 0;     
say $ln;     # OUTPUT: 1

这个特定的limited-num 将使用它的最小值进行初始化,但您也可以在声明时设置它

my $ln1 := limited-num(1.0 .. 9.9) = 5.5;
say $ln1;    # OUTPUT 5.5;

my $ln2 := limited-num(1.0 .. 9.9) = 1000;
say $ln2;    # OUTPUT 9.9

【讨论】:

    【解决方案2】:

    我不这么认为。所以,也许:

    multi clamp ($range, $value) {
      given $range {
        return .max when (($value cmp .max) === More);
        return .min when (($value cmp .min) === Less);
      }
      return $value
    } 
    my $range = (1.0 .. 9.9);
    say $range.&clamp: 15.3; # 9.9
    say $range.&clamp: -1.3; # 1
    
    my $range = 'b'..'y';
    say $range.&clamp: 'a'; # b
    say $range.&clamp: 'z'; # y
    

    MOP 允许直接探索 P6 系统中可用的对象。一个特别方便的元方法是.^methods,它适用于大多数内置对象:

    say Range.^methods; # (new excludes-min excludes-max infinite is-int ...
    

    默认情况下,这仅包括Range 类中定义的方法,而不包括它继承的方法。 (要获得它们,你可以使用say Range.^methods: :all。这会让你得到一个更大的列表。)

    当我刚刚尝试它时,我发现它还包含许多无用的方法,名称为Method+{is-nodal}.new。所以也许改用这个:

    say Range.^methods.grep: * !~~ / 'is-nodal' /;
    

    这个网:

    (new excludes-min excludes-max infinite is-int elems iterator
    flat reverse first bounds int-bounds fmt ASSIGN-POS roll pick
    Capture push append unshift prepend shift pop sum rand in-range
    hyper lazy-if lazy item race of is-lazy WHICH Str ACCEPTS perl
    Numeric min max BUILDALL)
    

    这就是我用来引导我找到上述解决方案的方法;我有点知道方法,但用.^methods提醒我。


    另一种探索可用内容的方法是文档,例如the official doc's Range page。这让我很满意:

    ACCEPTS min excludes-min max excludes-max bounds
    infinite is-int int-bounds minmax elems list flat
    pick roll sum reverse Capture rand
    

    比较这两个列表,排序和装袋,出于好奇:

    say
    
    <ACCEPTS ASSIGN-POS BUILDALL Capture Numeric Str WHICH append
     bounds elems excludes-max excludes-min first flat fmt hyper 
     in-range infinite int-bounds is-int is-lazy item iterator
     lazy lazy-if max min new of perl pick pop prepend push
     race rand reverse roll shift sum unshift>.Bag
    
     ∩
    
    <ACCEPTS Capture bounds elems excludes-max excludes-min flat
     infinite int-bounds is-int list max min minmax pick
     rand reverse roll sum>.Bag
    

    显示:

    Bag(ACCEPTS, Capture, bounds, elems, excludes-max, excludes-min,
    flat, infinite, int-bounds, is-int, max, min, pick,
    rand, reverse, roll, sum)
    

    因此,由于某种原因,listminmaxsum 被记录为 Range 方法,但在我的 .^methods 调用中没有列出。大概他们被称为Method+{is-nodal}.new。嗯。

    say Range.^lookup('minmax'); # Method+{is-nodal}.new
    say Range.^lookup('minmax').name; # minmax
    

    是的。唔。所以我可以写:

    say Range.^methods>>.name.sort;
    
    (ACCEPTS ASSIGN-POS AT-POS BUILDALL Bag BagHash Capture EXISTS-POS
     Mix MixHash Numeric Set SetHash Str WHICH append bounds elems
     excludes-max excludes-min first flat fmt hyper in-range infinite
     int-bounds is-int is-lazy item iterator lazy lazy-if list max min
     minmax new of perl pick pop prepend push race rand reverse roll
     shift sum unshift)
    

    无论如何,希望对您有所帮助。

    【讨论】:

    • 谢谢。很简单,做一个子,我只是不确定它是否被实现为一些 perl6-ism。我还没有进入任何深度 ATM 中的 MOP,所以要学习更多;)
    • 为了我的直接目的,我选择了“内联”:$rate= $rate &gt; 0.1??0.1!!$rate; $rate= $rate &lt; -0.1??-0.1!!$rate;
    • Yw。我认为大多数人可以使用 P6 多年,而无需查看 MOP,并且在编写 say WHAT 42 之类的东西时没有意识到他们正在使用它。我脑海中唯一记得的事情是.^methods.^lookup
    【解决方案3】:

    奇怪的是没有人建议使用augment。诚然,它会产生全局变化,但这可能不是问题。

    augment class Range {
       method clamp ($value) { ... }
    }
    

    您需要在 augment 之前的相同范围内使用 pragmause MONKEY-TYPING 才能使用它。但是这样一来,你可以简单地说$range.clamp(5),例如。与 raiph 的答案相比,它为您节省了一个字符,但代价是(并非微不足道的)破坏预编译。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-02
      • 1970-01-01
      • 1970-01-01
      • 2020-10-23
      • 2020-02-03
      • 1970-01-01
      相关资源
      最近更新 更多