Je n'ai pas de doctorat, ni aucun autre type de diplôme ni en CS ni en mathématiques ni d'ailleurs dans aucun autre domaine. Je n'ai aucune expérience préalable avec Scala ni aucune autre langue similaire. Je n'ai aucune expérience avec des systèmes de type comparables à distance. En fait, la seule langue que j'ai plus qu'une connaissance superficielle dont même a un système de type est Pascal, pas exactement connu pour son système de type sophistiqué. (Bien qu'il n'avoir des types de gamme, qui AFAIK à peu près pas d' autre langue a, mais ce n'est pas vraiment ici. Pertinent) Je sais que les trois autres langues sont BASIC, Smalltalk et Ruby, dont aucun n'a même un système de type.
Et pourtant, je n'ai aucun mal à comprendre la signature de la map
fonction que vous avez postée. Cela me semble à peu près la même signature que celle que map
j'ai vue dans toutes les autres langues. La différence est que cette version est plus générique. Cela ressemble plus à une chose C ++ STL qu'à, disons, Haskell. En particulier, il s'éloigne du type de collection concret en exigeant uniquement que l'argument soit IterableLike
, et s'abstient également du type de retour concret en exigeant seulement qu'il existe une fonction de conversion implicite qui peut construire quelque chose à partir de cette collection de valeurs de résultat. Oui, c'est assez complexe, mais ce n'est vraiment qu'une expression du paradigme général de la programmation générique: ne supposez rien que vous n'ayez pas à faire.
Dans ce cas, map
n'a pas réellement besoin que la collection soit une liste, soit ordonnée ou triable ou quelque chose comme ça. La seule chose qui map
compte, c'est qu'il puisse accéder à tous les éléments de la collection, l'un après l'autre, mais sans ordre particulier. Et il n'a pas besoin de savoir ce qu'est la collection résultante, il a seulement besoin de savoir comment la construire. C'est donc ce que requiert sa signature de type.
Donc, au lieu de
map :: (a → b) → [a] → [b]
qui est la signature de type traditionnelle pour map
, il est généralisé de ne pas nécessiter une structure concrète List
mais plutôt juste une IterableLike
structure de données
map :: (IterableLike i, IterableLike j) ⇒ (a → b) → i → j
ce qui est ensuite généralisé en exigeant uniquement l'existence d'une fonction capable de convertir le résultat en la structure de données que l'utilisateur souhaite:
map :: IterableLike i ⇒ (a → b) → i → ([b] → c) → c
J'avoue que la syntaxe est un peu plus maladroite, mais la sémantique est la même. Fondamentalement, cela commence à partir de
def map[B](f: (A) ⇒ B): List[B]
qui est la signature traditionnelle de map
. (Remarquez qu'en raison de la nature orientée objet de Scala, le paramètre de liste d'entrée disparaît, car c'est maintenant le paramètre récepteur implicite que possède chaque méthode dans un système OO à répartition unique.) Ensuite, il s'est généralisé d'un concret List
à un plus général.IterableLike
def map[B](f: (A) ⇒ B): IterableLike[B]
Maintenant, il remplace la IterableLike
collection de résultats par une fonction qui produit , enfin, pratiquement n'importe quoi.
def map[B, That](f: A ⇒ B)(implicit bf: CanBuildFrom[Repr, B, That]): That
Ce que je crois vraiment n'est pas si difficile à comprendre. Il n'y a vraiment que quelques outils intellectuels dont vous avez besoin:
- Vous devez savoir (grossièrement) ce qui
map
est. Si vous ne donniez que la signature de type sans le nom de la méthode, je l'admets, il serait beaucoup plus difficile de comprendre ce qui se passe. Mais puisque vous savez déjà ce qui map
est censé faire, et que vous savez ce que sa signature de type est censée être, vous pouvez rapidement scanner la signature et vous concentrer sur les anomalies, comme "pourquoi cela map
prend-il deux fonctions comme arguments, pas une?"
- Vous devez être capable de lire réellement la signature de type. Mais même si vous n'avez jamais vu Scala auparavant, cela devrait être assez facile, car il s'agit vraiment d'un mélange de syntaxes de types que vous connaissez déjà dans d'autres langages: VB.NET utilise des crochets pour le polymorphisme paramétrique, et en utilisant une flèche pour indiquer la retourner le type et deux points pour séparer le nom et le type est en fait la norme.
- Vous devez savoir à peu près ce qu'est la programmation générique. (Ce qui n'est pas si difficile à comprendre, car tout est essentiellement énoncé dans le nom: c'est juste une programmation générique).
Aucun de ces trois ne devrait donner à un programmeur professionnel ou même amateur un mal de tête sérieux. map
a été une fonction standard dans à peu près tous les langages conçus au cours des 50 dernières années, le fait que différentes langues ont une syntaxe différente devrait être évident pour quiconque a conçu un site Web avec HTML et CSS et vous ne pouvez pas vous abonner à une programmation même à distance. liste de diffusion connexe sans fanboy C ++ ennuyeux de l'église de St. Stepanov expliquant les vertus de la programmation générique.
Oui, Scala est complexe. Oui, Scala possède l'un des systèmes de types les plus sophistiqués connus de l'homme, rivalisant et même dépassant les langues comme Haskell, Miranda, Clean ou Cyclone. Mais si la complexité était un argument contre le succès d'un langage de programmation, C ++ serait mort depuis longtemps et nous serions tous en train d'écrire Scheme. Il y a de nombreuses raisons pour lesquelles Scala ne réussira probablement pas, mais le fait que les programmeurs ne puissent pas être dérangés pour tourner la tête avant de s'asseoir devant le clavier ne sera probablement pas le principal.