Pavel
Pavel

Reputation: 127

Update nested maps in scala

In haskell it is possible to do the following.

import Control.Lens
import qualified Data.Map as M
m :: Map Int (Map Int String)
m = M.empty & at 1 . non M.empty . at 2 .~ Just "one-two"

Is it possible to do something similar in scala? Maybe using scalaz? I mean updating nested map with default value.

Update: Ok can we at least compose function for updating value in a Map without specifying all involved types. Having function like this.

// modifyMap :: (k, v) -> (v -> v) -> Map k v -> Map k v
def modifyMap[K,V](k: K, v: V)(f: V => V)(m: Map[K,V]): Map[K,V] = {
    m + (k -> f(m.getOrElse(k, v)))
}

And I would like to be able to compose this function, in what seems to be reasonable way.

// (modifyMap (1, M.empty) . modifyMap (2, "")) (const "one-two") M.empty
(modifyMap(1, Map.empty) compose modifyMap(2, ""))(_ => "one-two")(Map.empty)

It is basically the same as haskell example, but type just would not derive with out being fully specified.

Upvotes: 1

Views: 601

Answers (2)

Julien Truffaut
Julien Truffaut

Reputation: 497

you can get something similar with Monocle :

import monocle.syntax._ // to use optics as infix operator, it is required to guide type inference
import monocle.function._ // to get generic optics like at, index etc
import monocle.std.map._ // to get Map instances of At, Index

(Map.empty[Int, Map[Int, String]] applyOptional index(1) composeLens at(2)).set(Some("one-two"))

// if you prefer there are some symbolic aliases

(Map.empty[Int, Map[Int, String]] &|-> index(1) ^|-> at(2)).set(Some("one-two"))

I couldn't test it, please tell me if it doesn't compile

Upvotes: 2

roterl
roterl

Reputation: 1883

Look at Shapless lenses or at scalaz as @Peter commented.

Upvotes: -1

Related Questions