Skip to content

Instantly share code, notes, and snippets.

@holgergp
Last active December 15, 2020 13:45
Show Gist options
  • Save holgergp/37f84740d7b958f40890 to your computer and use it in GitHub Desktop.
Save holgergp/37f84740d7b958f40890 to your computer and use it in GitHub Desktop.
Some fiddling with map, flatMap and foldLeft on Collections, Strings and Option. Trying to understand the generic monadic approach
object flatMapTest {
import scala.util.{ Try, Success, Failure }
println("Welcome to the Scala worksheet") //> Welcome to the Scala worksheet
val intList = 1 :: 2 :: 5 :: Nil //> intList : List[Int] = List(1, 2, 5)
intList.map(x => x * 2) //> res0: List[Int] = List(2, 4, 10)
//intList.flatMap(x=>x*2) //type mismatch; found : Int required: scala.collection.GenTraversableOnce[?]
intList.foldLeft(0)((x, y) => x + y) //> res1: Int = 8
val stringList = "eins" :: "zwei" :: "drei" :: Nil
//> stringList : List[String] = List(eins, zwei, drei)
stringList.map(x => x.reverse) //> res2: List[String] = List(snie, iewz, ierd)
stringList.flatMap(x => x.reverse) //> res3: List[Char] = List(s, n, i, e, i, e, w, z, i, e, r, d)
stringList.foldLeft("")((x, y) => x + y) //> res4: String = einszweidrei
val optionList = Some("Eins") :: None :: Some("Zwei") :: Nil
//> optionList : List[Option[String]] = List(Some(Eins), None, Some(Zwei))
def optionMatcher(x: Option[String]): String = x match { case Some(t) => t case None => "" }
//> optionMatcher: (x: Option[String])String
def optionMatcherToOption(x: Option[String]): Option[String] = x match { case Some(t) => Some(t.reverse) case None => None }
//> optionMatcherToOption: (x: Option[String])Option[String]
optionList.map(x => optionMatcherToOption(x)) //> res5: List[Option[String]] = List(Some(sniE), None, Some(iewZ))
optionList.flatMap(x => x match { case Some(t) => t case None => "" })
//> res6: List[Char] = List(E, i, n, s, Z, w, e, i)
optionList.flatMap(x => x match { case Some(t) => Some(t.reverse) case None => None })
//> res7: List[String] = List(sniE, iewZ)
optionList.flatMap(x => x match { case Some(t) => Some(t.reverse) case None => None })
//> res8: List[String] = List(sniE, iewZ)
optionList.foldLeft(Some(""))((x, y) => Some(optionMatcher(y)))
//> res9: Some[String] = Some(Zwei)
val simpleOption = Some("simple") //> simpleOption : Some[String] = Some(simple)
simpleOption.map(x => x) //> res10: Option[String] = Some(simple)
//simpleOption.flatMap(x=>x) //type mismatch; found : String required: Option[?]
simpleOption.flatMap(x => Some(x)) //> res11: Option[String] = Some(simple)
simpleOption.foldLeft(Some(""))((x, y) => Some(y))
//> res12: Some[String] = Some(simple)
val noneOption = None //> noneOption : None.type = None
noneOption.map(x => x) //> res13: Option[Nothing] = None
noneOption.flatMap(x => x) //> res14: Option[Nothing] = None
noneOption.foldLeft(Some(""))((x, y) => Some(y))//> res15: Some[String] = Some()
def manageByteArray(x: Array[Byte]) = Option(x) //> manageByteArray: (x: Array[Byte])Option[Array[Byte]]
val futureSimulator = Option(Array(12.toByte, 15.toByte))
//> futureSimulator : Option[Array[Byte]] = Some([B@5dfcfece)
futureSimulator.flatMap(x => manageByteArray(x))//> res16: Option[Array[Byte]] = Some([B@5dfcfece)
val futureSimulator2 = Some(Array(12.toByte, 15.toByte))
//> futureSimulator2 : Some[Array[Byte]] = Some([B@23ceabc1)
futureSimulator2.flatMap(x => manageByteArray(x))
//> res17: Option[Array[Byte]] = Some([B@23ceabc1)
val futureSimulator3 = None //> futureSimulator3 : None.type = None
futureSimulator3.flatMap(x => manageByteArray(x))
//> res18: Option[Array[Byte]] = None
//http://stackoverflow.com/questions/27715863/flatmap-implementation-in-scala
//auf Some("String") und Some(Some("String") testen
Some("test").map(x => x) //> res19: Option[String] = Some(test)
Some("test").flatMap(x => Option(x)) //> res20: Option[String] = Some(test)
Some(Some("test")).map(x => x) //> res21: Option[Some[String]] = Some(Some(test))
Some(Some("test")).flatMap(x => Option(x)) //> res22: Option[Some[String]] = Some(Some(test))
Some(None).flatMap(x => Option(x)) //> res23: Option[None.type] = Some(None)
Some(None).map(x => x) //> res24: Option[None.type] = Some(None)
def doSideEffects(x: Option[String]): Option[String] = {
println("Da!")
Some("")
} //> doSideEffects: (x: Option[String])Option[String]
def doSideEffects2(x: String): Option[String] = {
println("Da!")
Some(x)
} //> doSideEffects2: (x: String)Option[String]
Some(None).flatMap(x => doSideEffects(x)) //> Da!
//| res25: Option[String] = Some()
None.flatMap(x => doSideEffects2(x)) //> res26: Option[String] = None
Some("test").flatMap(x => doSideEffects2(x)) //> Da!
//| res27: Option[String] = Some(test)
Some("test").getOrElse(None) //> res28: java.io.Serializable = test
None.getOrElse(None) //> res29: None.type = None
Some("test").map(x => doSideEffects2(x)) //> Da!
//| res30: Option[Option[String]] = Some(Some(test))
Some("test").map(x => doSideEffects2(x)).getOrElse(None)
//> Da!
//| res31: Option[String] = Some(test)
None.map(x => doSideEffects2(x)) //> res32: Option[Option[String]] = None
None.map(x => doSideEffects2(x)).getOrElse(None)//> res33: Option[String] = None
}
@javacook
Copy link

stringList.flatMap(x => x.reverse) == List(s, n, i, e, i, e, w, z, i, e, r, d) is a little bit strange. I can imagine that at x.reverse there happened an autoboxing from String to List[Char].

@holgergp
Copy link
Author

In that case flatMap "flattens" the String list. It treats String as List of chars. The type definition of flatMap says that the resulting type of the function fed into flatMap has to suffice the type scala.collection.GenTraversableOnce[?] as you see in line 6. There the flatMap for List[Int] fails. String seems to implement GenTraversableOnce

@holgergp
Copy link
Author

I interpret GenTraversableOnce as "behave like a baseline list"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment