Bene, la digitazione debole vs. forte è definita in modo abbastanza vago. Inoltre, dal momento che l'uso più comune di "tipizzazione forte" è quello di riferirsi a cose che rendono difficile il cast di tipi, che non lascia altro per descrivere sistemi di tipi ancora più forti. È come dire che se riesci a trasportare meno di 30 libbre sei debole, e tutti coloro che possono sollevare di più sono nella stessa categoria di "forti" - una distinzione fuorviante.
Quindi preferisco la definizione:
- I sistemi tipicamente deboli usano tipi per impedirti di fare determinate cose (come errori)
- I sistemi fortemente tipizzati usano i tipi per fare le cose per te
Che cosa intendo per fare le cose per te? Bene, esaminiamo la scrittura di un'API di conversione delle immagini nel framework Servant (in Haskell, ma non è necessario conoscerla per seguirla, vedrai ...)
{-# LANGUAGE
TypeOperators,
DataKinds
#-}
import Codec.Picture
import Data.Proxy
import Network.Wai.Handler.Warp (run)
import Servant
import Servant.JuicyPixels
main :: IO ()
main = run 8001 conversion
Questo sta dicendo che vogliamo alcuni moduli tra cui il pacchetto Servant e il plug-in JuicyPixels su Servant e che il punto di accesso principale del programma è quello di eseguire la funzione 'conversione' sulla porta 8001 come server utilizzando il back-end Warp. Ignora il bit della lingua.
conversion :: Application
conversion = serve (Proxy :: Proxy ConversionApi) handler
Ciò significa che la funzione di conversione è un server in cui l'API deve corrispondere al tipo "ConversionApi" e le richieste sono gestite dalla funzione handler
type ConversionApi
= ReqBody '[BMP, GIF, JPEG 50, PNG, TIFF, RADIANCE] DynamicImage
:> Post '[BMP, GIF, JPEG 50, PNG, TIFF, RADIANCE] DynamicImage
Questo specifica il ConvesionApi
tipo. Dice che dovremmo accettare i tipi di contenuto in entrata specificati dall'elenco "[BMP, GIF, JPEG 50, PNG, TIFF, RADIANCE] e gestirli come DynamicImage e che dovremmo restituire un DynamicImage convertito nello stesso intervallo di contenuti tipi. Non preoccuparti esattamente di cosa:> significhi, pensalo come una magia felice per ora.
Quindi, data la mia definizione preferita, un sistema debolmente tipizzato può ora garantire cose come:
- Non si restituisce il tipo di contenuto in uscita errato
- Non si analizza la richiesta in arrivo come tipo di contenuto errato
- Se il nostro server fosse più complicato, ci impedirebbe di creare URI non validi, ma in realtà non stiamo restituendo alcuna pagina HTML per contenere collegamenti (e il tipo assicura che non possiamo!)
- Un sistema di digitazione molto ambizioso potrebbe persino verificare che stiamo gestendo in modo esaustivo tutti i tipi di contenuto in entrata e in uscita, consentendo al tipo di agire anche come documento di specifica anziché solo un vincolo.
Tutti obiettivi nobili, ma in realtà non abbastanza per qualificarsi come un sistema fortemente tipizzato, data la definizione di cui sopra. E ora dobbiamo arrivare alla parte più difficile della scrittura del codice che segue questa specifica. In un sistema di tipo davvero potente , scriviamo:
handler = return
E poi abbiamo finito. Ecco fatto, non c'è altro codice da scrivere . Questo è un server web pienamente operativo (modulo qualsiasi errore di battitura che ho perso). Il tipo ha detto al compilatore tutto ciò di cui ha bisogno per creare il nostro web server dai tipi e dai pacchetti (tecnicamente moduli) che abbiamo definito e importato.
Quindi, come impari a farlo nella scala delle applicazioni principali? Bene, in realtà non è molto diverso dal loro utilizzo in applicazioni su scala ridotta. Ai tipi che sono assoluti non importa quanto codice è scritto relativo a loro.
L'ispezione del tipo di runtime è qualcosa che probabilmente vorrai evitare, perché elimina una grande quantità del vantaggio e consente ai tipi di rendere il tuo progetto più complicato con cui lavorare, piuttosto che avere tipi semplifica le cose.
Come tale, è principalmente solo una questione di pratica modellare le cose con i tipi. I due modi principali per modellare le cose (o costruire cose in generale) sono dal basso verso l'alto e dall'alto verso il basso. Il top down inizia con il livello più alto di operazioni e quando si crea il modello si hanno parti in cui si rimanda la modellazione fino a dopo. La modellazione bottom-up significa che inizi con le operazioni di base, proprio come inizi con le funzioni di base, quindi costruisci modelli sempre più grandi fino a quando non hai acquisito completamente l'operazione del progetto. Bottom up è più concreto e probabilmente più veloce da costruire, ma top down può informare meglio i tuoi modelli di livello inferiore su come debbano comportarsi effettivamente.
I tipi sono il modo in cui i programmi si relazionano letteralmente con la matematica, quindi non c'è davvero un limite superiore a quanto possano essere complicati, o un punto in cui è possibile "imparare" su di essi. Praticamente tutte le risorse al di fuori dei corsi universitari di livello superiore sono tutte dedicate al modo in cui i tipi funzionano in una determinata lingua, quindi è necessario decidere anche quello.
Come meglio posso offrire, i tipi possono essere stratificati in questo modo:
- Caratterizzato in modo molto debole, cose come JavaScript in cui è definito [] + {}
- Digitato debolmente come Python, dove non puoi fare [] + {}, ma non viene controllato fino a quando non provi
- Digitato debolmente come C o Java, dove non è possibile eseguire [] + {}, ma è verificato al momento della compilazione, tuttavia non si dispone delle funzionalità di tipo più avanzate
- A cavallo tra il confine tra caratteri deboli e fortemente tipizzati, come la metaprogrammazione del modello C ++ e il codice Haskell più semplice in cui i tipi applicano solo proprietà.
- Completamente in fortemente tipizzato, come i programmi Haskell più complicati in cui i tipi fanno le cose, come mostrato sopra
- Sono fortemente tipizzati, come Agda o Idris, in cui tipi e valori interagiscono e possono vincolarsi a vicenda. Questo è forte quanto i sistemi di tipo ottengono e la programmazione in essi è la stessa di scrivere prove matematiche su ciò che fa il tuo programma. Nota: la codifica in Agda non sta letteralmente scrivendo prove matematiche, i tipi sono teorie matematiche e le funzioni con quei tipi sono esempi costruttivi che dimostrano tali teorie.
Generalmente, più in basso vai in questa lista, più i tipi possono fare per te, ma in fondo stai salendo nella stratosfera e l'aria sta diventando un po 'sottile: l'ecosistema del pacchetto è molto più piccolo e tu' Dovrai scrivere più cose da solo rispetto ad aver trovato una libreria pertinente. La barriera all'ingresso aumenta anche quando si scende, in quanto è necessario comprendere il sistema dei tipi abbastanza per scrivere programmi su larga scala.