Казвам се Пийт и съм пристрастен към F#.
Признавам си – обичам да използвам функционални езици и, като се има предвид моята .Net подготовка, особено F#. Простотата и преди всичко четливостта го поставят на върха на купчината. Повечето от това, за което ще говоря, обикновено се отнася за повечето функционални езици. Ще използвам F# в моите примери, но всеки, който е запознат със семейството на ML, трябва да може да го следва без проблем.
Една от основополагащите концепции на езика и на семейството ML от функционални езици за програмиране (напр. Haskel, OCaml,…) е неизменността на променливите (чието име сега е доста иронично, тъй като не вече не варира). Неизменността прави много неща по-лесни за мен като програмист - без случайни промени на стойността при преминаване по реф, автоматична безопасност на нишката, едно име = една стойност в обхвата.
Всичко това е много красиво и лесно в примерите, където грабваме някои данни от страхотен източник на данни като социалната мрежа Star Wars, играем си малко с тях и ги показваме. Нещата обаче са доста скучни без никакво взаимодействие и взаимодействието обикновено означава промяна (или поне запазване) на някои данни.
Но как да взаимодействам с програмата, за да променя неизменните данни?
Това е въпрос, с който се затрудних, когато се сблъсках с този начин на програмиране, така че документирам моите открития за моя собствена полза и ги споделям в полза на тези, които са на подобно пътуване.
Стандартният отговор на горния въпрос е не. Вместо това правите нов обект, който е като стария, но различен.
person { olderPerson { name = “Fred” --> name = "Fred" age = 42 age = 43 } }
Тук F# може да ни помогне с първата техника за обработка на промяна...
Конструктори на записи - Точно като този, но...
F# има концепция за запис, която е подобна на struct в C# по това, че:
- Това е неизменно (странно)
- Това е тип стойност (не се предава по препратка)
- Може да се сравнява с други записи от същия тип за равенство чрез сравняване на стойностите на неговите членове (т.е. сравняване на стойностите на името и възрастта)
Записите имат проста дефиниция...
type Person = { name: string; age: int; rating: double }
… и просто инстанциране.
let p1 = { name = "Pete"; age = 42; rating = 0.0 }
Всичко това е добре, но какво да кажем за промяната? Записът също има алтернативен конструктор, който изглежда така:
let p2 = { p1 with age = 43; rating = p1.rating * 1.2 }
Това бързо ви позволява да създадете сложен обект, който е копие на оригинала с няколко ощипвания. Можете дори да посочите оригиналния обект в рамките на конструктора, както направих със стойността рейтинг. Това е особено полезно за добавяне към съдържащи се списъци.
Разбира се, сега имате две стойности; оригиналната и „променената“. Можете просто да игнорирате оригинала и да го оставите в крайна сметка да излезе от обхвата. Въпреки това, понякога е полезно да имате навигационна пътека на промените за целите на регистриране / одит / отстраняване на грешки.
Какво следва
След малко ще премина към няколко други открития и ще усложня малко. Някои теми ще включват:
- Конструктори на записи — Точно като този, само различен (тази публикация)
- Начинът на OO: внедряване на сетери за свойства във F# за „измама“ чрез създаване на променлив обект в стил C#.
- „Лещи: промяна на нещото вътре в нещото вътре в другото нещо.“
- Лещи и списъци: промяна на нещо сред другите неща в това нещо… може би
- „Двупосочни доставчици: отразяване на променящите се външни данни“
- Някои често срещани неща, които обикновено разчитат на мутация: като сортиране...