The document discusses functional programming concepts in Haskell using the lens library. It introduces data types to represent contacts, persons, and accounts. It shows how to create lenses to access and update fields in nested data structures. Various lens operators like view, set, over, and folded are demonstrated. Prisms and combining lenses and prisms are also covered. The document aims to illustrate how the lens library allows manipulating nested structures in a functional way.
2. data Contacts = Contacts {
contactEMail :: String,
contactSkype :: String }
data Person = Person {
personName :: String,
personSurname :: String,
personContacts :: Contacts }
data Account = CommonAccount {
accountPerson :: Person,
accountLogin :: String }
Person
Account
Contacts
contactEMail
contactSkype
2
3. 3
updateAccountEMail account newMail = let
CommonAccount person login = account
Person name surname contacts = person
Contacts _ skype = contacts
newContacts = Contacts newMail skype
newPerson = Person name surname newContacts
newAccount = CommonAccount newPerson login
in newAccount
4. 4
data Account =
CommonAccount {
accountPerson :: Person,
accountLogin :: String }
| PayedAccount {
accountPerson :: Person,
accountLogin :: String,
accountScores :: Int }
data Contacts = Contacts {
contactEMail :: String,
contactSkype :: String }
data Person = Person {
personName :: String,
personSurname :: String,
personContacts :: Contacts }
5. 5
updateAccountEMail account newMail = let
CommonAccount person login = account
Person name surname contacts = person
Contacts _ skype = contacts
newContacts = Contacts newMail skype
newPerson = Person name surname newContacts
newAccount = CommonAccount newPerson login
in newAccount
?
6. 6
updateAccountEMail account newMail = let
CommonAccount person login = account
Person name surname contacts = person
Contacts _ skype = contacts
newContacts = Contacts newMail skype
newPerson = Person name surname newContacts
newAccount = CommonAccount newPerson login
in newAccount
7. 7
updateAccountEMail account newMail = case account of
CommonAccount p l = CommonAccount (updateP p newMail) l
PayedAccount p l s = PayedAccount (updateP p newMail) l s
where
updateP p mail = let
Person name surname contacts = p
Contacts _ skype = contacts
newContacts = Contacts mail skype
newPerson = Person name surname newContacts
in newPerson
8. 8
updateAccountEMail account newMail = case account of
CommonAccount p l = CommonAccount (updateP p newMail) l
PayedAccount p l s = PayedAccount (updateP p newMail) l s
where
updateP p mail = let
Person name surname contacts = p
Contacts _ skype = contacts
newContacts = Contacts mail skype
newPerson = Person name surname newContacts
in newPerson
9. 9
updateAccountEMail account newMail = let
person = accountPerson account
contacts = personContacts person
newContacts = contacts { contactEMail = newMail }
newPerson = person { personContacts = newContacts }
newAccount = account { accountPerson = newPerson }
in newAccount
10. getEMail contacts = contactEMail contacts
setEMail contacts mail = contacts { contactEMail = mail }
getContacts person = personContacts person
setContacts person contacts = person { personContacts = contacts }
getPerson account = accountPerson account
setPerson account person = account { accountPerson = person }
b = getB a
a = setB b a
10
getter :: A -> B
setter :: A -> B -> A
11. Линза = Геттер + Сеттер
lens :: (getter :: A -> B,
setter :: A -> B -> A)
eMailLens :: (Contacts -> String,
Contacts -> String -> Contacts)
eMailLens = (getEMail, setEMail)
where
getEMail contacts = contactEMail contacts
setEMail contacts mail = contacts {contactEMail = mail}
11
12. Комбинаторы view, set
view (getter, _) parent = getter parent
set (_, setter) parent value = setter parent value
> let contacts = Contacts "someone@null.ptr" "not_a_skype_account"
> view eMailLens contacts
"someone@null.ptr"
> set eMailLens contacts "dereference@null.ptr"
Contacts "dereference@null.ptr" "not_a_skype_account" 12
13. personLens = (getPerson, setPerson)
where
getPerson account = accountPerson account
setPerson account person = account {accountPerson = person}
contactLens = (getContacts, setContacts)
where
getContacts person = personContacts person
setContacts person contacts = person {personContacts = contacts}
13
Еще линзы
14. (getChild, setChild) . (getValue, setValue) = (getter, setter)
getter parent = getValue (getChild parent)
setter parent value = let
oldChild = getChild parent
newChild = setValue oldChild value
in setChild parent newChild
Композиция линз
14
15. Композиция линз - тоже линза
> let contacts = Contacts "someone@null.ptr" "not_a_skype_account"
> let person = Person “Some” “One” contacts
> view (contactLens . eMailLens) person
"someone@null.ptr"
> set (contactLens . eMailLens) person "dereference@null.ptr"
Person “Some” “One”
(Contacts "dereference@null.ptr" "not_a_skype_account") 15
16. > let contacts = Contacts "someone@null.ptr" "not_a_skype_account"
> let person = Person “Some” “One” contacts
> let account = PayedAccount person “login” 0
> view (eMailLens . contactLens . personLens) account
"someone@null.ptr"
> set (eMailLens . contactLens . personLens) account "42@nm.ru"
…………………………………………………………………………………
………………………………………………………………………………...
16
Композиция линз - тоже линза
21. makeLenses ''Contacts
makeLenses ''Person
makeLenses ''Account
Создание линз (Template Haskell)
name Person ===> String
surname Person ===> String
contacts Person ===> Contacts
person Account ===> Person
scores Account ===> Int
………. ……….. ……….....
21
26. someOnePerson = Person "Some" "One" someoneContacts [Cpp, Haskell]
grutPerson = Person "IAm" "Grut" grutContact [FSharp]
> view (folded . person . skills) accounts
[Cpp,Haskell,FSharp]
26
Оператор folded
27. someOnePerson = Person "Some" "One" someoneContacts [Cpp, Haskell]
grutPerson = Person "IAm" "Grut" grutContact [FSharp]
> view (folded . person . surname) accounts
“OneGrut”
Оператор folded
27
28. someOnePerson = Person "Some" "One" someoneContacts [Cpp, Haskell]
grutPerson = Person "IAm" "Grut" grutContact [FSharp]
> view (folded . person . contacts) accounts
No instance for (Data.Monoid.Monoid Contacts)
arising from a use of ‘folded’
In the first argument of ‘(.)’, namely ‘folded’
In the first argument of ‘view’, namely
‘(folded . person . contacts)’
In the expression: view (folded . person . contacts) accounts
28
Оператор folded
30. someOnePerson = Person "Some" "One" someoneContacts [Cpp, Haskell]
grutPerson = Person "IAm" "Grut" grutContact [FSharp]
> toListOf (folded . person . surname) accounts
[“One”, “Grut”]
30
Оператор toListOf
31. someOnePerson = Person "Some" "One" someoneContacts [Cpp, Haskell]
grutPerson = Person "IAm" "Grut" grutContact [FSharp]
> let onlyGrut = filtered (acc -> acc ^. person.surname == "Grut")
> view olnyGrut accounts
No instance for (Data.Monoid.Monoid Account)
arising from a use of ‘onlyGrut’
In the first argument of ‘view’, namely ‘onlyGrut’
In the expression: view onlyGrut accounts
In an equation for ‘it’: it = view onlyGrut accounts
31
Оператор filtered
32. someOnePerson = Person "Some" "One" someoneContacts [Cpp, Haskell]
grutPerson = Person "IAm" "Grut" grutContact [FSharp]
> let onlyGrut = filtered (acc -> acc ^. person.surname == "Grut")
> toListOf olnyGrut accounts
Couldn't match type ‘[Account]’ with ‘Account’
Expected type: Getting (Data.Monoid.Endo [Account])
[Account] Account
Actual type: Optic' (->) (Const (Data.Monoid.Endo
[Account])) Account Account
In the first argument of ‘toListOf’, namely ‘onlyGrut’
32
Оператор filtered