Não tenho doutorado, nem qualquer outro tipo de diploma nem em ciências da computação nem matemática, nem qualquer outro campo. Não tenho experiência anterior com Scala nem qualquer outro idioma semelhante. Não tenho experiência nem com sistemas remotamente comparáveis. De fato, a única linguagem que eu tenho mais do que apenas um conhecimento superficial do qual ainda possui um sistema de tipos é Pascal, não exatamente conhecido por seu sofisticado sistema de tipos. (Embora não têm tipos de gama, que AFAIK praticamente nenhuma outra língua tem, mas isso não é realmente relevante aqui.) As outras três línguas que eu conheço são BASIC, Smalltalk e Ruby, nenhum dos quais ainda têm um sistema do tipo.
E, no entanto, não tenho problemas para entender a assinatura da map
função que você postou. Parece-me praticamente a mesma assinatura que map
tem em todos os outros idiomas que eu já vi. A diferença é que esta versão é mais genérica. Parece mais uma coisa C ++ STL do que, digamos, Haskell. Em particular, ele abstrai do tipo de coleção concreta exigindo apenas que o argumento seja IterableLike
, e também abstrai do tipo de retorno concreto exigindo apenas que exista uma função de conversão implícita que possa criar algo a partir dessa coleção de valores de resultados. Sim, isso é bastante complexo, mas na verdade é apenas uma expressão do paradigma geral da programação genérica: não assuma nada do que você realmente não precisa.
Nesse caso, map
na verdade , não é necessário que a coleção seja uma lista, ou seja ordenada ou ordenada ou algo parecido. A única coisa que map
importa é que ele possa acessar todos os elementos da coleção, um após o outro, mas em nenhuma ordem específica. E ele não precisa saber qual é a coleção resultante, ela só precisa saber como construí-la. Então é isso que a assinatura do tipo requer.
Então, ao invés de
map :: (a → b) → [a] → [b]
que é a assinatura de tipo tradicional map
, é generalizada para não exigir uma estrutura concreta, List
mas apenas uma IterableLike
estrutura de dados
map :: (IterableLike i, IterableLike j) ⇒ (a → b) → i → j
que é generalizado ainda mais, exigindo apenas a existência de uma função que possa converter o resultado em qualquer estrutura de dados que o usuário desejar:
map :: IterableLike i ⇒ (a → b) → i → ([b] → c) → c
Admito que a sintaxe é um pouco mais desajeitada, mas a semântica é a mesma. Basicamente, começa a partir de
def map[B](f: (A) ⇒ B): List[B]
qual é a assinatura tradicional para map
. (Observe como, devido à natureza orientada a objetos do Scala, o parâmetro da lista de entradas desaparece, porque agora é o parâmetro implícito do receptor que todo método em um sistema OO de despacho único possui.) Em seguida, generalizou de concreto List
para mais geralIterableLike
def map[B](f: (A) ⇒ B): IterableLike[B]
Agora, ele substitui a IterableLike
coleção de resultados por uma função que produz , realmente, praticamente qualquer coisa.
def map[B, That](f: A ⇒ B)(implicit bf: CanBuildFrom[Repr, B, That]): That
O que eu realmente acredito que não é tão difícil de entender. Na verdade, você precisa de apenas algumas ferramentas intelectuais:
- Você precisa saber (aproximadamente) o que
map
é. Se você forneceu apenas a assinatura de tipo sem o nome do método, admito, seria muito mais difícil descobrir o que está acontecendo. Mas como você já sabe o que map
deve fazer e sabe qual deve ser sua assinatura de tipo, pode digitalizar rapidamente a assinatura e se concentrar nas anomalias, como "por que isso map
leva duas funções como argumentos, não uma?"
- Você precisa realmente ler a assinatura de tipo. Mas mesmo que você nunca tenha visto o Scala antes, isso deve ser bastante fácil, pois é realmente apenas uma mistura de sintaxes de tipo que você já conhece de outros idiomas: o VB.NET usa colchetes para polimorfismo paramétrico e usa uma seta para indicar o tipo de retorno e dois pontos para separar nome e tipo, é realmente a norma.
- Você precisa saber aproximadamente do que trata a programação genérica. (O que não é tão difícil de entender, já que está basicamente escrito em nome: é literalmente apenas programação de maneira genérica).
Nenhum desses três deve causar dor de cabeça a qualquer profissional ou programador amador. map
tem sido uma função padrão em praticamente todas as linguagens projetadas nos últimos 50 anos, o fato de diferentes linguagens terem sintaxe diferente deve ser óbvio para quem criou um site com HTML e CSS e você não pode assinar uma programação nem remotamente lista de discussão relacionada sem algum fanboy irritante de C ++ da igreja de St. Stepanov, explicando as virtudes da programação genérica.
Sim, Scala é complexo. Sim, o Scala possui um dos sistemas de tipos mais sofisticados conhecidos pelo homem, rivalizando e até superando idiomas como Haskell, Miranda, Clean ou Cyclone. Mas se a complexidade fosse um argumento contra o sucesso de uma linguagem de programação, o C ++ teria morrido há muito tempo e todos nós estaríamos escrevendo Scheme. Há muitas razões pelas quais o Scala provavelmente não será bem-sucedido, mas o fato de os programadores não se incomodarem em ligar o cérebro antes de se sentar na frente do teclado provavelmente não será o principal.