“Anemik model” probleminin tanımlanma şekli, olduğu gibi FP'ye iyi bir şekilde çevrilemez. İlk önce uygun şekilde genelleştirilmesi gerekir. Kalbinde, anemik bir model, modelin kendisi tarafından kapsanmayan, uygun şekilde nasıl kullanılacağı hakkında bilgi içeren bir modeldir. Bunun yerine, bu bilgi ilgili hizmetler yığını etrafında yayılır. Bu hizmetler sadece modelin müşterileri olmalıdır , ancak kansızlıklarından sorumlu tutuluyorlar . Örneğin, Account
hesapları bir AccountManager
sınıf aracılığıyla ele alınmadıkça hesapları etkinleştirmek veya devre dışı bırakmak veya bir hesapla ilgili bilgileri aramak için kullanılamayan bir sınıfı düşünün . Hesap, bazı harici yönetici sınıflarından değil temel işlemlerden sorumlu olmalıdır.
İşlevsel programlamada, veri tipleri modellemesi gerekenleri doğru bir şekilde göstermediğinde de benzer bir problem vardır. Kullanıcı kimliklerini temsil eden bir tür tanımlamamız gerektiğini varsayalım. Bir "anemik" tanımı, kullanıcı kimliklerini dizge olarak belirtir. Bu teknik olarak mümkün, ancak kullanıcı kimlikleri rastgele dizeler gibi kullanılmadığı için büyük sorunlara yol açıyor. Bunları birleştirmek ya da altlarını kesmek bir anlam ifade etmiyor, Unicode gerçekten önemli olmamalı ve URL'lerde ve katı karakter ve format sınırlamaları olan diğer bağlamlarda kolayca gömülebilir olmalıdır.
Bu problemi çözmek genellikle birkaç aşamada gerçekleşir. Basit bir ilk kesim, "a UserID
, bir dize ile eşit olarak temsil edilir, ancak farklı türlerdir ve birini diğerinden beklediğiniz yerde kullanamazsınız" demektir. Haskell (ve bazı diğer yazılı dilleri) bu özelliği aşağıdakiler aracılığıyla sağlar newtype
:
newtype UserID = UserID String
Bu tanımlar UserID
verilen bir işlevi String
olan bir değer oluşturur gibi tedavi bir UserID
tipi sistem tarafından, fakat sadece halen String
zamanında. Artık fonksiyonlar UserID
bir string yerine onların gerekli olduğunu ilan edebilir ; UserID
Daha önce dizeleri kullanmakta olduğunuz s tuşunu kullanarak birlikte s tuşunu birleştiren koda karşı korumaları kullanın UserID
. Tip sistemi olamayacağını garanti eder, test gerektirmez.
Burada zayıflık kodu hala rasgele herhangi alabilir olmasıdır String
gibi "hello"
bir inşa UserID
ondan. Diğer adımlar arasında, bir dize verildiğinde bazı değişmezleri denetleyen ve yalnızca UserID
memnun kaldıklarında döndüren "akıllı kurucu" işlevi oluşturma yer alır . Daha sonra "aptal" UserID
bir istemci istiyorsa yapıcı özel yapılmış yani edilir UserID
onlar gerekir böylece ortaya gelmesini hatalı oluşturulmuş userids önlenmesi, akıllı Oluşturucu kullanın.
Daha ileri adımlar bile UserID
veri tipini, hatalı tanımlanmış veya "uygun olmayan" bir tanımı basitçe tanımlayarak inşa etmenin imkansız olduğu şekilde tanımlar. Örneğin, bir UserID
basamak listesi olarak tanımlamak :
data Digit = Zero | One | Two | Three | Four | Five | Six | Seven | Eight | Nine
data UserID = UserID [Digit]
Bir UserID
basamak listesi oluşturmak için sağlanmalıdır. Bu tanım göz önüne alındığında UserID
, bir URL'de temsil edilemeyen bir varlığın mümkün olmadığını göstermek önemsizdir . Haskell'de bunun gibi veri modellerinin tanımlanmasına genellikle , tip sisteminin kodunuz hakkında daha fazla değişmezleri tanımlamasını ve kanıtlamasını sağlayan Veri Türleri ve Genelleştirilmiş Cebirsel Veri Tipleri (GADT'ler) gibi gelişmiş tip sistem özellikleri yardımcı olur . Veriler davranıştan ayrıştırıldığında, davranış tanımlamanız gereken tek şey veri tanımınızdır.