elm / core

Elm's core libraries
http://package.elm-lang.org/packages/elm/core/latest
BSD 3-Clause "New" or "Revised" License
2.8k stars 359 forks source link

Function Request : Array.update #298

Closed TheSeamau5 closed 9 years ago

TheSeamau5 commented 9 years ago

The following function would be very valuable and it would be best if the implementation were native:

update: Int -> (a -> a) -> Array a -> Array a 

This function would be analogous to Array.set and would be strictly equivalent to the following implementation using both Array.set and Array.get.

update' n f array = 
  case Array.get n array of 
    Nothing -> 
      array 
    Just x -> 
      Array.set (f x) array

(so, here's a good unit/property-based test for the update function).

The goal of having a native implementation is to avoid getting and setting in two distinct steps. This function would prove invaluable in the update step of the Elm Architecture

update : (action -> state -> state) -> Action action -> State state -> State state 
update updateChild action state = 
  case action of 
    ChildAction index childAction -> 
       { state | children <- Array.update index (updateChild action) state.children }

This would avoid the troublesome need of using functions like indexedMap to do this sort of work, and a native implementation could fuse the setting and the getting step of this operation in a way that isn't possible currently.

sindikat commented 9 years ago

I support this. Matrix third-party library has update, and Matrix a is just a type alias for Array (Array a). I use Matrix's update in my roguelike game all the time.

evancz commented 9 years ago

Following these guidelines I am going to close this, but I agree that this function would be very valuable and probably should be built in.

jinjor commented 7 years ago

I was about to make the same issue, but maybe we should consider consistency with Dict.update.

Alternative plan: update: Int -> (Maybe a -> Maybe a) -> Array a -> Array a

Personally, I want both.

boxofrox commented 7 years ago

@jinjor, I think your update signature needs a few more details as to how it should be implemented.

For Dict, the (Maybe a -> Maybe a) argument allows a user to assign a default value if Nothing exists at the index.

For an Array, how would that work if your index is out of bounds?

For example, what does the following produce?

things = Array.initialize 5 identity
--=> Array.fromList [ 0, 1, 2, 3, 4 ]

addOrDefault : Int -> Int -> Maybe Int -> Maybe Int
addOrDefault x default y =
  case y of
    Nothing -> Just default
    Just yy -> Just x + yy

Array.update 25 (addOrDefault 5 0) things
--=> ????

The benefit of update : Int -> (a -> a) -> Array a -> Array a is that it's simple, useful, and has practically one implementation. Given your signature has tradeoffs and concerns beyond "change value at this index", it may belong in a separate library.

jinjor commented 7 years ago

@boxofrox Ah, that's fair. You are right.