Generalised plusequals

16 points
1/21/1970
2 days ago
by leontrolski

Comments


flebron

The website asks what they do in Haskell. The answer is property modification and reading, as well as very powerful traversal constructs, use lenses (https://hackage.haskell.org/package/lens , tutorial at https://hackage.haskell.org/package/lens-tutorial-1.0.5/docs...).

2 days ago

leontrolski

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]
2 days ago

tome

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]
a day ago

RodgerTheGreat

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:

    l[1][1].age:9
    # (1,(2,{"age":9}),4)
    cat
    # {"age":3}
There's no special "infix" promotion syntax, so that last example would be:

    l:l,5
    # (1,(2,{"age":9}),4,5)
[0] http://beyondloom.com/tools/trylil.html
2 days ago

leontrolski

This is surprising to me:

  l[1][1].age:9
  # (1,(2,{"age":9}),4)
How come it doesn't return just:

  {"age":9}
Or is there something totally different going on with references here? As in, how is this different to:

  l_inner = l[1][1]
  l_inner.age:9
2 days ago

RodgerTheGreat

Amending a slice would amend only the slice:

    l_inner:l[1][1]
    # {"age":3}
    l_inner.age:9
    # {"age":9}
    l_inner
    # {"age":9}
    l
    # (1,(2,{"age":3}),4)
If an amending expression isn't "rooted" in a variable binding, it also returns the entire new structure:

    (1,(list 2,list ().age:5),4)[1][1].age:99
    # (1,(2,{"age":99}),4)
a day ago

rokob

Yeah this looks like lenses at first glance

2 days ago

hatthew

It seems like this is proposing syntactic sugar to make mutating and non-mutating operations be on equal footing.

> 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?

2 days ago

two_handfuls

It doesn't mutate l exactly, it makes a new list slightly different from the original one and assigns it to 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).

2 days ago

[deleted]
2 days ago

hatthew

I think I am misunderstanding the behavior of the alt keyword

2 days ago

beaumayns

q has the concept of amend, which is similar: https://code.kx.com/q4m3/6_Functions/#683-general-form-of-fu...

It's quite handy, though the syntax for it is rather clunky compared to the rest of the language in my opinion.

2 days ago