What would be the equivalent to this in Haskell (with or without lens):
cat = Cat(age=3)
l = [1, [2, cat], 4]
alt l[1][1].age.=9
That would give us l equal to:
[1, [2, Cat(age=9)], 4]
tome 2 hours ago [-]
In Haskell this list is not well-typed
l = [1, [2, cat], 4]
There are a few different ways to cook this up. Here's one:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Cat = Cat { _age :: Int }
deriving Show
makeLenses ''Cat
data Item
= I Int
| L [Item]
| C Cat
deriving Show
makePrisms ''Item
cat :: Cat
cat = Cat 3
l :: [Item]
l = [I 1, L [I 2, C cat], I 4]
l' :: [Item]
l' = set (ix 1 . _L . ix 1 . _C . age) 9 l
ghci> l'
[I 1,L [I 2,C (Cat {_age = 9})],I 4]
RodgerTheGreat 12 hours ago [-]
In Lil[0], this is how ordinary assignment syntax works. Implicitly defining a dictionary stored in a variable named "cat" with a field "age":
cat.age:3
# {"age":3}
Defining "l" as in the example in the article. We need the "list" operator to enlist nested values so that the "," operator doesn't concatenate them into a flat list:
l:1,(list 2,list cat),4
# (1,(2,{"age":3}),4)
Updating the "age" field in the nested dictionary. Lil's basic datatypes are immutable, so "l" is rebound to a new list containing a new dictionary, leaving any previous references undisturbed:
> The more interesting example is reassigning the deeply nested l to make the cat inside older, without mutating the original cat
Isn't that mutating l, though? If you're concerned about mutating cat, shouldn't you be concerned about mutating l?
That means if someone has a reference to the original l, they do not see the change (because l is immutable. Both of them).
It's quite handy, though the syntax for it is rather clunky compared to the rest of the language in my opinion.