0

I've tried to simplify a real code but not to much.

Given the following input, implementation of f and g are just for examples, real one are more complicated

scala> val m = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4)
m: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2, c -> 3, d -> 4)

scala> val f : Int => Option[Int] = i => if (i % 2 == 0) Some(i) else None
f: Int => Option[Int] = <function1>

scala> val g = (a:Int, l:List[Int]) => a :: l
g: (Int, List[Int]) => List[Int] = <function2>

Here is the process :

m.foldLeft(List[Int]()) { case (l, (k, v)) => 
  f(v) match {
    case Some(w) => g(w, l)
    case None => l
  }
}

Is it possible to use scalaz to better reveal the intent ?

I'm thinkink about m.traverseS

Electric Coffee
  • 11,733
  • 9
  • 70
  • 131
Yann Moisan
  • 8,161
  • 8
  • 47
  • 91

2 Answers2

0

If g really needs to handle the whole List[Int] then I immediately thought of Endo (requires slightly rewriting g):

val f: Int => Iterable[Int] = ???
val g: Int => Endo[List[Int]] = ???

val m = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4)

Foldable[List].fold(m.values.toList flatMap f map g).apply(List[Int]())

I'm not sure that's much clearer though.

lmm
  • 17,386
  • 3
  • 26
  • 37
  • as indicated above, f and g code are just for examples, only signatures are important. – Yann Moisan Oct 06 '14 at 14:10
  • That's why I deliberately wrote my example using just the signatures. An Option[Int] really is an Iterable[Int] (there's even an implicit for it) and a (Int, List[Int]) => List[Int] can always be written as an Int => Endo[List[Int]]. So these signatures are valid for any implementation of f and g. – lmm Oct 06 '14 at 15:24
0
m.collect{ case(s, i) => (s, f(i))}
 .filter{ case (s,i) => i.isDefined }
 .toList
 .traverseS({s => State({ l: List[Int] => (g(s._2.get, l), ())})})
 .run(Nil)
 ._1
 .reverse
Yann Moisan
  • 8,161
  • 8
  • 47
  • 91