Казвам се Пийт и съм пристрастен към 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 }

Това бързо ви позволява да създадете сложен обект, който е копие на оригинала с няколко ощипвания. Можете дори да посочите оригиналния обект в рамките на конструктора, както направих със стойността рейтинг. Това е особено полезно за добавяне към съдържащи се списъци.

Разбира се, сега имате две стойности; оригиналната и „променената“. Можете просто да игнорирате оригинала и да го оставите в крайна сметка да излезе от обхвата. Въпреки това, понякога е полезно да имате навигационна пътека на промените за целите на регистриране / одит / отстраняване на грешки.

Какво следва

След малко ще премина към няколко други открития и ще усложня малко. Някои теми ще включват:

  1. Конструктори на записи — Точно като този, само различен (тази публикация)
  2. Начинът на OO: внедряване на сетери за свойства във F# за „измама“ чрез създаване на променлив обект в стил C#.
  3. „Лещи: промяна на нещото вътре в нещото вътре в другото нещо.“
  4. Лещи и списъци: промяна на нещо сред другите неща в това нещо… може би
  5. „Двупосочни доставчици: отразяване на променящите се външни данни“
  6. Някои често срещани неща, които обикновено разчитат на мутация: като сортиране...