Il modo in cui viene descritto il problema del "modello anemico" non si traduce bene in FP così com'è. Innanzitutto deve essere adeguatamente generalizzato. Al suo centro, un modello anemico è un modello che contiene conoscenze su come usarlo correttamente che non è incapsulato dal modello stesso. Invece, quella conoscenza è diffusa in un mucchio di servizi correlati. Tali servizi dovrebbero essere solo clienti del modello, ma a causa della sua anemia ne sono ritenuti responsabili . Ad esempio, considera una Accountclasse che non può essere utilizzata per attivare o disattivare gli account o persino cercare informazioni su un account se non gestita tramite una AccountManagerclasse. L'account dovrebbe essere responsabile delle operazioni di base su di esso, non di alcune classi manager esterne.
Nella programmazione funzionale, esiste un problema simile quando i tipi di dati non rappresentano accuratamente ciò che dovrebbero modellare. Supponiamo di dover definire un tipo che rappresenti gli ID utente. Una definizione "anemica" indicherebbe che gli ID utente sono stringhe. È tecnicamente fattibile, ma si verificano enormi problemi perché gli ID utente non vengono utilizzati come stringhe arbitrarie. Non ha senso concatenarli o suddividere le loro sottostringhe, Unicode non dovrebbe davvero importare, e dovrebbero essere facilmente incorporabili in URL e altri contesti con rigide limitazioni di carattere e formato.
La risoluzione di questo problema si verifica in genere in alcune fasi. Un semplice primo taglio è dire "Beh, a UserIDè rappresentato in modo equivalente a una stringa, ma sono tipi diversi e non puoi usarne uno dove ti aspetti l'altro". Haskell (e alcuni altri linguaggi funzionali digitati) fornisce questa funzione tramite newtype:
newtype UserID = UserID String
Questo definisce una UserIDfunzione che quando viene data Stringcostruisce un valore che viene trattato come un UserIDsistema di tipo, ma che è ancora solo Stringin fase di esecuzione. Ora le funzioni possono dichiarare che richiedono UserIDuna stringa anziché una stringa; usando UserIDs dove in precedenza si utilizzavano protezioni stringhe contro il codice che concatena due UserIDs insieme. Il sistema di tipi garantisce che ciò non può avvenire, non sono richiesti test.
Il punto debole qui è che il codice può ancora prendere qualsiasi Stringlike arbitrario "hello"e costruirne uno UserID. Ulteriori passaggi includono la creazione di una funzione "costruttore intelligente" che quando viene data una stringa controlla alcuni invarianti e restituisce a solo UserIDse sono soddisfatti. Poi il "muto" UserIDcostruttore è fatto in modo privato, se un cliente vuole un UserIDessi devono utilizzare il costruttore intelligente, impedendo in tal modo UserIDs malformati da venire all'esistenza.
Anche ulteriori passaggi definiscono il UserIDtipo di dati in modo tale che sia impossibile costruirne uno malformato o "improprio", semplicemente per definizione. Ad esempio, definendo a UserIDcome un elenco di cifre:
data Digit = Zero | One | Two | Three | Four | Five | Six | Seven | Eight | Nine
data UserID = UserID [Digit]
Per costruire un UserIDelenco di cifre deve essere fornito. Data questa definizione, è banale dimostrare che è impossibile UserIDche esista un che non può essere rappresentato in un URL. La definizione di modelli di dati come questo in Haskell è spesso aiutata da funzionalità di sistema di tipo avanzato come tipi di dati e tipi di dati algebrici generalizzati (GADT) , che consentono al sistema di tipi di definire e dimostrare più invarianti sul codice. Quando i dati sono disaccoppiati dal comportamento, la definizione dei dati è il solo mezzo per imporre il comportamento.