Successfully reported this slideshow.

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

0

Share

1 of 39
1 of 39

More Related Content

More from Alexander Granin

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Линзы - комбинаторная манипуляция данными (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

×