Julia: sintaxe: separe a concatenação da matriz da construção da matriz

Criado em 5 jun. 2014  ·  145Comentários  ·  Fonte: JuliaLang/julia

Muito ranger de dentes deriva da sobreposição entre a sintaxe para a construção literal da matriz e a concatenação da matriz em Julia - em grande parte herdada do Matlab. Talvez devêssemos apenas usar uma sintaxe diferente para a construção de matriz de bloco inteiramente. Um pensamento seria este:

| a b
  c d |

Isso tem a vantagem de ser bem conciso e leve. Por exemplo, o idioma atual para expandir um intervalo em uma matriz é [1:10] que se tornaria |1:10| enquanto [1:10] construiria uma matriz de um elemento do tipo UnitRange{Int} .

breaking speculative

Comentários muito úteis

Só queria registrar minha forte preferência de que nenhum dos literais de array (incluindo matrizes) faça qualquer forma de concatenação. O comportamento de concatenação parece um MATLAB-ismo desnecessário para mim. Se estamos construindo LinAlg para ser amigável com a matriz de blocos, por que não deixar [A B; C D] fazer uma matriz de blocos?

Em relação às mudanças de sintaxe, a sintaxe que mais me atrai é a mencionada por @yuyichao , com vírgulas e ponto-e-vírgulas e sem sensibilidade a espaços em branco. Eu posso ver isso generalizando dimensões arbitrárias por ter outros símbolos como ponto-e-vírgula duplo ;; , sendo invariante de espaço em branco, permitindo matrizes de linha vs vetor, etc.

# vector
[1, 2, 3, 4]

# matrix
[1, 2;
 3, 4]

# 3D array
[1, 2;
 3, 4;;

 5, 6;
 7, 8]

A única coisa que às vezes me pergunto se seria melhor fazer isso na ordem de armazenamento e não na ordem "parece álgebra linear". Caso contrário, [1, 2, 3, 4;] é uma matriz 1x4, não uma matriz 4x1, parece estranho que o último ponto-e-vírgula possa fazer uma mudança tão drástica.

A última coisa que eu adoraria é um literal para matrizes 0-dimensionais, pois acho StaticArrays.Scalar extremamente útil para controlar broadcast , etc. A possibilidade aqui é [a] torna um zero-D array e [a,] formam um vetor 1D. Admito que alguns usuários podem achar isso desagradável, mas tem alguma lógica (com , sendo o primeiro separador dimensional e seguindo a mesma regra do final de ; , etc, mais nós temos que tratar tuplas de comprimento-1 com , à direita, como em (a,) portanto, há uma precedência.).

Todos 145 comentários

Se alterações significativas estiverem sendo consideradas para isso, votarei pelo uso de um delimitador explícito aqui. Vírgula, ponto e vírgula, qualquer coisa. Não é espaço em branco.

Bem, isso liberaria a capacidade de usar um delimitador explícito em vez de _requiring_ usando espaços em branco. Às vezes, ainda é bom usar espaços em branco, embora eu ache que poderíamos evitar isso, pois é um pesadelo de análise.

cópia de:

3737

2488

discussão de sintaxe relacionada:

6960

relacionado:

6491

A inconveniência de um caractere extra por elemento para delimitadores explícitos é menor em comparação com a inconsistência de análise IMO

Não é realmente uma cópia perfeita de qualquer um desses, embora esteja relacionado.

3737 é um dup exato. Até o título é quase o mesmo.

|...| parece um pouco determinante demais para o meu conforto. No OP, li | a b; c d | como a*d-c*b na primeira vez.

Conforme mencionado em outro lugar, a sintaxe {...} poderia ser disponibilizada, pois é completamente redundante de qualquer maneira (sempre pode usar Any[...] lugar). Eu gosto da ideia de tornar os colchetes realmente úteis!

+1 para fazer {...} concatenação (e fazer [ ] equivalente a Any[ ] vez de None[ ] ).

Consolidando de # 7293, gostaria de ver maneiras de construir N-vetores e matrizes Nx1, já que estamos distinguindo-os.

Recuperar {...} pode ser uma boa solução. [...] poderia realmente manter seu comportamento de concatenação, e {...} se tornaria a versão de não concatenação. Isso seria minimamente perturbador, pois {...} é usado com menos frequência e não concatena no momento. (Além disso, acho mais "intuitivo" do que os papéis invertidos, não tenho certeza por que ...)

Além disso, acho mais "intuitivo" do que os papéis invertidos, não tenho certeza por que ...

Talvez isso o lembre das listas de inicializadores do C ++ 11?

Talvez isso o lembre das listas de inicializadores do C ++ 11?

Acho que não, nem sei o que são! Não atualizei meu conhecimento de C ++ na última década ...

{...} sintaxe pode ser disponibilizada, pois é completamente redundante de qualquer maneira

FWIW, como alguém que faz um trabalho mais geral com Julia, discordo que a sintaxe {...} não seja útil. Eu posso definitivamente entender essa perspectiva daqueles que escrevem principalmente códigos sensíveis ao desempenho (e, portanto, ao tipo), mas quando você não quer pensar sobre o sistema de tipos, é ótimo ter uma saída de emergência conveniente.

(E redundante ≠ inútil - toda a sintaxe do array atual é essencialmente uma conveniência sintática, mas muitas vezes essas são importantes)

Gosto da sugestão de usar x = [] como abreviatura para x = Any[] , e
ter que dizer explicitamente x = None[] para criar um array None. Então nós podemos
recupere {...} para outra coisa e não há perda de conveniência.

Na quinta-feira, 18 de setembro de 2014 às 21h11, one-more-minute [email protected]
escreveu:

{...} sintaxe pode ser disponibilizada, pois é completamente redundante de qualquer maneira

FWIW, como alguém que faz um trabalho de propósito geral com Julia, eu discordo
que a sintaxe {...} não é útil. Eu posso definitivamente entender isso
perspectiva daqueles que principalmente escrevem desempenho- (e, portanto, tipo-)
código confidencial, mas quando você não quer pensar sobre o sistema de tipos em
tudo é ótimo ter uma saída de emergência conveniente.

(E redundante ≠ inútil - toda a sintaxe do array atual é essencialmente
uma conveniência sintática, mas muitas vezes essas são importantes)

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/JuliaLang/julia/issues/7128#issuecomment -56124658.

[] = Any[] definitivamente faz sentido, mas é um pouco separado - geralmente tenho que escrever literais array / dict que contêm elementos. Presumivelmente, recuperar {} significaria que eu teria que escrever Any[...] .

Em geral, Julia se sai muito bem com sua filosofia "nunca mencione tipos quando não estiver com vontade" - eu realmente acho que seria uma pena perdê-la.

Seria muito louco se |...| representasse um valor absoluto? De alguma forma, x = | x - 1 | parece muito bom para mim, mas por outro lado, _pode_ ser um pesadelo de análise.

Eu estou indo com muito louco. Qual norma você deseja (muito por onde escolher)? As normas são comumente necessárias o suficiente para merecer sua própria sintaxe?

Eu temia isso, só queria me livrar de pessoas sãs. Provavelmente a norma sqrt(dot(x,x)) para estruturas de dados 1d e amigos ( abs(x) para escalares, det(x) para matrizes?). Imagino que as normas sejam bastante usadas para vetores, embora a norma seja tecnicamente || x || para eles.

não seria autônomo | ou || criar muitos casos extremos de análise insanos? 2 | x | em REPL significa 2 bits ou x bits ou algo mais a ser seguido na próxima linha, ou 2 * norm( x ) ? Parênteses compostos com dicas direcionais como [| x |] , {| x |} , |: x :| etc. podem fazer mais sentido, pois podem criar ruído na linha. Ou começamos a usar colchetes Unicode ⟦⟧ ⟨⟩ ⟪⟫

Isso se aplicaria à proposta original também, certo? Destes, |: x :| parece o mais limpo.

Então {...} será a nova magia da Matriz ou a assinatura de tipo de uma Tupla?

Eu não acho que usar | | como colchetes vai acontecer. No entanto, seria ótimo ter uma abordagem geral para usar mais tipos de colchetes --- uma maneira padrão de analisar ⟦x⟧ , x⟦i⟧ , etc. x[] as getindex não tem uma generalização óbvia.

Muito bem ... temos o comportamento atual no nível de análise, antes mesmo de chegar ao que eles fazem

type   with prefix    without prefix
[]     ref           vcat (maybe hcat), comprehension
{}     curly         cell1d, comprehension (and in 0.4: tuple type?)
()     call          tuple, or nothing (AST abstracted it away)

(Uau, os colchetes usam tantos chapéus. Não tenho certeza se tenho todos eles listados.)

Novos colchetes podem seguir um padrão simplificado, mapeando em refdoublesquare e catdoublesquare para os casos prefixados e não prefixados. Em seguida, decidimos o que eles fazem: conjunto, norma, notação de matriz, abreviatura de dicionário, etc.

Os colchetes Unicode eu ficaria contente em analisar por agora. Mas alguns colchetes ascii alternativos como [| |] são uma possibilidade real para uso no Base.

então agora [| ... |] para construção de matriz é uma possibilidade real.

julia> [[1, 0] , [1, 0] ]
4-element Array{Int64,1}:
 1
 0
 1
 0

julia> [[1, 0] for i=1:2]
2-element Array{Array{Int64,1},1}:
 [1,0]
 [1,0]

Isso está consertado? Temos uma separação clara agora: espaços e pontos-e-vírgulas se concatenam, qualquer outra coisa constrói um array a partir de elementos.

Sempre não gostarei de espaços em branco como sintaxe para hcat . Mas é provável que esse navio já tenha navegado. A separação é certamente muito melhor após 8599, pelo menos.

Eu posso ver um caso de consistência em fazer todas as operações de concatenação (hcat, vcat e hvcat) sempre retornando pelo menos um array 2D. Veja esta postagem de Bill Hart na lista de usuários. Mas esse talvez seja um problema separado.

É possível criar um Array 1x1 ?? por exemplo, em algo como o seguinte exemplo (bobo):

julia> [1, 2] * [3 4]
2x2 Array{Int64,2}:
 3  4
 6  8

julia> [1, 2] * [3]
# fails

Aqui [3] , [3 ] , [3;] (todas as permutações que tentei) criam um Array{Int, 1} , seria bom se houvesse alguma forma de forçar 1x1 ...

julia> Array{Int, 2}([[1 3]]) # this is cheating
1x2 Array{Int64,2}:
 1  3

julia> Array{Int, 2}([[1]])
# fails

[1]' funciona. reshape é outra opção.

O hcat digitado está fazendo algo engraçado agora? https://groups.google.com/forum/#!topic/julia -users / E3G686bg9lE provavelmente vale seu próprio problema ... cc @SimonDanisch

Para literais com dimensões extras, algo como Int{2}[1;2;3;4] funcionaria ou parece muito diferente da sintaxe do parâmetro de tipo atual?

Você pode ter:

Int[1;2;3;4]     #4-element Array{Int,1} (unchanged)
Int{1}[1;2;3;4]  #same
Int{2}[1;2;3;4]  #4 x 1 Array{Int,2}
Int{2}[1,2,3,4]  #error?
Int{3}[1;2;3;4]  #4 x 1 x 1 Array{Int,3}
Int{3}[1 2; 3 4] #2 x 2 x 1 Array{Int,3}
Int{1}[1 2] #error

Presumivelmente, você exigiria um nome de tipo como {2}[x] pode parecer um pouco estranho.

Hm, isso parece um pouco estranho e confuso.
Eu gosto da solução [| discutida anteriormente, como @JeffBezanson sugeriu em Julia-users .
Ele nos permite diferenciar claramente entre concatenação e concatenação + nivelamento, o que parece ser a diferença crucial aqui.
Isso justificaria simplesmente tratar esses dois casos com sintaxe diferente, deixando bem claro o que vai acontecer:

# All cases with optional typing, ensuring that you don't end up with Any[], 
# which I think is what the typing is really for
[vec, vec] => [vec, vec] 
[vec vec] => 
[vec 
vec] 

[| vec, vec |] => [el1, el2, el3, el4, ...]
[| vec vec |]  => 
[el el2 
el3 el4]

Não sei como esqueci esse aqui quando abri o # 10338, porque é o mesmo (então vou fechá-lo em favor deste exemplar antigo). No entanto, não acho que isso deva se tornar a v0.5. Não há nada difícil na implementação, é apenas uma questão de decisão. E como a concatenação vs construção de array já está passando por mudanças em julia 0.4, seria chato alterá-lo novamente em 0.5. É melhor tomar a decisão correta e bem ponderada imediatamente e, em seguida, segui-la.

Espero que o seguinte resumo seja útil para as discussões restantes:

Como distinguir entre construção de array e concatenação?

_Proposta 1: distinção por tipo de separador _
Isso é o que existe atualmente no mestre, ou seja, pré-0,4

  • A construção da matriz usa vírgulas como em [a,b,c] ou T[a,b,c]
  • A concatenação usa ponto e vírgula para concatenação vertical e espaços para concatenação horizontal como em [A B; C D] ou T[A B; C D]
  • Observações: há apenas um construtor Vector=Array{T,1} puro, nenhum construtor Matrix=Array{T,2} puro que não concatena; construir Matrix com uma única coluna é difícil e requer truques usando reshape ou transpose que não é à prova de futuro, pois ambas as funções podem mudar no futuro (retornando um tipo especial de visualização em vez de um puro Array ).
  • A concatenação digitada não é totalmente funcional, pois não pode ser usada para concatenar matrizes duplamente aninhadas em um T=Array{...} ; talvez tenha que ir, mas isso significa que depende do conteúdo se T[ ... ] é permitido.
  • Espaços como separadores também são frequentemente criticados como difíceis de analisar e fáceis de cometer erros.

_Proposta 2: distinção por tipo de colchete _

  • Use um par de colchetes para a construção de array puro sem concatenação (por exemplo, [ ... ] ) e outro par de colchetes (por exemplo, [| ... |] ) para concatenação.
  • A quebra mínima com a v0.3 exigiria na verdade a convenção reversa, ou seja, [| ... |] para construção de array puro e [ ... ] para concatenação.
  • Ambos os vetores e matrizes podem ser facilmente construídos: [a, b, c, d] e [a b; c d] . Pode-se até usar vírgulas em vez de espaços na construção de matrizes como [a, b; c, d] e é fácil construir uma matriz com uma única coluna como [a; b; c; d] .
  • A concatenação digitada pode ser facilmente eliminada se desejado: há um par de colchetes que pode ser prefixado por um tipo e outro par que não pode.

Eu pessoalmente prefiro a proposta 2 - especialmente eliminando os espaços como separadores e usando vírgulas em seu lugar. Esta seria uma grande mudança revolucionária, que eu sinto que deveríamos ter feito há muito tempo.

Eu também preferiria a alternativa 2.

: 100: para a proposta 2)

Concordo que apoiar apenas vírgulas e ponto-e-vírgulas como separadores seria muito mais claro. Que tal fazer [a, b, c, d] criar um vetor de coluna (como atualmente), [a, b, c, d;] criar uma matriz de uma coluna, [a; b; c; d] uma matriz de uma linha e [a, b; c, d] uma matriz de bloco?

Igualmente a favor da proposta 2.

Desculpe, aperte o botão errado.

A opção 2 parece mais clara.

Supondo que usemos [| e |] para concatenação, acho que seria bom ainda permitir espaços / novas linhas para construção de matriz neste contexto, mas proibir espaços na construção de matriz normal e não concatenante . Acho que matrizes construídas assim são mais fáceis de ler com espaços.

Não gosto de espaços porque o código se torna sensível a espaços em branco. Se você tiver expressões de matriz que estão sendo concatenadas, não pode ter espaços nelas. Isso pode levar a bugs sutis e pode ser difícil de depurar.

Não tenho preferência forte pelos espaços. Uma sugestão poderia ser que o analisador permite espaços se cada elemento for um único símbolo e retorna um erro se ocorrerem subexpressões em combinações com espaços. Mas isso provavelmente também suscita muitas questões, e não tenho ideia de como isso é difícil para o analisador.

[a, b, c, d;] criar uma matriz de uma coluna, [a; b; c; d] uma matriz de uma linha

Você quis dizer o contrário com isso? Caso contrário, isso seria inverter a convenção atual e um pouco inconsistente com a versão da matriz de bloco.

Eu pessoalmente adquiri o hábito de usar hcat e vcat na sintaxe de função convencional com mais frequência. Espaços são realmente apropriados apenas quando cada entrada é um único identificador (único caractere mesmo) e o valor de cada um desses identificadores é um escalar. Pode aliviar um pouco a dor se hcat e vcat aceitarem o tipo de elemento como entrada. Talvez hvcat também, mas esse é um pouco mais complicado de usar manualmente.

@tkelman Minha ideia era que [a, b, c, d] cria um vetor de coluna com uma dimensão, então [a, b, c, d;] simplesmente adicionaria a segunda dimensão, mantendo a organização das entradas em uma coluna. Parece lógico dessa forma, mas na verdade vai totalmente contra o modo como funciona atualmente. Talvez precisemos de outro símbolo ...

Acho que essa é realmente a desvantagem de usar vírgulas em vez de espaços como separador horizontal no construtor de matriz; no construtor vetorial, as pessoas pensariam nele como um separador vertical, o que fica confuso. Eu estava em dúvida se deveria mencionar essa sugestão exatamente por causa disso.

Não gosto de espaços porque o código se torna sensível a espaços em branco. Se você tiver expressões de matriz que estão sendo concatenadas, não pode ter espaços nelas. Isso pode levar a bugs sutis e pode ser difícil de depurar.

Entenda isso (e entenda esse ponto de vista). Ainda prefiro espaços em algumas circunstâncias. ;-)

Bem antes de começar a usar o Julia, mudei do Matlab para Python / Numpy / Scipy e, embora estivesse feliz por poder fazer muito do que costumava fazer Matlab, lembro-me de ter ficado bastante irritado com o quão confuso e prolixo para as matrizes de tipo tornaram-se com vírgulas (e os colchetes do Python, que não são relevantes aqui). Para os usos que tenho, as matrizes geralmente parecem mais limpas com espaços.

O que posso dizer, sou "sensível ao espaço". ;-)

Alguém me diga se essa é uma ideia maluca ou se funcionaria. Livre-se de espaços como concatenação para uso normal. Mas escreva uma macro abreviada @[ que usa regras normais de análise de macro para espaços e tenta agir como o construtor de literal de array atual para casos simples. Posso estar errado, mas tenho uma leve suspeita de que muitos dos casos de uso em que os espaços atualmente não são ambíguos e mais compactos provavelmente também não precisam de uma especificação de tipo de elemento.

Não me ocorreu que @[ ] é a sintaxe disponível. Esperto.

Felizmente, eu não sou _completamente_ mal, e o analisador tem apenas uma única configuração "sensível ao espaço" usada por chamadas de macro e concatenação, portanto, as regras são as mesmas em ambos os casos.

Ah, conveniente, eles já compartilham da implementação. Então vou votar (editar: espere, eu já votei no ano passado - vote antes, vote frequentemente, certo?) Em [| |] como construção de concatenação que requer vírgulas, [ ] como matriz pura que requer vírgulas , e talvez para pessoas que realmente gostam de espaços, @[ ] como um array sensível a espaços. @[| |] como construtor de concatenação sensível ao espaço, mesmo?

Felizmente [1, 2; 3, 4] pelo menos analisa em 0.3.6 (mas não em 0.3.0? Terei que descobrir qual backport o corrigiu), então pelo menos essa sintaxe para matrizes de bloco poderia ser feita em Compat.jl . Para matrizes de linha única, a sintaxe de função hcat deve funcionar em ambas. Não acho que temos uma sintaxe atualmente para criar uma matriz de uma coluna diretamente (sem contar a transposição de um vetor duas vezes).

Enquanto estamos lançando grandes mudanças de sintaxe aqui, uma opção agora que { ... } está sendo disponibilizado seria {a, b, c} para construção de array e [a, b, c] para concatenação de array. Você pode usar vírgulas e ponto-e-vírgulas para ambos e eliminar os espaços. Na verdade, isso tem a vantagem de ser mais compatível com as versões anteriores de 0.3 e anteriores, já que [a, b, c] não mudaria o significado e {a, b, c} mudaria apenas o tipo de elemento. As principais desvantagens são que não há como expressar Any[a, b, c] e, uma vez que o modo sensível a espaço ainda existe para macros, ele ainda não remove inteiramente o modo de análise sensível a espaço. Uma das coisas que estou atento para espaços é algo como f a b para f(a,b) ou mesmo generalizar a in b . Talvez isso não seja incompatível com a forma como as macros são analisadas.

Vamos dar uma olhada neles

a = {1,2,3,4;
     3,2,3,4;
     7,2,3,1}

a = [1,2,3,4;
     3,2,3,4;
     7,2,3,1]

a = [|1,2,3,4;
      3,2,3,4;
      7,2,3,1|]

a = {1 2 3 4;
     3 2 3 4;
     7 2 3 1}

a = [1 2 3 4;
     3 2 3 4;
     7 2 3 1]

a = [|1 2 3 4;
      3 2 3 4;
      7 2 3 1|]

Eu acho que todas as soluções parecem bastante aceitáveis, enquanto os espaços parecem um pouco melhores do que , e { parecem um pouco melhores do que [| (provavelmente depende muito da fonte).
Mas eu não vejo a diferença como muito grande, então eu decidiria por conveniência e clareza.
Para pessoas que não estão acostumadas a matlab , faz muito mais sentido porque é congruente com o caso 1D e removerá espaços, então eu votaria em , vez de espaços.
Eu votaria contra { pois acho que digitar o array é muito importante. De que outra forma você forçaria a matriz a ser do tipo Any , ou um tipo abstrato comum?

No Scala, gostei que você pode escrever map sin A especialmente para f para f() . Mas também introduz alguma aleatoriedade em seu código, porque você pode escolher uma sintaxe ou outra de maneira arbitrária. O que é muito chato e torna parte do código difícil de ler.
Acho que votaria contra ... Não estou totalmente decidido a isso, mas acho que é uma ladeira escorregadia para facilitar a leitura;)

Por que não podemos ter digitado a construção do array se { ... } é usado para a construção do array. Não é simplesmente obtido sobrecarregando getindex , mas apresenta problemas de qualquer maneira se alguém tentar criar um array com um tipo de elemento Tuple . Mas o analisador poderia transformar um T{ ... } em uma chamada especializada, assim como existe atualmente typed_(h)(v)cat .

Eu acho que o principal problema é a compatibilidade com versões anteriores, ou seja, T[ ... ] ficaria obsoleto ou se tornaria uma versão digitada de concatenação.

@Jutho , o problema é que X{...} é a sintaxe para tipos paramétricos.

Ah sim, como posso não pensar nisso. Talvez eu deva tentar me concentrar em uma coisa de cada vez.

Acho que deveria funcionar de forma totalmente simétrica, dessa forma é mais fácil para o usuário aprender e ele não corre para o momento de "ei, por que o mesmo princípio não se aplica aqui, preciso perguntar na lista de discussão sobre isso comportamento estranho ".
Então, eu sugiro que T[ + T[| permaneça a sintaxe para definir o tipo de elemento resultante da matriz.

T[...] também é a sintaxe para indexação, o que não parece ser um problema na prática, mas é um pouco duvidoso.

O que eu estava tentando fazer é que usando novos colchetes para construção de array (por exemplo, [| ... |] mas claramente não { ...} ), podemos ter digitado a construção de array, ou seja, T[| ... |] poderia dar origem a uma chamada de construtor digitada especializada, que também funciona com T<:Tuple . Então [ ... ] seria concatenação, como era na v0.3 e antes, e T[ ... ] poderia ser preterido em favor de T[| ... |] . Essa parece uma estratégia de transição bastante suave.

@SimonDanisch : existem alguns problemas com a concatenação digitada, se você quiser usá-la com T<:AbstractArray . O que acontece se eu quiser chamar typed_vcat(Vector{T},a) onde a é algum objeto do tipo Vector{S} . Deve-se tentar converter a em Vector{T} , ou a ser expandido e os elementos individuais do tipo S serem convertidos em Vector{T} . Isso provavelmente depende do que S e T são, mas com mais níveis de aninhamento isso se torna essencialmente insolúvel. Isso e o problema de que T[...] interfere na indexação em um tipo de tupla.

Então eu acho que descartar a concatenação tipada é bom. Você força o tipo de elemento usando uma construção de matriz pura e não concatena (ou usa splatting para concatenações simples) ou usa a sintaxe de conveniência para concatenação e aceita o fato de que ela tem limitações.

... uma opção agora que {...} está sendo disponibilizada seria {a, b, c} para construção de matriz e [a, b, c] para concatenação de matriz.

Isso é muito semelhante à sintaxe do MATLAB, novamente - as matrizes de células têm comportamento de construção não concatenado. É claro que Julia faria algo digitado com mais precisão aqui, mas a estrutura é semelhante.

Entendo ... Que chatice! ;)
Embora eu achasse que a regra geral seria bastante simples.
Por typed_vcat(::Type{T}, A...) algo como:
Primeiro, tente nivelar qualquer iterável e, em seguida, tente converter os elementos para T.
Se seu vetor em A não tem Vector {T} como elementos, então não digite o elemento de vcat com Vector {T}.
Com a nova sintaxe, também seria muito mais fácil construir o vcat digitado de que você está falando:

a = Vector{Int}[|[[1],[1],[1]], [[1],[1],[1]]|] # [| for concatenation
#-> [[1], [1], [1], [1], [1], [1]]

Poderíamos usar {a,b,c} para construção de array e [a,b,c] para concatenação e criar uma sintaxe diferente para especificar o tipo de elemento. Por exemplo, talvez T@{a,b,c} ou T@[a,b,c] . Acredito que Int.{a,b,c} e Int.[a,b,c] também estão disponíveis.

Para especificar o elemento, poderíamos imitar Go colocando o elemento _after_
os colchetes:

x = {a,b,c}Int
y = [a,b,c]Float64

Na terça-feira, 10 de março de 2015 às 15:15, Stefan Karpinski [email protected]
escreveu:

Poderíamos usar {a, b, c} para construção de matriz e [a, b, c] para concatenação
e criar uma sintaxe diferente para especificar o tipo de elemento. Para
exemplo, talvez T @ {a, b, c} ou T @ [a, b, c]. Eu acredito que Int. {A, b, c} e
Int. [A, b, c] também estão disponíveis.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/JuliaLang/julia/issues/7128#issuecomment -78149861.

Acho que agora temos um constrangimento de colchetes. Passei a não gostar de concatenação de [a,b] . Ele apenas "se parece com" a construção de um array, por exemplo, se você conhece python. Um problema é que o comportamento em escalares ( [1,2,3] ) faz você pensar que ele faz a construção de um array. [ ] também são bens imóveis mais valiosos, pois têm uma aparência melhor e não exigem mudança. Acho que veríamos muito [1,2,3] , mas então você teria que se lembrar de mudar para uma sintaxe diferente para elementos mais gerais ou para especificar um tipo de elemento. Portanto, estar mais perto de matrizes de células matlab não é muito atraente para mim.

A construção da matriz é mais geral do que a concatenação da seguinte maneira interessante: se [a b; c d] fornecesse uma matriz 2x2 apenas referenciando a, b, c e d, você poderia obter a concatenação com uma chamada extra, por exemplo, blockmat([a b; c d]) . Além disso, isso é bastante eficiente, pois a quantidade de alocação extra não depende do tamanho dos argumentos. Seguir o outro caminho, começando com a concatenação, não é possível. Então, eu poderia viver sem sintaxe de concatenação facilmente.

+1
Também percebi hoje que sua sugestão anterior de ter uma função semelhante a python array para construir matrizes multidimensionais arbitrárias (com possivelmente N>2 ) de vetores aninhados ficaria muito feia se a construção de matrizes fosse necessária colchetes ou, pior ainda, os colchetes [| ... |] .

Embora uma possível advertência seja se você deseja construir uma matriz de blocos de forma que os diferentes blocos sejam desiguais e, portanto, possa haver um número diferente de blocos nas diferentes linhas. algo como
[A ; 1 2] onde A tem duas colunas.

Hmm sim, esse é um bom ponto. Essa é provavelmente uma das principais razões pelas quais as coisas são como são agora.
No entanto, é quase um recurso acidental; apenas as linhas funcionam dessa maneira e você não pode fazer o mesmo truque com as colunas. Eu me pergunto se existe uma solução inteligente.

Splatting 2D / nD?

R = [0.5 0.5; 0.5 0.5]
t = [2.0, 3.0]

Rt = [R... t...; 0 0 1]
# Gives: Rt == [ 0.5 0.5 2.0
#                0.5 0.5 3.0 
#                0.0 0.0 1.0 ]

Eu poderia viver com isso.

Acho que Stefan tem uma ideia interessante para adicionar sintaxe dedicada para especificar o tipo de elemento de uma construção / concatenação de array.

Isso separaria muito o resto das decisões de sintaxe das considerações atuais de quais casos especiais colidem com a sintaxe existente.

E embora eu realmente goste de usar, por exemplo, a sintaxe Int[x, y, z] , acho que já vimos que essa sobrecarga da indexação em tipos não é totalmente isenta de problemas. Esta pode ser uma chance de melhorar essa situação.

Eu votaria pessoalmente em uma sintaxe que não use @ , já que não quero ficar insensível à sensação de que há algo especial acontecendo quando está envolvido.

Eu acredito que a concatenação do matlab tem as mesmas limitações de hvcat , btw?

[] também são bens imóveis mais valiosos, uma vez que têm uma aparência melhor e não exigem mudança.

Isso mesmo, eles exigem AltGr. (Não estou tentando fazer um ponto para esta discussão em particular, apenas um gentil lembrete de que a perspectiva internacional sobre quais caracteres são fáceis de digitar pode variar.)

Hmm sim, esse é um bom ponto. Essa é provavelmente uma das principais razões pelas quais as coisas são como são agora. No entanto, é quase um recurso acidental; apenas as linhas funcionam dessa maneira e você não pode fazer o mesmo truque com as colunas. Eu me pergunto se existe uma solução inteligente.

Isso é verdade. Eu acho que não permitir blockmat([A; 1, 2;]) e ter que escrever blockmat([A; [1,2;]]) não é tão ruim. É mais simétrico, pois no caso da coluna você também precisaria escrever blockmat([A, [1; 2];]) . Observe, entretanto, que preciso de muitos pontos-e-vírgulas para preparar a entrada de blockmat se não usar espaços como separadores horizontais. No primeiro caso, quero construir uma matriz (2,1) contendo os elementos A e a (1,2) matrix [1,2;] . No segundo caso, quero construir uma matriz (1,2) contendo os elementos A e a (2,1) matrix [1;2] . Manter os espaços ao redor como separador horizontal seria útil para tais casos, ou seja, então torna-se

A=randn(2,2)
blockmat([A; [1 2]]) # adding an extra row A
blockmat([A [1; 2]]) # adding an extra column to A

que parece perfeitamente simétrico.

Observe também que poderíamos ter um literal de string personalizado blockmat e fazer este tipo de coisa:

X = blockmat"""
    A B
    C D
"""

Isso pode permitir que nos livremos da análise sensível a espaço para concatenação.

Outra possibilidade é preencher com matrizes vazias: blockmat([A []; B C]) , embora isso possa causar poluição de tipo.

Modo céu azul ativado:

Fila larga:

mat"""
    A -
    B C
"""

Coluna alta:

mat"""
    A B
    | C
"""

Matriz aumentada particionada:

mat"""
    A 0 X
    0 B |
"""

Eu votaria pessoalmente em uma sintaxe que não use @, já que não quero ficar insensível à sensação de que há algo especial acontecendo quando isso está envolvido.

+1 para isso.
Existe algo que fala contra [...]T / {...}T ?
Se seguirmos proposta blockmat 's @JeffBezanson, {...}T ainda poderia ser usado para FixedSizeArrays, permitindo que eles seguem os mesmos princípios para a criação de matrizes FixedSize.
Se combinarmos isso com , vez de espaços, sinto que a maioria das demandas básicas está satisfeita.
Os últimos casos de uso com os literais de string poderiam então ser uma adição a isso, provavelmente não vivendo na base.

a,b,c... = 1
const T = Int # T is in all cases optional

A = [a,b,c]T
#-> Array{T, 1}
B = [a, b, c; 
     c, d, f]T 
#-> Array{T, 2}
C = blockmat([A;A]) # and why not also: blockmat([A;A], T) 
#-> Array{T, 2}

AF = {a,b,c}
#-> FixedSizeArray{T, (3,)}
BF = {a, b, c; 
     c, d, f}T
#-> FixedSizeArray{T, (2,3)}
CF = {A;A}
#-> FixedSizeArray{ Vector{T, 1}, (1,2)}
DF = blockmat(CF)
#-> FixedSizeArray{T, (2,3)}
EF = blockmat({AF;AF})
#-> FixedSizeArray{T, (3,3)}. Probably more copies used than optimal?

Estou bem com isso, pois cobre meus casos de uso muito bem, mas não sei o que o pessoal do matlab vai pensar de sua preciosa concatenação.
Espero que não seja algo análogo a uma das minhas citações favoritas:

No início, o universo foi criado.
Isso deixou muitas pessoas muito zangadas e foi amplamente considerado uma má jogada.

Como essa é uma mudança crucial, influenciando diretamente como Julia é percebida, provavelmente deveríamos tratar isso um pouco mais analítico.
Poderíamos primeiro compilar uma lista de casos de uso, em seguida, outra lista com soluções que satisfaçam os casos de uso e, em seguida, poderíamos fazer uma enquete com o usuário.
Posso escrever algo mais tarde.

Seria bom ter estatísticas sobre pacotes.

Embora haja algumas vantagens em mover o tipo para o outro lado ( [1,2,3]Int ), a mudança parece um pouco estúpida para mim, como se estivéssemos apenas brincando com as pessoas.

Não acho que devemos escolher uma estrutura de dados sortuda para dar chaves. [ ] deve construir Arrays (não concatenar), e { } pode ser algo totalmente diferente. Sets e Dicts são usos justificáveis, mas acho que mesmo esses não são comuns o suficiente para precisar de colchetes especiais em vez de Set([a,b,c]) .

Então ninguém ganha {} ?
Eu concordo, não deve ser um tipo de dados de sorte arbitrário, mas sim ser baseado nas estatísticas de uso.
Além disso, FixedSizeArrays seria um bom caso de uso, pois precisa exatamente do mesmo conjunto de construtores que os arrays normais. (Embora eu entenda, se eles não forem usados ​​o suficiente para justificar sua própria sintaxe)
As listas prometidas (um pouco apressadas):

Casos de uso:

  • criação de vetor sem concatenação
  • criação de matriz sem concatenação
  • concatenando a criação de vetores
  • criação de matriz de concatenação
  • mantenha Julia perto da sintaxe do matlab , tornando mais fácil mudar
  • livrar-se de espaços
  • sintaxe concat para uma mistura de elementos e vetores
  • digitando o tipo de elemento de qualquer array criado
  • tornar tudo intuitivo de usar e com aparência suave (duh!)

Obviamente, há itens conflitantes nesta lista, como livrar-se de espaços enquanto se mantém próximo ao matlab.

Blocos de construção de implementação:

criação de vetor / matriz não concatenada
  • qualquer coisa criada com [ não é concatenante
  • introduza outra sintaxe ( { , | , [| , blockmat() ) para concatenação
livrar-se de espaços
  • use , vez de espaços
  • use literais de string para criação
sintaxe concat para uma mistura de elementos e vetores
  • use literais de string para criação
  • Splatting 2D / nD (também pode tornar a conatenação obsoleta)
  • use símbolos de espaço reservado
digitando o tipo de elemento de qualquer array criado
  • T [
  • ] T
  • T @ [

Implementações

satisfaz:
  • [x] criação de vetor sem concatenação
  • [x] criação de matriz sem concatenação
  • [x] concatenando a criação de vetor
  • [x] criação de matriz de concatenação
  • [] manter Julia próxima à [sintaxe do matlab]
  • [x] livrar-se de espaços
  • [] concat sintaxe para uma mistura de elementos e vetores (não explicitamente)
  • [x] digitando o tipo de elemento de qualquer array criado
  • [] tornar tudo intuitivo de usar e com aparência suave (blockmat não é muito bom para expressões aninhadas)
a,b,c... = 1
const T = Int # T is in all cases optional

A = [a,b,c]T
#-> Array{T, 1}
B = [a, b, c; 
     c, d, f]T 
#-> Array{T, 2}
C = blockmat([A;A]) # and why not also: blockmat([A;A], T) 
#-> Array{T, 2}

AF = {a,b,c}
#-> FixedSizeArray{T, (3,)}
BF = {a, b, c; 
     c, d, f}T
#-> FixedSizeArray{T, (2,3)}
CF = {A;A}
#-> FixedSizeArray{ Vector{T, 1}, (1,2)}
DF = blockmat(CF)
#-> FixedSizeArray{T, (2,3)}
EF = blockmat({AF;AF})
#-> FixedSizeArray{T, (3,3)}. Probably more copies used than optimal?

Não há tempo para adicionar permutações de implementação mais completas;)

Melhor,
Simon

Este é realmente um material v0.5? A interface de construção / concatenação de array já está mudando drasticamente de v0.3 para v0.4 e, em seguida, alterar drasticamente o mesmo aspecto da linguagem novamente na v0.5 parece que vai incomodar muitos usuários.

+1

Ah, acho que entendi mal o marco, ainda é material da v0.4. Bom ver e minhas desculpas pelo spam.

Da palestra de @JeffBezanson ontem aqui no JuliaCon2015, parece que {} pode ser dado a Tuplas.
Isso significaria que () para tuplas está obsoleto e {expr} funciona em vez de ter que lembrar de colocar , em (expr,) (algo que não me causou fim dos problemas nas minhas primeiras semanas)

parece que {} pode ser dado a tuplas.
Isso significa que () para tuplas está obsoleto

Não, {} seriam tuplas de tipos, os atuais Tuple{} . As tuplas de valores ainda usariam () .

Ah! OK, tudo bem também. Estou ansioso para o subtipo mostrado ontem.

OK, é hora de decidir como encerrar a parte 0,4 disso. Vejo três opções:

  1. Ative o novo comportamento [a,b] agora ( _oldstyle_array_vcat_ = false ).
  2. Produza um candidato a lançamento, dê às pessoas uma ou duas semanas para corrigir os avisos de suspensão de uso e, em seguida, ligue o interruptor.
  3. Deixe o comportamento antigo ativado e obsoleto para 0.4.

Eu voto em 1 ou 2.
cc @StefanKarpinski @ViralBShah

Eu voto em 1, mas provavelmente haverá gritos de angústia.

Em geral, tenho visto um número diferente de zero de testes de pacote que ainda exibem esse aviso agora. desligar isso quebrará o código antes que eles tenham a chance de ver e corrigir seu comportamento. Suspeito que muitos autores de pacotes têm seguido a recomendação de aguardar o lançamento de v0.4-pre para atualizar seu código da v0.3 e ficarão infelizes se seu código quebrar em vez de receber um aviso útil de depreciação.

Eu voto por não apressar isso (também conhecido como 3), uma vez que, aparentemente, não tem sido um grande problema por vários anos (já que está apenas sendo consertado agora).

Não se trata realmente de consertar um problema; é uma mudança de comportamento.

Eu ficaria bem com 2 também, que é a versão um pouco menos drástica de 1.

1 ou 2 aqui também (este mordeu meu filho de 9 anos na semana passada, ele ficou muito feliz em saber que ia ser mudado).

Nada além de 3 significa que qualquer pessoa que está executando apenas 0.3 irá, ao atualizar para a versão lançada de 0.4, encontrar uma quebra silenciosa, sem nenhuma recomendação sobre como consertá-la?

Nada além de 3 significa que qualquer pessoa que está executando apenas 0.3 irá, ao atualizar para a versão lançada de 0.4, encontrar uma quebra silenciosa, sem nenhuma recomendação sobre como consertá-la?

Sim. 3 é a única opção que realmente segue nossa política de suspensão de uso.

Política: para aqueles momentos em que você precisa de um motivo para não fazer o que todo mundo quer.

Eu concordo que é muito inconveniente - para registro, pessoalmente eu também prefiro fazer essa mudança agora. Mas eu não acho que podemos. Há mérito na "disciplina de liberação".

Pense nisso como uma motivação para fazer lançamentos mais frequentes: sorria :

No entanto, isso não é realmente uma depreciação. É uma grande mudança na semântica. Do jeito que as coisas estão, estamos nesse meio-termo estranho, onde há um aviso de sintaxe de que tanto era quanto será completamente válida. Bloquear essa sintaxe para um ciclo de lançamento inteiro seria frustrante ... mas também entendo que a quebra silenciosa também seria muito frustrante.

Eu gosto da opção 2 - há muitos pacotes quebrados na 0.4 agora. Vamos querer passar algum tempo no pré-estágio limpando as coisas e garantindo que tudo funcione. Também pode avisar as pessoas enquanto elas estão consertando as coisas e, em seguida, ligar o segundo candidato a lançamento. (Também teremos a chance de reconsiderar nesse ponto).

Ecoando o ponto de @vtjnash , vou apontar que eu fiz lobby por isso há algum tempo , mas outra pessoa disse que não podíamos mudar isso: stick_out_ language : .

Nenhuma opinião forte aqui sobre 1-2-3, mas está claro que o comportamento atual de _oldstyle_array_vcat_ = false é o que queremos manter? Achei que ao redor e abaixo aqui houvesse um certo consenso para separar totalmente a construção da matriz e a concatenação da matriz, não pelo tipo de separador usado, mas pelo tipo de colchetes usado. Este último compraria várias vantagens sobre o primeiro.

Esse é um ponto justo --- podemos querer uma revisão mais abrangente da sintaxe de concatenação, caso em que poderíamos deixar essa depreciação no lugar e mudar tudo de uma vez em 0,5.

Tenho certeza que [a,b] deve construir um vetor de 2 elementos. Podemos fazer outras alterações, mas não acho que isso deva mudar. Portanto, não é totalmente louco mudar apenas isso primeiro.

Até agora, as sugestões que mais gosto neste tópico são: [a b; c d] construir apenas arrays e [| |] concatenar e usar Int.[ ] para arrays digitados. [a,b,c;] para construir uma matriz de 1 coluna também está ok.

Eu votaria em 3. O pior cenário para 1 ou 2 é que alguém está fazendo algum tipo de análise com código privado que não está em um pacote e atualiza 0,3 -> 0,4 ​​apenas quando é lançado. Existem situações em que se podem obter resultados diferentes e incorretos sem nenhum aviso, o que, embora não seja provável na maioria dos usos, é uma possibilidade realmente assustadora.

O fato de podermos mudar ainda mais essa sintaxe no Arraymageddon é um ponto muito bom. Acho que isso derruba meu voto a favor de 3 e estou esperando para ver como tudo isso vai acabar.

Ok, deixaremos o aviso e esperamos poder consertar isso de uma vez por todas no Arraymageddon.

É uma boa ideia alterar a sintaxe de concation vs construção em duas etapas (sem falar sobre o período de depreciação). Se as pessoas aprenderem na v0.4 que [ a, b, c] não se concatenará mais, elas passarão para [a ; b; c] . Essa sintaxe, então, em um segundo ciclo, seria alterada novamente para um construtor de matriz de uma coluna não concatenante. Portanto, na v0.5 [a; b; c] provavelmente resultaria em uma depreciação com a sugestão de usar um par diferente de colchetes para concatenação, e a sintaxe final só seria resolvida na v0.6.

Eu esperava que a distinção baseada em colchetes (em vez de baseada em separadores) entre construção e concatenação fosse concluída na v0.4, embora ainda desabilitada em favor do comportamento antigo com aviso de descontinuação, e depois se tornasse habilitada na v0.5. Estou disposto a ajudar com o trabalho restante no lado julia, mas não posso oferecer ajuda no lado do analisador.

Por que [|...|] para concatenação? Isso seria [| a, b, c |] agir como vcat(a, b, c) ?
Nesse caso, por que não considerar também a ++ b ++ c , e não ter nenhuma sintaxe com [ e ] que se concatena?

Matrizes de bloco.

Estou cada vez mais a favor de escrever vcat(a, b, c) e hcat(a, b, c) e ter uma sintaxe literal de string para matrizes de bloco semelhante a esta:

mat"""
 A B
 C D
"""

Ele pode gerar o código ideal para construir a nova matriz a partir das entradas, o que é uma vantagem sobre a redução atual para chamadas vcat e hcat.

A ideia literal de string de @StefanKarpinski parece bastante interessante, e parece muito mais compreensível do que algo com [| e |] .

Pode-se também oferecer suporte a coisas convenientes como este:

mat"""
 A 1
 0 B
"""

Isso seria o equivalente ao que se expressa atualmente como:

[ A                            ones(size(A,1), size(B,2))
  zeros(size(A,2), size(B,1))  B                          ]

Sempre quis isso.

Também pode vir facilmente em diferentes sabores, como:

fixedmat"""
1 1 1
0 0 0 
"""
So +1 from me =)

@StefanKarpinski , também acabei de chegar a essa conclusão e seria muito bom. Embora talvez com I vez de 1 sendo substituído por eye vez de ones (embora ambos possam ser úteis). De qualquer forma, não tenho nenhum favor especial para uma sintaxe de concatenação, só queria deixar claro que seria terrível se em 0.4 houver um aviso de depreciação para usar ; para concatenação e então na v0.5 há outro depreciação advertindo que ; agora está reservado para um construtor de matriz sem concatenação e há ainda outra nova sintaxe para concatenação.

a redução atual para chamadas vcat e hcat

Na verdade, chamamos hvcat .

+1 para:

mat"""
 A I
 0 B
"""

embora, na prática, provavelmente deva ser blockmat"""...""" ou algo semelhante.

Em 14 de julho de 2015, às 17:49, Jeff Bezanson [email protected] escreveu:

a redução atual para chamadas vcat e hcat

Na verdade, chamamos hvcat.

Foi o que pensei, mas não o que vi quando experimentei.

Aceito ter alguma matriz de bloco alternativa ou sintaxe concat, mas colocar código em strings sempre me dá arrepios. Parece-me que poderíamos muito bem fazer algo como

<strong i="6">@mat</strong> [
  a b
  c d
]

mas colocar código em strings sempre me dá arrepios.

Sim! Sempre achei que representar código como strings era sempre o último recurso. _Quase_ tão ruim quanto jogar coisas em uma string e executar eval . Há muita liberdade. Eu amo sistemas rigorosos e rígidos com comportamento de erro claramente definido.

Na verdade, eu escolheria quase tudo _mas_ uma string.

Também:

  • IDEs passam por momentos terríveis com a conclusão e o realce dentro das strings

+1 para @mat .

+1 para @mat de mim também. Eu também me sinto muito desconfortável em colocar código em strings.

+1 para @mat . Eu concordo que é melhor / mais limpo do que cordas.

+1 para @mat também, é bom tirar as coisas da sintaxe especial embutida no analisador e nas macros.

Também não gosto de colocar código em strings, mas o problema de @mat é que o que vem depois da macro precisa ser uma sintaxe válida. Eu gostaria de me livrar da sensibilidade complicada de espaços em branco que ocorre dentro da sintaxe de concatenação de array. Ter a sensibilidade a espaços em branco dentro de mat"..." seria muito mais palatável.

@StefanKarpinski E quanto a sth gosta

<strong i="7">@mat</strong> [A, B;
      C, D]

Isso pode tornar o espaço em branco insensível.

Não acompanhei a discussão aqui de perto, sinto muito se isso já foi mencionado antes.

@StefanKarpinski você está dizendo que gostaria

mat"""
A B
  C D
"""

a ser traduzido para:

mat"""
A B 0
0 C D
"""

As definições seriam:

mat"""
longmatrixnameA B
C D
"""

ser inválido porque as colunas não se alinham verticalmente?

@tbreloff : não, eu não estava propondo isso. Acho que você precisa de zeros explícitos.

Estou indo e voltando sobre isso agora. Acho que a implementação pode realmente ser mais robusta com a versão mat"""...""" . É um pouco mais direto dividir / analisar / reconstruir a string se pudermos assumir que apenas símbolos e números são permitidos, especialmente se a sintaxe em torno de [] mudar ou se o layout AST mudar. Se, no entanto, quisermos que expressões arbitrárias sejam permitidas, como:

<strong i="8">@mat</strong> [
map(sin,rand(10,10)) a
b 0
]

então isso pode ser muito difícil de acertar com as cordas.

outras perguntas...
1) Se houver discrepâncias de tamanho, como você as trata? Pad com zeros? Jogue um erro?
2) Como lidar com formas incompatíveis como:

a = rand(1,2)
b = rand(1,3)
c = rand(1,4)
z = <strong i="15">@mat</strong> [
 a 0
 0 b
 c
]

# does z look like:
[ a1 a2 0 0
 0  b1 b2 b3
 c1 c2 c3 c4 ]

# or:
[ a1 a2 0  0  0
 0  0  b1 b2 b3
 c1 c2 c3 c4 0 ]

Para a abordagem mat""" , você não usaria apenas interpolação para esse caso? ie

mat"""
      $(map(sin,rand(10,10))) a
      b 0
      """

(talvez a e b devam realmente ser $a e $b também?)

Não acho que funcione:

julia> macro mat_str(e); dump(e); end

julia> mat"""
       sin(rand(2,2)) a
       b 0
       """
ASCIIString "sin(rand(2,2)) a\nb 0\n"

julia> mat"""
       $(sin(rand(2,2))) a
       b 0
       """
ASCIIString "\$(sin(rand(2,2))) a\nb 0\n"

Acho que a macro de string é uma ótima solução para construir pequenos literais de matriz sem vírgulas, permitindo a construção com colchetes adequados para exigi-los. Definitivamente, não deve ser uma solução genérica para construção / concatenação, embora você possa querer colocar um código arbitrário.

Estou um tanto cético quanto à necessidade, fora da pureza da linguagem, de uma sintaxe de construção Array{T,N} , N >= 2 , que não achatar os elementos. Com que frequência as pessoas criam matrizes de vetores? Talvez a macro pudesse ser usada para o comportamento de construção puro, já que deveria ser muito menos comum e o comportamento de concatenação atual pode permanecer? Também acho que usar colchetes diferentes é uma boa solução.

OK, que pena, pensei que a interpolação de strings ainda ocorria, antes de passar para a macro.
Claro, você _pode_ fazer o seguinte:

<strong i="7">@mat</strong> """
       $(sin(rand(2,2))) a
       b 0
       """
Expr 
  head: Symbol string
  args: Array(Any,(2,))
    1: Expr 
      head: Symbol call
      args: Array(Any,(2,))
        1: Symbol sin
        2: Expr 
          head: Symbol call
          args: Array(Any,(3,))
          typ: Any
      typ: Any
    2: ASCIIString " a\nb 0\n"
  typ: Any

Uma reclamação sobre DSLs que usam strings é a falta de destaque de sintaxe, mas eu me pergunto se isso é algo que poderia ser superado (no futuro) definindo lexer / parser para cada macro. Essa é uma outra lata de vermes.

A maioria das gramáticas de realce de sintaxe de editor de texto oferece suporte a gramáticas de aninhamento. No
Sublime, por exemplo, eu hackeei o julia.tmLanguage para destacar o SQL dentro
as funções / macros sql "..." ou query ("...") (acho que @Keno fez isso para C ++
também com cxx "..."). Não acho que isso tenha nada a ver com o Base.

Na quarta-feira, 15 de julho de 2015 às 10:50, Andy Hayden [email protected]
escreveu:

Uma reclamação sobre DSLs usando strings é a falta de destaque de sintaxe,
mas eu me pergunto se isso é algo que poderia ser superado (no futuro) por
definindo lexer / analisador para cada macro. Essa é uma outra lata de vermes.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/JuliaLang/julia/issues/7128#issuecomment -121676812.

@tbreloff

Poderíamos tornar a sintaxe inequívoca, sempre produzindo a menor matriz de saída possível.

a = rand(1,2)
b = rand(1,3)
c = rand(1,4)
z = <strong i="7">@mat</strong> [
 a 0
 0 b
 c
]
# ==>
[ a1 a2 0 0
 0  b1 b2 b3
 c1 c2 c3 c4 ]

z = <strong i="8">@mat</strong> [
 a 0
 0 b
 c 0
]
# ==>
[ a1 a2 0  0  0
 0  0  b1 b2 b3
 c1 c2 c3 c4 0 ]

Eu discordo que devemos alegar que não temos sintaxe sensível a espaço e, na verdade, devemos tê-la dentro de um tipo especial de string que dizemos às pessoas para usarem. Você ainda tem sintaxe sensível a espaço, além dos problemas adicionais de colocar o código em strings. Esta é uma construção de linguagem importante para nós, então devemos ser capazes de analisá-la apenas com nosso analisador normal. Isso facilita a vida dos escritores de outras macros ou ferramentas de análise de código. Se vale a pena ter alguma sintaxe, vale a pena tê-la no analisador real.

Uma das coisas que me atraiu em Julia foi a limpeza da linguagem - é bonita e (principalmente) fácil de compreender, mesmo para alguém que não é um cientista e que tem formação em programação em K&R C com pouca programação real nos últimos dois décadas. O que, entretanto, não é nada bonito e limpo é colocar o código em strings. Para mim, torna o código difícil de ler - é assim que meu cérebro está conectado. Da mesma forma, usar espaços em branco como separadores é simplesmente horrível do ponto de vista da legibilidade - eu certamente preferiria ver, e; como separadores obrigatórios. Também não tenho certeza se é uma boa ideia usar a abordagem macro, já que macros tendem a ser um pouco desligadas para pessoas altamente incompetentes como eu, mas certamente é melhor do ponto de vista de acessibilidade do que a coisa de string.

@ Jakki42 , você acha que a solução de string não é boa porque geralmente não oferece realce de sintaxe sensato? Em outras palavras, você aceitaria a solução se oferecermos realce de sintaxe especializado para ela?

Macros de string são como o oeste selvagem. A macro pode fazer _absolutamente qualquer coisa_. O que é incrível e poderoso, mas também pode ser louco e difícil de raciocinar.

Muitas pessoas têm uma aversão ao código em strings, devidamente aprendida. E eles estão certos. O código não tem lugar em uma string. Requer análise e avaliação de tempo de execução, o que é lento e uma armadilha de desempenho em quase todas as linguagens, pois não há como um analisador estático raciocinar sobre o que a avaliação pode resultar.

Mas as macros de string não retornam necessariamente o código em uma string. Eles podem implementar suas próprias regras de análise e colocar a expressão resultante diretamente no código circundante antes de ser compilado. Pode não haver diferença entre o texto de um arquivo de origem e o texto em uma macro de string. É tudo apenas texto analisado. Como um exemplo de brinquedo, aqui está uma macro de string que simplesmente transforma seu conteúdo separado por espaços em branco em uma adição entre todos eles:

julia> macro add_str(ex)
          toks = map(parse, split(ex)) # This could be more robust, but works as a simple example
          esc(Expr(:call, :+, toks...))
       end

julia> x = 2; y = 3;
       add"x y 2x*y sin(rand())"
17.775332435685616

julia> macroexpand(:(add"x y 2x*y sin(rand())"))
:(x + y + (2x) * y + sin(rand()))

Isso significa que eles podem implementar DSLs, adicionar marcação de rich text, pré-compilar expressões regulares, executar código C ++ e muito mais. O conteúdo de uma macro de string pode ser inteiramente de dados, ou pode ter suas próprias regras de interpolação (com código demarcado por $ ou \(…) ou quaisquer regras que desejar), ou pode ser inteiramente código Julia _in o mesmo escopo_ que seu código circundante, retornando uma expressão Juliana analisada.

Depois de tudo isso, ainda estou com @JeffBezanson. Se esta for uma construção importante o suficiente para ser incluída na biblioteca padrão, deve ser uma sintaxe analisada de primeira classe. Todas as outras macros de string incluídas na base atualmente seguem a semântica "inteiramente dados" ou "dados com interpolação" - adicionar isso causaria muita confusão, eu acho. A única maneira de ver uma história consistente aqui é se decidirmos que as macros de string de crase (# 12139) devem sempre conter código Julian no escopo e todas as outras macros de string devem ser predominantemente de dados de string (que podem ser códigos para outro idioma … O que é lamentável para Cmd ).

@SimonDanisch - para mim não é um problema de realce de sintaxe, mas a confusão da própria sintaxe - é confuso e pouco claro para mim, um desvio de como o resto da sintaxe se parece, como de uma linguagem diferente - eu não consigo olhar rapidamente embora isso, mas meu cérebro velho e lento precisa de muito esforço extra para entender o que está acontecendo. Talvez seja minha formação, mas para mim [], (), {} claramente encapsula algo, faz uma unidade ou bloco de algo e "" e '' sempre parecem apenas strings ou caracteres sem nenhum significado programático por dentro. Embora <> também formem uma boa abertura e fechamento, estou tão velho que, para meu cérebro, eles não equivalem a nada, a não ser maiores ou menores do que os símbolos, e é necessário um esforço extra para entender se eles querem ter algo significativo dentro. E espaço em branco - para mim é sempre apenas algo não relevante para a sintaxe, analisado.

De qualquer forma, lembre-se de que sou um usuário de baixa prioridade, certamente não sou membro dos principais grupos de público-alvo do idioma :-)

Acho toda a noção de macros de string para fazer matemática um pouco horripilante. Esta é uma sintaxe terrível. Não é apenas feio e confuso; é ad-hoc e inconsistente. Um princípio de design é que coisas semelhantes devem ser semelhantes e coisas diferentes devem ser diferentes. Normalmente, as macros de string devem fazer coisas semelhantes a strings. Por exemplo, o PyPlot usa L "..." para strings LaTeX. A sintaxe semelhante a string deve ser usada para objetos semelhantes a string. Pelo mesmo princípio, coleções de coisas como tuplas e matrizes devem usar [], (), {}.

Outro grande problema com macros de string, que foi levantado anteriormente, é que a sintaxe da linguagem deve ser analisada pelo analisador. As macros forçam sub-linguagens ad-hoc dentro de Julia com seus próprios analisadores alternativos. Isso é ruim para ferramentas que precisam analisar Julia (destaque de sintaxe foi mencionado) e é apenas um design ruim porque macros em geral são problemáticas. Minha maior implicância com Julia é que @sprintf é uma macro e não uma função. Outras linguagens conseguem fazer funções sprintf, por que Julia não consegue? Portanto, minha opinião é que precisamos de menos macros na linguagem central, não mais.

@dcarrera sua pergunta sobre a macro @sprintf foi muito bem respondida aqui no stackoverflow por @StefanKarpinski.

Abordamos grande parte do problema central aqui, alterando o significado de [a,b,c] para sempre fazer a construção de array. A sintaxe sensível a espaços em branco continua sendo um problema, mas não um grande problema. No 1.x podemos revisitar isso e experimentar novas sintaxes para isso e, eventualmente, poderíamos remover a sintaxe sensível a espaços em branco no 2.0, mas isso não vai acontecer no 1.0.

Só queria registrar minha forte preferência de que nenhum dos literais de array (incluindo matrizes) faça qualquer forma de concatenação. O comportamento de concatenação parece um MATLAB-ismo desnecessário para mim. Se estamos construindo LinAlg para ser amigável com a matriz de blocos, por que não deixar [A B; C D] fazer uma matriz de blocos?

Em relação às mudanças de sintaxe, a sintaxe que mais me atrai é a mencionada por @yuyichao , com vírgulas e ponto-e-vírgulas e sem sensibilidade a espaços em branco. Eu posso ver isso generalizando dimensões arbitrárias por ter outros símbolos como ponto-e-vírgula duplo ;; , sendo invariante de espaço em branco, permitindo matrizes de linha vs vetor, etc.

# vector
[1, 2, 3, 4]

# matrix
[1, 2;
 3, 4]

# 3D array
[1, 2;
 3, 4;;

 5, 6;
 7, 8]

A única coisa que às vezes me pergunto se seria melhor fazer isso na ordem de armazenamento e não na ordem "parece álgebra linear". Caso contrário, [1, 2, 3, 4;] é uma matriz 1x4, não uma matriz 4x1, parece estranho que o último ponto-e-vírgula possa fazer uma mudança tão drástica.

A última coisa que eu adoraria é um literal para matrizes 0-dimensionais, pois acho StaticArrays.Scalar extremamente útil para controlar broadcast , etc. A possibilidade aqui é [a] torna um zero-D array e [a,] formam um vetor 1D. Admito que alguns usuários podem achar isso desagradável, mas tem alguma lógica (com , sendo o primeiro separador dimensional e seguindo a mesma regra do final de ; , etc, mais nós temos que tratar tuplas de comprimento-1 com , à direita, como em (a,) portanto, há uma precedência.).

+1 para as regras propostas por @andyferris , exceto para a parte do array 0D ( [a,] soa muito complicado).

Por outro lado, [a,] seria consistente com o comprimento de 1 tuplas (a,) .

Além de todos os problemas, a sensibilidade ao espaço em branco é tão leve: chore:

[1 2 3
 4 5 6
 7 8 9]

vs

[1, 2, 3;
 4, 5, 6;
 7, 8, 9]

Relacionado a este problema: a construção de matrizes n x 1 surge frequentemente (por exemplo, isto e isto apenas no mês passado). Até que esse problema seja resolvido, faria sentido criar um item de FAQ para isso?

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