Esclarecimento sobre assinatura de função e comportamento de despacho em julia

8

Eu estava tentando algumas coisas no REPL Julia (1.2) e prendi minha mente em algo que não entendo sobre o envio.


Eu tentei pela primeira vez essa coisa que está funcionando da maneira que eu esperava:

f(a::T) where {T <: Int} = "Test"

  • Chamar f (3) funciona desde Int <: Int == true

  • Chamar f ("Hello") resulta em um erro "MethodError: no method matching" desde String <: Int == false


Então, tentei esse método e não entendo por que chamá-lo funciona em alguns casos:

f(a::T, b::U) where {T, U <: T} = "Another Test"

  • Chamar f (3, 3) funciona (como eu esperava)

  • MAS f (3, "Hello") também funciona e não gera um "MethodError: nenhum método correspondente" ???

Eu pensei que (desde que T se torna um Int e U uma String) String <: Int == false???


Acho que estou perdendo algo bem direto aqui, mas não consigo encontrá-lo ... Portanto, esta é a minha pergunta, por que f (3, "Olá") está funcionando ???


Além disso, eu tentei esse trecho de código (tentei recriar a segunda assinatura do método) e ele falhou corretamente como eu esperava:

Test = Tuple{T, U} where {T, U <: T}

Test{Int, String} (isso falha como eu esperava com "TypeError: no tipo, em U, U esperado <: Int64, obteve o tipo {String}")

SnoopyDoowop
fonte
1
Não consigo reproduzir sua última definição de f () retornando Int64,String,false. Pode ser necessário reiniciar a Julia se você adicionar métodos às funções. Basta usar um novo personagem, por exemplo, hpara um novo teste. Para sua pergunta: Parece que o sistema tenta encontrar qualquer solução para a restrição de tipo e T=Any, U=Any where U:<Té uma delas. Se você introduzir um tipo concreto, como no terceiro exemplo, ele funcionará conforme o esperado. Pessoas com um conhecimento mais profundo do sistema do tipo Julia darão em breve uma resposta adequada.
laborg 14/01
Oh! Você está certo, eu precisava reiniciar Julia ... Minha redefinição com T <: Int não substituiu a última com apenas T (sem nenhum aviso ...). E sua resposta sobre a localização do sistema Any como solução para T e U explica tudo! Obrigado :)
SnoopyDoowop 14/01

Respostas:

4

O que está acontecendo aqui é que Tpode ser um tipo de dados e Uqualquer supertipo de string. Este as condições são cumpridas. A única coisa que estava provocando você com uma string que não é um subtipo de int é um arenque vermelho, pois nenhum tipo concreto é o subtipo de qualquer outro.

Oscar Smith
fonte
E por que, com a definição de tupla, ocorre o erro?
Antonello
3

Ok, graças ao trabalho , parece que agora entendo o que estava acontecendo. Se usarmos este método:

f(a::T, b::U) where {T, U <: T} = "Another Test"

  • 'T' é o "UnionAll", também conhecido como "União Iterada" de todos os tipos possíveis de 'a'.
  • 'U' é o "UnionAll", também conhecido como "União Iterada" de todos os tipos possíveis de 'b' que são subtipos de 'T'

  • O que eu estava entendendo errado era o fato de que se (exemplo) a :: Int, então T pode pegar um tipo abstrato pai do tipo de (a). Desde Int <: Qualquer, então T = Qualquer é uma solução válida para envio.

  • O mesmo para U = Any desde String <: Any.

Portanto, agora temos U <: T que resolve como Any <: Any == true, e o método é chamado!

Espero conseguir :)

SnoopyDoowop
fonte
Você faz. Neste ponto, a sua é uma resposta melhor que a minha.
Oscar Smith