Julia: Desprezar `uns`?

Criado em 2 nov. 2017  ·  46Comentários  ·  Fonte: JuliaLang/julia

Agora que distinguimos one e oneunit , ones(T, sz) parece um nome impróprio. Substituir em favor de fill(oneunit(T), sz) ? Em caso afirmativo, devemos descartar zeros também?

decision linear algebra stdlib

Comentários muito úteis

Para mim, fill(oneunit(T), sz) parece uma perda não trivial em legibilidade em comparação com ones(T, sz) .

Todos 46 comentários

xref https://github.com/JuliaLang/julia/issues/11557#issuecomment -339776065 e abaixo, e também PR # 24389 de @ Sacha0

Tenho um trabalho em andamento nesse sentido que espero postar nos próximos um ou dois dias :). Melhor!

Para mim, fill(oneunit(T), sz) parece uma perda não trivial em legibilidade em comparação com ones(T, sz) .

Observe que raramente você precisa escrever algo tão prolixo como fill(oneunit(T), sz) , já que normalmente um literal ou algo similarmente compacto é suficiente no lugar de oneunit(T) . Encantamentos mais curtos também podem se tornar possíveis com mudanças futuras nos construtores de array. Além disso, depois de fazer a transição para fill , você começa a gostar disso, garanto-lhe :). Melhor!

Poderíamos apenas escolher se ones usa one ou oneunit . ones e zeros devem ser consideradas funções de conveniência, o que está ok desde que tenham significados claros em termos de funções mais gerais.

Plano por triagem: Revisite na próxima semana, considerando especificamente mover ones e zeros para a camada de compatibilidade do MATLAB, em favor de fill na base. Melhor!

ones e oneunits distinguiriam as duas opções.

Não tenho certeza de como me sinto sobre mover isso e zeros para a compatibilidade do MATLAB. Só porque Mathworks inventou isso não significa que não seja uma boa API de conveniência da qual possamos nos orgulhar . Apenas brevemente - quais foram as razões por trás desse pensamento? (Desculpe, devo dizer que a triagem parece muito mais eficiente, mas significativamente menos transparente quando o raciocínio não é fornecido).

Não é uma mudança com a qual estou entusiasmado, mas levantei porque é uma inconsistência lógica. Acho que é justo dizer que ones(T, sz) implica fill(one(T), sz) mas o que realmente faz por baixo do capô é fill(oneunit(T), sz) .

Uma opção seria renomeá-lo para oneunits . Uma alternativa seria fazer uma troca horrível: one -> algebraic_one e oneunit -> one . Isso está quebrando e não é possível fazer por meio de depreciação, e é por isso que digo "horrível".

Sim, eu diria que adicionar oneunits e alterar ones para dar fill(one(T), ...) seria a solução óbvia para isso, não?

Eu ficaria bem com isso. Por curiosidade, quais são os usos de fill(one(T), sz) ? Precisamos de ones ?

Haha :) Eu ia perguntar - para que você usa fill(oneunits(T), sz) ? (Por exemplo, para que uma matriz preenchida com 1 metro, ou 1 quilograma, ou 1 segundo, seria usada?)

Acho que fill(one(T), sz) é usado praticamente pelo mesmo motivo que zeros(T, sz) , que é inicializar uma matriz para uma operação de redução personalizada. Um array z = zeros(T, sz) está pronto para ter seus elementos adicionados com z[i] += x enquanto o = fill(one(T), sz) está pronto para ter seus elementos multiplicados o[i] *= x . Por exemplo, estou pensando em situações em que os elementos do array podem representar probabilidade (relativa). Nesses dois casos, estou procurando a identidade do operador + ou * respectivamente (e não geradores aditivos).

Veja também # 23544

Haha :) Eu ia perguntar - para que você usa fill (oneunits (T), sz)? (Por exemplo, para que uma matriz preenchida com 1 metro, ou 1 quilograma, ou 1 segundo, seria usada?)

As variáveis ​​dependentes de um ODE. Seria estranho se ele apenas dividisse as unidades aleatoriamente quando você pedisse um array do tipo T ?

A razão fundamental para preferir fill é que um conjunto compacto de ferramentas poderosas, ortogonais e combináveis ​​funciona melhor do que uma coleção maior de ferramentas ad hoc, limitadas e sobrepostas, como ones / zeros / trues / falses . A discussão acima destaca este ponto: Enquanto fill acomoda todos os casos de uso acima de forma inequívoca e (no uso mais real) de forma concisa, o ones / zeros / trues / falses abordagem requer uma nova função para cada caso de uso.

Alguns exemplos relevantes de reescritas na base:

complex.(ones(size(Ac, 1)), ones(size(Ac, 1)))

torna-se

fill(1.0 + 1.0im, size(Ac, 1))

e

2ones(Int, 2, 2, 2)

torna-se

fill(2, (2, 2, 2)) # or fill(2, 2, 2, 2) if you prefer

Observe que esses fill encantamentos são mais simples, mais legíveis, mais compactos e mais eficientes do que seus equivalentes não fill , e base/ e test/ são repleto de exemplos como esses. Como acontece com todas as mudanças, a transição para fill requer algum ajuste mental inicial. Mas após o ajuste você descobre que tem mais poder e elegância ao seu alcance :). Melhor!

@ Sacha0 : trues / falses não são substituíveis diretamente por fill , mas precisam usar fill! com um inicializador BitArray . Eles também não estão incluídos na ambigüidade entre one e oneunit . Portanto, não acho que eles se encaixem nessa discussão.

Quanto a ones , geralmente me oponho a descontinuá-lo, não vejo benefício. O argumento de que alguma expressão pode ser escrita de forma mais eficaz com fill não é muito convincente em minha opinião, já que todos esses exemplos usam ones como etapas intermediárias para fazer outra coisa; mas e quando você realmente quiser uma variedade de uns? Então, ter que usar fill é mais longo, menos óbvio e apenas mais irritante. Eu gosto mais da proposta de base ou test podem ser reescritas de forma mais eficaz usando fill vez de ones não há nada que impeça isso agora.

@carlobaldassi Embora isso seja verdade, uma rápida pesquisa no GitHub revela que quase todos os usos de ones deveriam realmente estar usando fill para evitar alocações intermediárias ...

Usar fill para esses casos faz sentido para mim. Observe que queremos um novo método fill(x, A) = fill!(x, copymutable(A)) para substituir os métodos correspondentes de ones etc.

@TotalVerb Com uma rápida ones lá, talvez até a maioria (e mesmo se fossem apenas 20%, acho que meu argumento ainda está de pé).

(Eu também tenho reservas sobre o argumento da legibilidade, acho que é questionável afirmar que, por exemplo, fill(2, 2, 2, 2) é mais legível do que 2 * ones(Int, 2, 2, 2) , ou que, digamos, fill(k * 1.0, 3) seria mais legível do que k * ones(3) ; não estou absolutamente convencido de que seja apenas uma questão de hábito. Este é um ponto secundário.)

verdadeiros / falsos não podem ser substituídos diretamente por preenchimento, mas precisam ser usados ​​preenchimento! com um inicializador BitArray. Eles também não estão incluídos na ambigüidade entre uma e uma unidade. Portanto, não acho que eles se encaixem nessa discussão.

De fato, trues e falses não são diretamente substituíveis por fill :). Em vez disso, trues e falses são instâncias adicionais do problema geral descrito acima / relacionado a # 11557 (e que a direção recente dos construtores de array, espera-se, resolverá). Outros exemplos incluem a existência de, por exemplo, bones , bzeros , brand , brandn e beye em BandedMatrices.jl e equivalentes com um Prefixo d em DistributedArrays.jl.

Quanto a alguns, geralmente me oponho a rejeitá-lo de qualquer maneira, não vejo benefício. O argumento de que alguma expressão pode ser escrita de forma mais eficaz com preenchimento não é muito convincente na minha opinião, já que todos esses exemplos usam alguns como etapas intermediárias para fazer outra coisa

Tendo acabado de reescrever algumas centenas de usos de ones na base, posso afirmar a declaração de @TotalVerb

uma rápida pesquisa no GitHub revela que quase todos os usos de uns deveriam realmente estar usando fill para evitar alocações intermediárias ...

(Editar: embora eu diria mais ou menos a metade em vez de quase todas, e as reescritas apropriadas podem ser algo diferente de fill .) Além disso, essa experiência de reescrita me ensinou ...

mas e quando você realmente quiser uma variedade de uns? Então, ter que usar o preenchimento é mais longo, menos óbvio e apenas mais irritante.

... que por outro lado, fill é frequentemente mais curto e mais simples neste caso: os pedidos frequentemente não são Float64 (em vez disso, por exemplo, ones(Int, n...) e ones(Complex{Float64}, n...) ), neste caso fill é mais curto e simples ao admitir um literal (por exemplo, fill(1, n...) e fill(1.0 + 0im, n...) ). Em termos mensuráveis, o branch no qual tenho reescrito ones chamadas na base é ~ 5% mais curto pela contagem de caracteres de ones -> fill reescritas. Melhor!

Para ter uma ideia objetiva de como ones aparece na natureza, eu coletei todas as ones chamadas que aparecem nas primeiras dez páginas de uma pesquisa no GitHub por ones no código Julia, reescrito cada chamada conforme apropriado e classificou a mudança correspondente (veja esta essência ) e, em seguida, reduziu os dados de classificação para o seguinte resumo:

A análise incluiu 156 ones chamadas. Dessas ligações,

  • 84 chamadas (~ 54%) foram ad hoc fill s. (Por exemplo, ones(100)/sqrt(100)*7 simplifica para fill(7/sqrt(100), 100) ou, melhor ainda, fill(.7, 100) . Meu favorito era kron(0.997, ones(1, J*J*s) -> fill(0.997, 1, J*J*s) .)

  • 3 chamadas (~ 2%) eram transmissões ad hoc. (Por exemplo, A - ones(n,n) simplifica para A .- 1. .)

  • 5 chamadas (~ 3%) eram literais de vetor ad hoc. (Por exemplo, ones(1) simplifica para [1.] .)

  • 1 chamada (~ 0,5%) era semanticamente uma construção de matriz de lixo. (Embora relativamente incomum na natureza, esse padrão é bastante comum em test/ porque não temos um construtor de conveniência conciso para Array s não inicializados, como em, por exemplo, <strong i="32">@test_throws</strong> DimensionMismatch BLAS.trsv(...,Vector{elty}(n+1)) versus <strong i="34">@test_throws</strong> DimensionMismatch BLAS.trsv(...,ones(elty,n+1)) .)

As chamadas restantes eram semanticamente razoáveis ​​como ones , embora frequentemente ones usado meramente porque é curto, e não porque one s especificamente são necessários. Dessas chamadas restantes,

  • 13 chamadas (~ 8%) foram ligeiramente mais curtas para fill . (Por exemplo, ones(Int, n, n) -> fill(1, n, n) ou ones(Float64, n) -> fill(1., n) .)

  • 50 chamadas (~ 32%) demoraram um pouco mais: fill . (Por exemplo, ones(n, n) -> fill(1., n, n) .)

No geral, na natureza ~ 60% das chamadas ones são melhor escritas de outra forma, ~ 8% são razoavelmente semanticamente ones e ligeiramente mais curtas quanto fill , e ~ 32% são razoavelmente semanticamente ones e um pouco mais longo quanto fill .

Uma observação adicional:

Eu encontrei apenas uma instância de uma chamada ones aceitando um argumento de array, e não estava claro se o snippet delimitador era um código real. Portanto, os métodos ones que aceitam um argumento de array têm pouco ou nenhum uso em campo.

Discussão realmente interessante ... passou de contra para a favor ... Também como outro precedente de linguagem, R usa rep e matrix de uma maneira que é equivalente a fill (apenas correspondendo aos casos 1d e 2d) e você se acostuma rapidamente - embora eu tenha vindo de um mundo de zeros / uns.

Uau, obrigado @ Sacha0 por se esforçar!

A questão surge naturalmente como "e quanto a zeros "? Suponho que haverá muito mais uso e mais algumas categorias de uso (incluindo coisas como "Simplesmente não confio em matrizes não inicializadas" ou "Não sei como usar os construtores Array ").

Por alguma razão (acho que é a simetria de one e zero ), estou um pouco atraído por substituir ones e zeros por fill ou nenhum.

O problema com zeros é que você parece estar em uma destas situações:

  1. Você precisa sobrescrever a maioria dos zeros - neste caso, é melhor usar uma compreensão;
  2. Você não precisa substituir a maioria dos zeros - neste caso, é melhor usar uma matriz esparsa;
  3. Na verdade, você precisa de uma matriz totalmente zero - neste caso, é melhor usar 0I .

Não há nenhum caso de uso em que alocar uma matriz de zeros densos seja uma boa ideia.

Isso talvez seja verdade na álgebra linear. Não é incomum precisar de uma coleção inicializada com zero em meu trabalho com compiladores e outras estruturas de dados. Talvez eles sejam esparsos, mas não vale a pena o impacto no desempenho representá-los de forma compacta.

Muito justo - às vezes você não se preocupa com a densidade e a simplicidade vale a pena.

Triagem: resolvido que manteríamos apenas os métodos completamente não genéricos, ou seja, zeros(dims...) e ones(dims...) e talvez zeros(dims) e ones(dims) também.

@StefanKarpinski para recomendações de uso significa que recomendaríamos zeros(3, 3) vez de fill(0.0, 3, 3) para código normal (quando uma matriz densa é desejada etc etc)? Alguns dos detalhes de eficiência etc. estão fora do meu alcance, estou apenas pensando em como ensinaria as melhores práticas / idiomáticas em julia daqui para frente.

Esta decisão me parece muito surpreendente, não é tão comum na base para prevenir especificamente a genericidade. Qual é o raciocínio por trás? será que essa função vem do matlab onde não é genérica (e funciona apenas com floats)?

Triagem: resolvido que mantemos apenas os métodos completamente não genéricos

Qual é o raciocínio por trás?

Além disso, esse problema está de alguma forma relacionado ao problema geral de construção de matrizes que parece estar sendo considerado agora e, em caso afirmativo, como isso ajuda? Ou estamos tentando reduzir o número de métodos exportados de Base ? (Ou algo totalmente diferente?)

Escrita em breve em https://github.com/JuliaLang/julia/issues/24595 :). Melhor!

O OP de 24595 detalhou o contexto mais amplo desta questão, e agora um acompanhamento em # 24595 aborda especificamente os construtores de conveniência ones , zeros e fill em profundidade. Ler o primeiro é valioso para apreciar o último. Melhor!

Bem, salvar pelo menos a caixa Float64 é melhor do que nada.
Acredito que o caso de zeros inteiros também seja bastante relevante, o que - presumo - é basicamente o que @vtjnash estava fazendo aqui .

Também deve ser notado que zeros não tem o "problema" de permitir o anti-padrão 3 * ones(n) . Na verdade, eu realmente não vejo por que ones e zeros deveriam andar juntos, exceto no sentido amplo de serem construtores de conveniência. Não existe uma "simetria" real entre os dois.

Alguns comentários adicionais sobre a análise estatística , uma vez que parece ser a base das discussões a seguir e da redação do # 24595. Em primeiro lugar, dez páginas não são realmente suficientes para conclusões detalhadas do que está acontecendo no mundo selvagem; elas podem dar uma ideia aproximada, na melhor das hipóteses. Alguns arquivos vieram direto do matlab, por exemplo, como fica claro pelo seu nome / estilo. Em segundo lugar, como eu suspeitava, mesmo essa análise mostra que cerca de metade dos usos de ones eram "legítimos". Em terceiro lugar, olhar para um código como este não diz nada sobre quando escrever 3 * ones(...) é realmente um antipadrão que cria problemas de desempenho, ou é um pedaço de código que não tem nenhuma implicação de desempenho (e o escritor pode decidiram que é apenas mais legível escrito dessa forma - o que eu fortemente sinto que ninguém deve decidir o contrário, nesse caso).

Em relação ao último ponto, e acho mais importante, o que você vê em uma pesquisa no github nunca levará em consideração o que está acontecendo no REPL de pessoas fazendo trabalho exploratório / preliminar em Julia. Que é exatamente onde as funções de conveniência são mais úteis, e retirá-las sem motivo aparente é correspondentemente mais irritante. Meu ponto é, ter um conjunto consistente de primitivas ortogonais que permitem escrever código genérico e eficiente é um grande objetivo, e o esforço para chegar lá é verdadeiramente louvável; só que nem todo código deve ser um código de biblioteca bonito, genérico e composto. Apenas meus dois centavos.

Em relação a

Acredito que o caso de zeros inteiros também seja bastante relevante, o que - presumo - é basicamente o ponto que @vtjnash estava fazendo aqui.

que se refere a

Não é incomum precisar de uma coleção inicializada com zero em meu trabalho com compiladores e outras estruturas de dados. Talvez eles sejam esparsos, mas não vale a pena o impacto no desempenho representá-los de forma compacta.

Observe que fill serve tão bem ou melhor nesse caso: fill(0, shape...) versus zeros(Int, shape...) .

Sobre seus outros pontos, # 24595 pode valer a pena ler :). Melhor!

Eu simplesmente acho que zeros(Int, 10, 10) é mais legível / explícito do que fill(0, 10, 10) , e zeros(T, k) é melhor do que fill(zero(T), k) . Por que não podemos simplesmente ter os dois? Eu não acredito no argumento de que zeros sofre o mesmo problema de ambigüidade que ones .

Sobre seus outros pontos, # 24595 pode valer a pena ler

Eu tinha lido isso. (Eu até associei.)

Eu tinha lido isso. (Eu até associei.)

Tendo lido o # 24595 na íntegra e dado a devida consideração, você está ciente de que o # 24595: (1) diz respeito a uma questão muito mais ampla da qual os construtores de conveniência são apenas uma parte; e (2) considera muito mais do que apenas a análise estatística postada acima e os pontos que você enfoca aqui.

Agradeço sua opinião sobre ones e zeros ; seu sentimento veio alto e claro :). Como tal, é provável que nossa largura de banda seja mais bem gasta empurrando outras frentes para a frente do que continuar esta conversa em sua forma atual. Melhor!

Existe uma entrada genérica de fill junto com a mudança de zeros ? zeros tinha um uso muito legítimo para programação genérica, pois é muito mais seguro do que similar , então tudo de DiffEq, e eu sei que recentemente Optim e NLsolve mudaram de alocação com similar para zeros pois saber que tudo está alocado para conter zeros evita muitos bugs. No entanto, agora parece que não haverá nenhum método para:

zeros(X)

mais, diferente de:

similar(X); fill!(X,0)

porque o fill atual apenas constrói Array s e, portanto, não corresponde ao tipo como similar ou zeros . Eu sei que algumas pessoas usaram zeros indevidamente para alocar quando não deveriam, mas alocar com zeros é uma coisa muito razoável de se fazer em muitos casos. Espero que uma abreviatura fill(0,X) seja adicionada para preencher este vazio.

Muito obrigado pela postagem atenciosa Chris! :) Como uma substituição provisória de taquigrafia, zero(X) faz o truque?

Observe que tais casos de uso são precisamente onde a ambigüidade em zeros e ones pode ser problemática: zeros(X) produz um objeto com eltype(X) e preenchido com eltype(X) Identidade aditiva de fill!(similar(X), 0) ), ou em vez disso, um objeto preenchido com um zero multiplicativo para eltype(X) (possivelmente não de eltype(X) )? (Para expansão, consulte # 24595.)

O conceito fill(0, X) vê um pouco de discussão em # 11557, e eu concordo que pode ser uma generalização útil de fill . Obrigado e melhor!

O outro problema é que arrays com índices não convencionais podem querer ser criados com algo como zeros(inds...) (porque o tipo de índice determina o tipo de array ). Mas para um caso 1-d, X "é o array ao qual você deseja ser semelhante" ou "os índices para o array desejado"? (Afinal, AbstractUnitRange <: AbstractArray .) Concretamente, zeros(3:5) significa fill!(similar(3:5), 0) ou fill!(OffsetArray(Vector{Float64}(3), 3:5), 0) ?

Vinculando https://github.com/JuliaLang/julia/pull/24656 , que contém uma discussão adicional sobre {ones|zeros }(A::AbstractArray, ...) construtores de conveniência. Melhor!

Estou surpreso que seja considerado estranho usar zeros para criar variáveis ​​de cache de acordo com # 24656. Eu pensaria que, se zeros fosse reduzido a quase zero despesas gerais, quase todos os casos em que as pessoas estão usando similar deveriam ser zeros já que isso tende a corrigir alguns insetos. Acho que devemos encorajar mais pessoas a fazer isso, já que similar pode ser bastante inseguro e não ter uma função e, em vez disso, reunir fill! + similar torna menos óbvio que é o que as pessoas deveriam estar fazendo. Aqui está um comentário sobre isso surgindo no Optim.jl:

https://github.com/JuliaNLSolvers/NLsolve.jl/issues/89#issuecomment -294585960

No entanto, concordo com @timholy que não é óbvio como deve ser interpretado. Deixe-me apontar para um exemplo realmente não simples em DiffEq.

https://github.com/JuliaDiffEq/MultiScaleArrays.jl

MultiScaleArrays.jl criou arrays abstratos que são estruturas semelhantes a gráficos recursivos que podem ser usados ​​nos solvers diffeq (e eu acho que pode ser compatível com Optim.jl e NLsolve.jl agora?). É uma boa conveniência para modelos biológicos, entre outras coisas. Quando o lançamos no solucionador ODE, há uma pergunta: o que devemos fazer os arrays de cache? Em alguns casos, é importante que o usuário receba de volta o array desejado, pois ele aparecerá em sua função ODE f(t,u,du) e ele desejará tratá-lo de acordo. No entanto, em outros casos, ele só aparece como algo contra o qual é transmitido internamente. Portanto, há dois tipos diferentes de variáveis ​​de cache.

Para lidar com isso, dê uma olhada no cache de um dos algoritmos:

https://github.com/JuliaDiffEq/OrdinaryDiffEq.jl/blob/master/src/caches/low_order_rk_caches.jl#L224 -L234

Aqui, rate_prototype = similar(u,first(u)/t,indices(u) é semelhante, mas com um tipo de unidade potencialmente diferente. Mas observe que há dois tipos separados aqui: similar(u) vs similar(u,indices(u)) . Eu interpretei isso como significando "coincidir com o tipo e a forma" vs "coincidir com a forma e o eltype, mas não precisa ser do mesmo tipo". Portanto, para um AbstractMultiScaleArray , o primeiro criará outro AbstractMultiScaleArray enquanto o outro, para velocidade, uma vez que não é visto pelo usuário, criará apenas um Array do apropriado Tamanho. Isso é então estendido para similar(u,T) e similar(u,T,indices(u)) .

Talvez isso seja apenas um trocadilho com o que já existe, mas acho que essa é uma distinção importante. Ao fazer programação genérica, você tem dois caches separados: caches voltados para o usuário que você deseja que os tipos correspondam às suas expectativas e caches internos que são usados ​​apenas pelo algoritmo e você deseja o máximo de velocidade possível.

Observe que eles estão usando similar porque eu estava com preguiça de inventar uma versão zeros dele. Na verdade, tenho um local separado que pode zerar algumas dessas matrizes porque se o usuário definir apenas du em seu cálculo derivado de f(t,u,du) , eles tendem a considerar implicitamente "o que eu não defini significa zero ", que só é verdade quando foi alocado com zeros , então tento pré-alocar usando zeros tanto quanto possível (o mesmo problema surge em NLsolve.jl para isso) .

Esperançosamente, essa explicação não foi muito confusa para seguir. Em todos os meus casos, posso apenas mudar para similar seguido por fill! , mas sei que alguns pacotes não mudarão e isso será uma fonte de bugs.

Interessante. Você está certo que similar(A, inds) pode criar um tipo diferente de similar(A) , mas em geral sempre pensei nisso como provavelmente criando o mesmo tipo, mas com índices diferentes. Por exemplo, se você precisar de um cache unidimensional para uma operação columnwise em um objeto 2-d, eu usaria similar(A, first(inds)) . (Claro que é um tipo diferente porque a dimensionalidade é um parâmetro de tipo, mas pode ser o mesmo tipo de contêiner abstrato.) Você também pode usá-lo para criar um cache 5x5 de um pequeno bloco, etc.

No geral, este parece ser um problema desafiador. É um pouco tarde no jogo, mas devemos apresentar same ? Ele poderia ter os mesmos argumentos que similar , mas o contrato seria que seria necessário retornar o mesmo contêiner abstrato.

Eu poderia suportar uma forma de um argumento de same , mas mesmo isso é complicado - note que same(a) não poderia retornar o mesmo tipo de array se a não suportasse setindex! porque same e similar só são úteis se você for escrever no array posteriormente. Poderíamos tornar isso um erro para a imutável, mas como uma interface para AbstractArray isso parece desnecessário (e talvez inútil) para fazer código genérico correto.

Da mesma forma, não podemos assumir que cada AbstractArray pode suportar diferentes tipos ou índices. Para mim, ter uma forma de dois ou três argumentos de same apenas introduziria erros de tempo de execução em vários lugares, enquanto daria às pessoas uma falsa sensação de segurança de que seu código genérico funcionará bem para qualquer AbstractArray entrada, quando isso não acontece.

Mas, para um caso 1-d, é X "a matriz à qual você deseja ser semelhante" ou "os índices da matriz desejada"?

Esta é outra razão pela qual sou a favor de keys retornar um contêiner com índices e valores idênticos e, em seguida, tornar isso um requisito de similar (a menos que você forneça um (alguns) inteiro (s) em caso em que Base.OneTo (CartesianRange) é assumido).

Esta discussão está se voltando para # 18161, e talvez deva continuar aí :).

A triagem mais recente tendia a manter apenas ones .

Dói mantê-los? Acho que ajuda as pessoas que vêm de entorpecidas a se sentirem em casa em Julia.

Fechando porque estamos mantendo ones e zeros .

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

dpsanders picture dpsanders  ·  3Comentários

Keno picture Keno  ·  3Comentários

sbromberger picture sbromberger  ·  3Comentários

TotalVerb picture TotalVerb  ·  3Comentários

helgee picture helgee  ·  3Comentários