On my journey to start getting better with functional programming, I discovered, with the help of a member of the SO family, what lens. I even made some research on it with the links down below to understand more about them.
https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/basic-lensing
http://fluffynukeit.com/how-functional-programming-lenses-work/
https://medium.com/@dtipson/functional-lenses-d1aba9e52254#.27yw4gnwk
With all that knowledge, I thought I could give them a try and see whether or not I could understand their functionnality and the reasons why they're useful in FP. My problem at the moment is moving from the type members that were define to access and modify fields in my equipment record that I've define for a game that I'm prototyping at the moment. I will put snippets of the Equipment records, the members that were there before and the functional lens I'm trying to create but just won't work. After the first pattern matching, it expects the code to have the same return value, when I'd like it to be a general value to be returned, depending on a pattern that I had successfully matched! For the the remain of the code, instead of omitting the code and making it not compile while you're trying to give me a hand, I've thought it be best to put the important snippets here and a public to the relevant code so you can compile it on your local machine ! The public gist can be found here. It's a lot of for my definitions, the relevant code is from line 916.
type Equipment = {
Helmet : Hat option
Armor : Armor option
Legs : Pants option
Gloves : Gauntlets option
Ring : Ring option
Weapon : Weaponry option
Shield : Shield option
Loot : ConsumableItem option
}
let equipPurchasedProtection newItem (inventory,equipment) =
match newItem with
| Helmet ->
match equipment.Helmet with
| None ->
let newEquipment = { equipment with Helmet = Some newItem }
(inventory,newEquipment)
| Some oldHelm
if (playerWantsToAutoEquip newItem) then
let newEquipment = { equipment with Helmet = Some newItem }
let newInventory = inventory |> addToInventory oldHelm
(newInventory,newEquipment)
else
let newInventory = inventory |> addToInventory newItem
(newInventory,equipment)
| Gloves ->
match equipment.Hands with
| None ->
let newEquipment = { equipment with Hands = Some newItem }
(inventory,newEquipment)
| Some oldGloves
if (playerWantsToAutoEquip newItem) then
let newEquipment = { equipment with Hands = Some newItem }
let newInventory = inventory |> addToInventory oldGloves
(newInventory,newEquipment)
else
let newInventory = inventory |> addToInventory newItem
(newInventory,equipment)
| Boots ->
match equipment.Feet with
| None ->
let newEquipment = { equipment with Boot = Some newItem }
(inventory,newEquipment)
| Some oldBoots
if (playerWantsToAutoEquip newItem) then
let newEquipment = { equipment with Boot = Some newItem }
let newInventory = inventory |> addToInventory oldBoots
(newInventory,newEquipment)
else
let newInventory = inventory |> addToInventory newItem
(newInventory,equipment)
let equipPurchasedItem newItem (inventory,equipment) =
let equipFunction =
match newItem with
| Protection(Helmet(_)) -> genericEquipFunction HelmetFun_
| Protection(Gloves(_)) -> genericEquipFunction GlovesFun_
| Protection(Legs(_)) -> genericEquipFunction LegsFun_
| Protection(Armor(_)) -> genericEquipFunction ArmorFun_
| Protection(Ring(_)) -> genericEquipFunction RingFun_
| Protection(Shield(_)) -> genericEquipFunction ShieldFun_
| Weapon _ -> genericEquipFunction WeaponFun_
| Consumable HealthPotion -> genericEquipFunction LootFun_
| Consumable HighHealthPotion -> genericEquipFunction LootFun_
| Consumable MegaHealthPotion -> genericEquipFunction LootFun_
| Consumable Elixir -> genericEquipFunction LootFun_
| Consumable HighElixir -> genericEquipFunction LootFun_
| Consumable MegaElixir -> genericEquipFunction LootFun_
| Consumable PhoenixFeather -> genericEquipFunction LootFun_
| Consumable MedicinalHerb -> genericEquipFunction LootFun_
let itemForInventory,newEquipment = equipFunction (Some newItem) equipment
match itemForInventory with
| None -> (inventory,newEquipment)
| Some item ->
let newInventory = inventory |> addToInventory { Item = item; Count = 1 }
(newInventory,newEquipment)
UPDATE 1 Here's a look at one of the lens function that I'm using to equip purchased items.
let getArmorFun e = e.Armor
let equipArmorFun newArmor e = { e with Armor = newArmor }
let ArmorFun_ = (getArmorFun, equipArmorFun)