Sembra che manchi il punto di digitazione dinamica.
Non è insolito che funzioni ecc aspettino particolari tipi di dati degli argomenti anche in linguaggi dinamici. La documentazione di questo è proprio questo: documentazione, non codice. Alcuni tipi di asserzione sono spesso inclusi nel codice, tuttavia, per garantire che i requisiti dei tipi di dati siano soddisfatti.
Tuttavia, un linguaggio comune nelle lingue dinamiche è "digitazione anatra" - basato sulla frase "se cova come un'anatra, è un'anatra". Ciò significa che, se il valore passato supporta tutte le operazioni necessarie, generalmente non ti interessa quale sia il tipo esatto.
Quindi, il lato negativo delle lingue digitate dinamicamente è la mancanza di controllo automatico del tipo statico. Si ottiene ancora un controllo di tipo in fase di esecuzione: l'interprete (o compilatore JIT) tiene traccia del tipo di ciascun valore / oggetto, ma se si desidera un rigoroso controllo dei tipi lo si fa manualmente e in fase di esecuzione. Il vantaggio è maggiore praticità e flessibilità - e mentre potresti aver bisogno di un po 'più di test unitari per assicurarti la correttezza, dovresti comunque eseguire alcuni test unitari.
Il sistema di tipi usato da Haskell è un'interessante variante - tipizzata staticamente, ma le funzioni sono "generiche" per impostazione predefinita (dando una sorta di digitazione anatra), ma con un sistema di classe che consente di controllare la genericità (si può dire " questo argomento deve essere di qualche tipo che pretende di ciarlare come un'anatra ").
Modifica
Il punto è che esiste una "via di mezzo", in cui è possibile consentire a qualsiasi tipo di essere passato come argomento che supporta tutte le operazioni necessarie per impostazione predefinita, ma può limitare ulteriormente l'intervallo di tipi consentiti quando è necessario . Le funzioni generiche di default in Haskell sono pensate per essere viste come (anche quelle analoghe) usando la digitazione anatra in linguaggi dinamici, ma con l'opzione (specificando i vincoli di tipografia) per limitare quella libertà e recuperare qualunque sia il livello di cui hai bisogno tipo di sicurezza.
Anche questo non vuol dire che Haskell sia unico. Immagino che le stesse idee si applichino ai linguaggi della famiglia ML, anche se non sono mai stato un esperto in queste, e non ho nemmeno giocato con ATM per un po ', quindi non ho garanzie. In C ++, di solito descrivo i modelli C ++ come un "sottoinsieme funzionale in metaprogrammazione funzionale". Un modello C ++ è abbastanza simile a una funzione Haskell, infatti è una funzione valutata in fase di compilazione che restituisce una classe o una funzione. Gli argomenti (typename) sono digitati a forma di anatra - non esistono ulteriori restrizioni dirette se non che sono tipi. Sfruttare al massimo la flessibilità è un punto fondamentale della regola SFINAE. I concetti sono stati proposti (ma ritirati) da C ++ 0x per fare un modello WRT di lavoro simile a quello che fanno i typeclass Haskell per le funzioni - per fornire una via di mezzo limitando quella flessibilità.
Le interfacce Java sono correlate alle interfacce Haskell, ma non proprio la stessa cosa. In questo contesto, Java non è lo stesso di Haskell perché le funzioni Java non sono generiche per impostazione predefinita, anche se Java ha avuto il supporto per funzioni e classi generiche per un po 'di tempo. Non conosco bene Java, quindi non so se c'è un mezzo per quella "via di mezzo" o no.
Nei commenti, "tipizzazione strutturale" è stata descritta come l'equivalente di programmazione funzionale della digitazione anatra, il che è vero, tranne che è più l'equivalente tipizzato in modo statico della digitazione anatra. Prendi, ad esempio, questo tipo di funzione Haskell ...
mylength :: [a] -> Integer
L'argomento di input può essere una qualsiasi lista. L'ovvia parte di "duck typing" è che può prendere liste di qualsiasi tipo, ma tutti questi tipi e molti altri potrebbero essere accettati da una funzione con il seguente vincolo di tipo ...
myfunc :: a -> Integer
L'aspetto strutturale è che la firma mylength specifica che ogni argomento valido deve "ciarlare come un elenco". Questo differisce dal tipo di battitura a programmazione dinamica in cui il vincolo di "tipo di sottofondo" è esplicito, anche se ovviamente può essere dedotto.
Che cosa intendo per "ciarlatano come una lista"? Bene, l'elenco di Haskell viene sostanzialmente definito supportando le operazioni associate a un elenco. Ad esempio, una lista viene creata usando le operazioni ":" (spesso nascoste dietro lo zucchero a bretelle quadrate), quindi qualsiasi elenco può essere decostruito usando ":".
Non l'ho detto prima perché tutto ciò che significa veramente è che "è ciarlatano come un'anatra" viene controllato staticamente. Anche C lo fa fino ad un certo punto. Tuttavia, non fornisce (di per sé) quella via di mezzo che stavo cercando di descrivere. Anche se forse sostituendo il typedef C con il typedef D o un sottotipo Ada (un tipo distinto piuttosto che un alias) puoi ottenere la stessa via di mezzo nelle lingue imperative.