Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Линзы
Комбинаторная манипуляция данными
Александр Гранин
graninas@gmail.com
1
О себе
● Haskell, C++, немного C#
● Организатор сообщества LambdaNsk
● Доклады:
o Haskell. DevDay@2GIS
o ФП вчера и сегодн...
● Очень кратко о ФП
● Линзы в Haskell
● Сценарии с использованием линз
● Линзы в других языках
План доклада
3
Функциональное программирование
● Функции высших порядков
● Лямбды
● Замыкания
● Иммутабельность
● Рекурсия
4
Функциональное программирование
● Функции высших порядков
● Лямбды
● Замыкания
● Иммутабельность
● Рекурсия
● Математическ...
data Credentials = Credentials {
credentialsLogin :: String,
credentialsPassword :: String }
Credentials
Login
Password
6
...
updatePassword credentials newPassword = let
(Credentials login _) = credentials
in (Credentials login newPassword)
update...
data Credentials = Credentials {
credentialsLogin :: String,
credentialsPassword :: String }
data Person = Person {
person...
updatePersonPassword person newPass = let
credentials = personCredentials person
newCreds = credentials { credentialsPassw...
data Credentials = Credentials {
credentialsLogin :: String,
credentialsPassword :: String }
data Person = Person {
person...
updateSubscriberPassword subscriber newPass = let
person = subscriberPerson subscriber
credentials = personCredentials per...
updateSubscriberPassword subscriber newPass = let
person = subscriberPerson subscriber
credentials = personCredentials per...
person = subscriberPerson subscriber
newSubscriber = subscriber { subscriberPerson = person }
credentials = personCredenti...
getPerson subscriber = subscriberPerson subscriber
setPerson subscriber person = subscriber { subscriberPerson = person }
...
Линза = Геттер + Сеттер
lens :: (getter :: A -> B,
setter :: A -> B -> A)
passwordLens :: (Credentials -> String,
Credenti...
Простые операторы view и set
view (getter, _) parent = getter parent
set (_, setter) parent value = setter parent value
> ...
credentialsLens = (getCreds, setCreds)
where
getCreds person = personCredentials person
setCreds person newCreds = person ...
(getChild, setChild) . (getValue, setValue) = (getter, setter)
where
getter parent = getValue (getChild parent)
setter par...
myCredentials = Credentials "login" "pass"
mePerson = Person "Alex" "Granin" myCredentials
> view (credentialsLens . passw...
Линзы в Haskell: библиотека lens
Автор - Edward Kmett
20
data ContactType = VK | FB | Twitter | Email
data Skill = Cpp | CSharp | Haskell | Java | FSharp | Python
data Person = Pe...
type Presentation = String
data Attendee =
Speaker {
_person :: Person,
_visited :: [Presentation],
_presentationTitle :: ...
-- Template Haskell rocks:
makeLenses ''Person
makeLenses ''Attendee
Создание линз
_name name Person ===>
String
_surname ...
pete = Person "Pete" "Howard" [(FB, "pete")] [Java, Python]
peteAttendee = Attendee pete []
> _name (_person peteAttendee)...
> peteAttendee ^. person.skills
[Java,Python]
> itoList (peteAttendee ^. person.skills)
[(0,Java),(1,Python)]
> (itoList (...
setAttendeeName att n = case att of
Speaker pers visit theme -> Speaker (setName pers) visit theme
Attendee pers visit -> ...
addContact att contact = case att of
Speaker pers visit theme -> Speaker (appendContact pers) visit theme
Attendee pers vi...
#%%= **= //= //~ <<%@= <<.|.= <<^~ %= ...
#%%~ **~ <-= <#%= <<%@~ <<.|.~ <<||= %@= .=
#%= *= <-~ <#%~ <<%~ <<.~ <<||~ %@~ ...
Сценарии с использованием линз
29
data Conference = Conference {
_attendees :: [Attendee],
_currentPresentation :: Presentation,
_conferenceTweets ::
[(Pres...
pete = Person "Pete" "Howard" [facebook "pete"] [Java]
jakob = Person "Jakob" "Brown" [twitter "jab"] [Java, CSharp]
lana ...
conferenceScenario :: State Conference ()
conferenceScenario = do
alex `tweeted` "Rush hour, sorry. #dev2dev"
beginPresent...
tweeted :: Person -> Msg -> State Conference ()
tweeted pers msg = if "#dev2dev" `isInfixOf` msg
then writeTweet pers msg
...
beginPresentation :: Presentation -> State Conference ()
beginPresentation title = currentPresentation .= title
34
Сценари...
setListeners :: [Person] -> State Conference ()
setListeners persons = setVisited (attendees . onlyListeners persons)
only...
conferenceScenario :: State Conference ()
conferenceScenario = do
alex `tweeted` "Rush hour, sorry. #conf"
beginPresentati...
Линзы в других языках
● Haskell
○ Edward Kmett, “Lenses, Folds, and Traversals”
● Scalaz
○ Edward Kmett, “Lenses: A Functi...
38
Спасибо за внимание!
Вопросы?
Александр Гранин
graninas@gmail.com
beginPresentation :: Presentation -> State Conference ()
beginPresentation title = currentPresentation .= title
listeners ...
Upcoming SlideShare
Loading in …5
×

Линзы - комбинаторная манипуляция данными (Dev2Dev)

252 views

Published on

Presentation about lenses in Haskell.

Presented on Dev2Dev, Krasnoyarsk, 30 of May.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Линзы - комбинаторная манипуляция данными (Dev2Dev)

  1. 1. Линзы Комбинаторная манипуляция данными Александр Гранин graninas@gmail.com 1
  2. 2. О себе ● Haskell, C++, немного C# ● Организатор сообщества LambdaNsk ● Доклады: o Haskell. DevDay@2GIS o ФП вчера и сегодня. TechTalks@NSU o Функционально-декларативный дизайн на С++ o Идиоматичный ФП-код. LambdaNsk 2
  3. 3. ● Очень кратко о ФП ● Линзы в Haskell ● Сценарии с использованием линз ● Линзы в других языках План доклада 3
  4. 4. Функциональное программирование ● Функции высших порядков ● Лямбды ● Замыкания ● Иммутабельность ● Рекурсия 4
  5. 5. Функциональное программирование ● Функции высших порядков ● Лямбды ● Замыкания ● Иммутабельность ● Рекурсия ● Математические абстракции 5
  6. 6. data Credentials = Credentials { credentialsLogin :: String, credentialsPassword :: String } Credentials Login Password 6 Простой алгебраический тип данных
  7. 7. updatePassword credentials newPassword = let (Credentials login _) = credentials in (Credentials login newPassword) updatePassword2 credentials newPassword = credentials { credentialsPassword = newPassword } Изменение значения простого АТД 7 data Credentials = Credentials { credentialsLogin :: String, credentialsPassword :: String } Credentials Login Password
  8. 8. data Credentials = Credentials { credentialsLogin :: String, credentialsPassword :: String } data Person = Person { personName :: String, personSurname :: String, personCredentials :: Credentials } 8 Более сложный АТД Person Credentials Login Password Credentials Login Password Credentials Name Surname
  9. 9. updatePersonPassword person newPass = let credentials = personCredentials person newCreds = credentials { credentialsPassword = newPass } newPerson = person { personCredentials = newCreds } in newPerson 9 Изменение более сложного АТД
  10. 10. data Credentials = Credentials { credentialsLogin :: String, credentialsPassword :: String } data Person = Person { personName :: String, personSurname :: String, personCredentials :: Credentials } data Subscriber = Subscriber { subscriberPerson :: Person, subscriberTariffId :: Int } Person Subscriber Credentials Login Password 10 А что, если?..
  11. 11. updateSubscriberPassword subscriber newPass = let person = subscriberPerson subscriber credentials = personCredentials person newCreds = credentials { credentialsPassword = newPass } newPerson = person { personCredentials = newCreds } newSubscriber = subscriber { subscriberPerson = newPerson } in newSubscriber 11
  12. 12. updateSubscriberPassword subscriber newPass = let person = subscriberPerson subscriber credentials = personCredentials person newCreds = credentials { credentialsPassword = newPass } newPerson = person { personCredentials = newCreds } newSubscriber = subscriber { subscriberPerson = newPerson } in newSubscriber Getters Setters 12
  13. 13. person = subscriberPerson subscriber newSubscriber = subscriber { subscriberPerson = person } credentials = personCredentials person newPerson = person { personCredentials = credentials } password = credentialsPassword credentials newCreds = credentials { credentialsPassword = password } b = getB a a = setB b a 13
  14. 14. getPerson subscriber = subscriberPerson subscriber setPerson subscriber person = subscriber { subscriberPerson = person } getCredentials person = personCredentials person setCredentials person creds = person { personCredentials = creds } getPassword creds = credentialsPassword creds setPassword creds pass = creds { credentialsPassword = pass } b = getB a a = setB b a 14 getter :: A -> B setter :: A -> B -> A
  15. 15. Линза = Геттер + Сеттер lens :: (getter :: A -> B, setter :: A -> B -> A) passwordLens :: (Credentials -> String, Credentials -> String -> Credentials) passwordLens = (getPass, setPass) where getPass creds = credentialsPassword creds setPass creds newPass = creds {credentialsPassword = newPass} 15
  16. 16. Простые операторы view и set view (getter, _) parent = getter parent set (_, setter) parent value = setter parent value > let myCredentials = Credentials "login" "pass" > view passwordLens myCredentials "pass" > set passwordLens myCredentials "qwerty" Credentials "login" "qwerty" 16
  17. 17. credentialsLens = (getCreds, setCreds) where getCreds person = personCredentials person setCreds person newCreds = person {personCredentials = newCreds} personLens = (getPerson, setPerson) where getPerson subscr = subscriberPerson subscr setPerson subscr newPers = subscr {subscriberPerson = newPers} Еще линзы 17
  18. 18. (getChild, setChild) . (getValue, setValue) = (getter, setter) where getter parent = getValue (getChild parent) setter parent value = let oldChild = getChild parent newChild = setValue oldChild value in setChild parent newChild Линза . линза = линза 18 Композиция!
  19. 19. myCredentials = Credentials "login" "pass" mePerson = Person "Alex" "Granin" myCredentials > view (credentialsLens . passwordLens) mePerson “pass” > set (credentialsLens . passwordLens) mePerson “qwerty” Person "Alex" "Granin" (Credentials "login" "qwerty") Линза . линза = линза 19
  20. 20. Линзы в Haskell: библиотека lens Автор - Edward Kmett 20
  21. 21. data ContactType = VK | FB | Twitter | Email data Skill = Cpp | CSharp | Haskell | Java | FSharp | Python data Person = Person { _name :: String, _surname :: String, _contacts :: [(ContactType, String)], _skills :: [Skill] } АТД Person Person Name Surname Contacts Skills 21
  22. 22. type Presentation = String data Attendee = Speaker { _person :: Person, _visited :: [Presentation], _presentationTitle :: String } | Attendee { _person :: Person, _visited :: [Presentation] } АТД Attendee Attendee Person Name Surname Contacts Skills 22
  23. 23. -- Template Haskell rocks: makeLenses ''Person makeLenses ''Attendee Создание линз _name name Person ===> String _surname surname Person ===> String _contacts contacts Person ===> Contacts _person person Attendee ===> Person _visited visited Attendee ===> 23
  24. 24. pete = Person "Pete" "Howard" [(FB, "pete")] [Java, Python] peteAttendee = Attendee pete [] > _name (_person peteAttendee) -- Manual “Pete” > view (person.name) peteAttendee -- With lenses “Pete” > peteAttendee ^. (person.name) -- The same “Pete” Оператор view (^.) 24
  25. 25. > peteAttendee ^. person.skills [Java,Python] > itoList (peteAttendee ^. person.skills) [(0,Java),(1,Python)] > (itoList (peteAttendee ^. person.skills)) ^.. ix 1 [(1,Python)] Операторы itoList, (^..) и ix 25
  26. 26. setAttendeeName att n = case att of Speaker pers visit theme -> Speaker (setName pers) visit theme Attendee pers visit -> Attendee (setName pers) visit where setName (Person _ s cts skls) = Person n s cts skls setAttendeeName’ att n = set (person.name) "Jack" att Оператор set 26
  27. 27. addContact att contact = case att of Speaker pers visit theme -> Speaker (appendContact pers) visit theme Attendee pers visit -> Attendee (appendContact pers) visit where appendContact (Person n s cts skls) = Person n s (contact : cts) skls addContact' att contact = over (person . contacts) (insert contact) att Оператор over 27
  28. 28. #%%= **= //= //~ <<%@= <<.|.= <<^~ %= ... #%%~ **~ <-= <#%= <<%@~ <<.|.~ <<||= %@= .= #%= *= <-~ <#%~ <<%~ <<.~ <<||~ %@~ .> #%~ *~ <. <#= <<&&= <<//= <<~ %~ .@= #= += <.&.= <#~ <<&&~ <<//~ <>= & .@~ #~ +~ <.&.~ <%= <<**= <</>= <>~ &&= .|.= %%= -= <.= <%@= <<**~ <</>~ <?= &&~ .|.~ %%@= -~ <.> <%@~ <<*= <<<.>= <?~ &~ .~ %%@~ .&.= <.>= <%~ <<*~ <<<.>~ <^= <.|.= <<-= %%~ .&.~ <.>~ <&&= <<+= <<</>= <^^= <.|.~ <<-~ Тысячи их... Zen 28
  29. 29. Сценарии с использованием линз 29
  30. 30. data Conference = Conference { _attendees :: [Attendee], _currentPresentation :: Presentation, _conferenceTweets :: [(Presentation, Person, String)] } АТД Conference Attendee Person Conference currentPresentation conferenceTweets 30
  31. 31. pete = Person "Pete" "Howard" [facebook "pete"] [Java] jakob = Person "Jakob" "Brown" [twitter "jab"] [Java, CSharp] lana = Person "Lana" "Dell" [] [FSharp] alex = Person "Alexander" "Granin" [vk "graninas"] [Haskell] guru = Person "Real" "Guru" [] [Cpp, Java, CSharp, Haskell] confAttendees = [ attendee pete, attendee jakob, attendee lana, speaker alex "Lenses", speaker guru “Multilanguage projects”] conference = Conference confAttendees "" [] 31
  32. 32. conferenceScenario :: State Conference () conferenceScenario = do alex `tweeted` "Rush hour, sorry. #dev2dev" beginPresentation "Multilanguage projects" setListeners [pete, jakob, lana] jakob `tweeted` "Great talk! #dev2dev" lana `tweeted` "So technical. #dev2dev" pete `tweeted` "#MLP 222 coming soon." 32 Сценарий “Конференция”
  33. 33. tweeted :: Person -> Msg -> State Conference () tweeted pers msg = if "#dev2dev" `isInfixOf` msg then writeTweet pers msg else return () writeTweet :: Person -> Msg -> State Conference () writeTweet pers msg = do presentationName <- use currentPresentation conferenceTweets %= insert (presentationName, pers, msg) 33 Сценарий “Твит”
  34. 34. beginPresentation :: Presentation -> State Conference () beginPresentation title = currentPresentation .= title 34 Сценарий “Начать доклад”
  35. 35. setListeners :: [Person] -> State Conference () setListeners persons = setVisited (attendees . onlyListeners persons) onlyListeners :: Persons -> Traversal' [Attendee] Attendee onlyListeners persons = traversed . filtered (att -> (att ^. person) `elem` persons) 35 Сценарий “Задать слушателей”
  36. 36. conferenceScenario :: State Conference () conferenceScenario = do alex `tweeted` "Rush hour, sorry. #conf" beginPresentation "Multilanguage projects" setListeners [pete, jakob, lana] jakob `tweeted` "Great talk! #conf" lana `tweeted` "So technical. #conf" pete `tweeted` "#MLP 222 coming soon." 36 Сценарий “Конференция”
  37. 37. Линзы в других языках ● Haskell ○ Edward Kmett, “Lenses, Folds, and Traversals” ● Scalaz ○ Edward Kmett, “Lenses: A Functional Imperative” ● JavaScript ● Clojure ● C++ (!) ● … your language 37
  38. 38. 38 Спасибо за внимание! Вопросы? Александр Гранин graninas@gmail.com
  39. 39. beginPresentation :: Presentation -> State Conference () beginPresentation title = currentPresentation .= title listeners :: [Person] -> State Conference () listeners perss = setVisited (attendees . onlyListeners perss) where setVisited atts = do title <- use currentPresentation atts.visited %= (insert title) onlyListeners :: Persons -> Traversal' [Attendee] Attendee onlyListeners ls = traversed . filtered (att -> att ^. person `elem` ls) 39

×