Expressando a sequência de somatório duplo em Raku

13

Como expressar a sequência de dupla somação de variável dupla em Perl 6?

Para um exemplo de sequência de soma dupla com variável dupla , consulte este

imagem

Ele deve ser expresso como está, ou seja, sem reduzir matematicamente o somatório duplo em um somatório único. Obrigado.

Lars Malmsteen
fonte

Respostas:

14

O X(operador cruzado) e o [+](metaoperador de redução [ ]com operador aditivo +) tornam isso surpreendentemente fácil:

Para representar 1 o somatório duplo ∑³ x  = 1 ∑⁵ y  = 1 2x + y , você pode fazer o seguinte:

  [+] do for 1..3 X 1..5 -> ($x, $y) { 2 * $x + $y }
#        for 1..3 X 1..5                             # loop cross values
#                        -> ($x, $y)                 # plug into x/y
#                                    { 2 * $x + $y } # calculate each iteration
#     do                                             # collect loop return vals 
# [+]                                                # sum them all

Se você quiser criar um subpara isso, escreva-o da seguinte maneira :

sub ΣΣ (
    Int $aₒ, Int $aₙ,     # to / from for the outer
    Int $bₒ, Int $bₙ,     # to / from for the inner
    &f where .arity = 2   # 'where' clause guarantees only two params
) {
  [+] do for $aₒ..$aₙ X $bₒ..$bₙ -> ($a, $b) { &f(a,b) }
}

say ΣΣ 1,3, 1,5, { 2 * $^x + $^y }

Ou até simplificar mais as coisas para

sub ΣΣ (
    Iterable \a,            # outer values
    Iterable \b,            # inner values
    &f where .arity = 2) {  # ensure only two parameters
  [+] do f(|$_) for a X b
}

# All of the following are equivalent
say ΣΣ 1..3, 1..5, -> $x, $y { 2 * $x  + $y  }; # Anonymous block
say ΣΣ 1..3, 1..5,           { 2 * $^x + $^y }; # Alphabetic args
say ΣΣ 1..3, 1..5,             2 *  *  +  *   ; # Overkill, but Whatever ;-) 

Observe que, digitando-o, podemos garantir que os intervalos sejam passados, mas digitando-o da Iterablemelhor maneira Rangepossível para permitir sequências de soma mais interessantes, como, por exemplo, ΣΣ (1..∞).grep(*.is-prime)[^99], 1..10, { … }que nos permitiriam usar a sequência dos 100 primeiros números primos.

De fato, se realmente quiséssemos, poderíamos exagerar e permitir um operador de soma de profundidade arbitrário, que é facilitado movendo a função para a esquerda:

sub ΣΣ (
    &function, 
    **@ranges where                # slurp in the ranges
        .all   ~~ Iterable &&      # make sure they're Iterables 
        .elems == &function.arity  # one per argument in the function
) {
  [+] do function(|$_) for [X] @ranges;
};

Assim como [+]resume todos os valores de nossa f()função, [X]calcula a cruz iterativamente, por exemplo, [X] 0..1, 3..4, 5..6primeiro faz 0..1 X 3..4ou (0,3),(0,4),(1,3),(1,4), e depois faz (0,3),(0,4),(1,3),(1,4) X 5..6, ou (0,3,5),(0,4,5),(1,3,5),(1,4,5),(0,3,6),(0,4,6),(1,3,6),(1,4,6).


1. Desculpe, SO não me permite fazer o LaTeX, mas você deve ter a ideia. 2. Sim, eu sei que é uma letra subscrita O e não zero, os números subscritos normalmente não são identificadores válidos, mas você pode usar Slang :: Subscripts para habilitá-los.

user0721090601
fonte