Non ho un dottorato di ricerca, né alcun altro tipo di laurea né in CS né in matematica né in effetti nessun altro campo. Non ho alcuna esperienza precedente con Scala né con nessun altro linguaggio simile. Non ho esperienza con sistemi di tipo anche remotamente comparabili. In effetti, l'unico linguaggio che ho più di una semplice conoscenza di cui ha persino un sistema di tipi è Pascal, non esattamente noto per il suo sofisticato sistema di tipi. (Anche se fa avere tipi di raggio, che per quanto ne so praticamente nessun altro linguaggio ha, ma che non è davvero rilevante qui.) Le altre tre lingue che conosco sono essenziali, Smalltalk e Ruby, nessuno dei quali nemmeno un sistema di tipo.
Eppure, non ho alcun problema a capire la firma della map
funzione che hai pubblicato. Mi sembra quasi la stessa firma che map
ha in ogni altra lingua che abbia mai visto. La differenza è che questa versione è più generica. Sembra più una cosa C ++ STL che, diciamo, Haskell. In particolare, si estrae dal tipo di raccolta concreto richiedendo solo che l'argomento sia IterableLike
, e si estrae anche dal tipo di ritorno concreto richiedendo solo l'esistenza di una funzione di conversione implicita che può costruire qualcosa da quella raccolta di valori di risultato. Sì, è piuttosto complesso, ma in realtà è solo un'espressione del paradigma generale della programmazione generica: non dare per scontato nulla che non sia effettivamente necessario.
In questo caso, in map
realtà non è necessario che la raccolta sia un elenco o sia ordinata o ordinabile o qualcosa del genere. L'unica cosa che map
importa è che possa accedere a tutti gli elementi della collezione, uno dopo l'altro, ma senza un ordine particolare. E non ha bisogno di sapere quale sia la raccolta risultante, deve solo sapere come costruirla. Quindi, questo è ciò che richiede la firma del suo tipo.
Quindi, invece di
map :: (a → b) → [a] → [b]
che è la firma di tipo tradizionale per map
, è generalizzato per non richiedere una struttura di dati concreta List
ma piuttosto soloIterableLike
map :: (IterableLike i, IterableLike j) ⇒ (a → b) → i → j
che viene poi ulteriormente generalizzato richiedendo solo l'esistenza di una funzione in grado di convertire il risultato in qualsiasi struttura di dati l'utente desideri:
map :: IterableLike i ⇒ (a → b) → i → ([b] → c) → c
Ammetto che la sintassi è un po 'più complessa, ma la semantica è la stessa. Fondamentalmente, inizia da
def map[B](f: (A) ⇒ B): List[B]
che è la firma tradizionale per map
. (Nota come, a causa della natura orientata agli oggetti di Scala, il parametro della lista di input svanisce, perché ora è il parametro del ricevitore implicito che ogni metodo in un sistema OO a spedizione singola ha.) Quindi si è generalizzato da un concreto List
ad un più generaleIterableLike
def map[B](f: (A) ⇒ B): IterableLike[B]
Ora, sostituisce la IterableLike
raccolta dei risultati con una funzione che produce , beh, praticamente qualsiasi cosa.
def map[B, That](f: A ⇒ B)(implicit bf: CanBuildFrom[Repr, B, That]): That
Che credo davvero non sia così difficile da capire. C'è davvero solo un paio di strumenti intellettuali di cui hai bisogno:
- Devi sapere (approssimativamente) cos'è
map
. Se hai dato solo la firma del tipo senza il nome del metodo, lo ammetto, sarebbe molto più difficile capire cosa sta succedendo. Ma dal momento che già sapete che cosa map
si dovrebbe fare, e si sa che cosa la sua firma tipo dovrebbe essere, è possibile analizzare rapidamente la firma e attenzione per le anomalie, come "perché questo map
introito due funzioni come argomenti, non uno?"
- Devi essere in grado di leggere effettivamente la firma del tipo. Ma anche se non hai mai visto Scala prima, questo dovrebbe essere abbastanza facile, dal momento che è davvero solo una miscela di sintassi di tipo che già conosci da altre lingue: VB.NET usa parentesi quadre per il polimorfismo parametrico e usa una freccia per indicare il tipo di ritorno e due punti per separare il nome e il tipo, è in realtà la norma.
- Devi sapere più o meno di cosa tratta la programmazione generica. (Che non è quello difficile da capire, dal momento che è praticamente tutto spiegato nel nome: è letteralmente solo programmando in modo generico).
Nessuno di questi tre dovrebbe dare a nessun programmatore professionista o anche un hobbista un forte mal di testa. map
è stata una funzione standard in quasi tutte le lingue progettate negli ultimi 50 anni, il fatto che lingue diverse abbiano una sintassi diversa dovrebbe essere ovvio per chiunque abbia progettato un sito Web con HTML e CSS e non è possibile abbonarsi a una programmazione anche remota mailinglist correlata senza alcuni fastidiosi fanboy C ++ della chiesa di Santo Stefano che spiegano le virtù della programmazione generica.
Sì, Scala è complessa. Sì, Scala ha uno dei sistemi di tipo più sofisticati conosciuti dall'uomo, in grado di competere e persino di superare linguaggi come Haskell, Miranda, Clean o Cyclone. Ma se la complessità fosse un argomento contro il successo di un linguaggio di programmazione, il C ++ sarebbe morto molto tempo fa e tutti scriveremmo Scheme. Ci sono molte ragioni per cui Scala probabilmente non avrà successo, ma il fatto che i programmatori non possano preoccuparsi di accendere il cervello prima di sedersi davanti alla tastiera non sarà probabilmente il principale.