0

In trying to understand Monads as "a structure that represents computations defined as sequences of steps" : https://en.wikipedia.org/wiki/Monad_(functional_programming)

This example :

def optionAdd(x:Option[Int], y:Option[Int]):Option[Int] = 
  for(xx <- x; yy <- y) yield xx+yy 

taken from Scala Monad - Full worked example. This monad concatenates two Strings in a predefined order.

I'm attempting to wrap these steps within a monad :

 1. Get String to be converted to html
 2. Perform series of replace statements on the String to create html compliant String



  def getString = {
    "def test() \n { }"
  }                                               //> getString: => String
  val stringOption = Option(getString);           //> stringOption  : Option[String] = Some(def test() 
                                                  //|  { })
  def createHtmlMonad(x: Option[String]): Option[String] =
    Option(x.get.replace("\n", "<br>").replace("def", "<div style=\"color:red\" </div>"));
                                                  //> createHtmlMonad: (x: Option[String])Option[String]
  val h = createHtmlMonad(stringOption);          //> h  : Option[String] = Some(<div style="color:red" </div> test() <br> { })

The method createHtmlMonad is not a Monad ? Can this functionality be encapsulated within a Monad ?

I could just create a new method that encapsulates the series of steps but this is not a Monad :

    def getString = {
    "def test() \n { }"
  }                                               //> getString: => String

  def stepsToCreateHtml(stringOption: Option[String]) = {

    val replaceBr = Option(stringOption.get.replace("\n", "<br>"))
    val replaceStyle = Option(replaceBr.get.replace("def", "<div style=\"color:red\" </div>"))

    replaceStyle
  }                                               //> stepsToCreateHtml: (stringOption: Option[String])Option[String]
  val stringOption = Option(getString);           //> stringOption  : Option[String] = Some(def test() 
                                                  //|  { })

  val html = stepsToCreateHtml(stringOption);     //> html  : Option[String] = Some(<div style="color:red" </div> test() <br> { })
                                                  //| 

Update : I think this helps to answer the question. Instead of creating a new monad I re-use the existing Option monad :

object t extends App {

  println(parseService.getHtml("").flatMap(convertBr).flatMap(convertStyle))

  def convertBr = (str: String) => Option(str.replaceAll("\n", "<br>"))
  def convertStyle = (str: String) => Option(str.replaceAll("def", "<div style= color : \"red\"></div>"))

}

object parseService {
  def getHtml(str: String): Some[String] = {
    Some("test \n newline def")
  }
}

This is based on https://medium.com/@sinisalouc/demystifying-the-monad-in-scala-cc716bb6f534#.xprt8msoc . The monad itself is just a wrapper, the value is how it is composed with the functionality to be implemented, in this case I use the Option monad to compase appending of new Strings. I still do not fully understand monads but feel a little closer.

Community
  • 1
  • 1
blue-sky
  • 51,962
  • 152
  • 427
  • 752
  • 1
    `createHtmlMonad` is not a monad, only monad in your code is `Option` monad. You do computation in the context of monad by using `flatMap` which for `M[A]` takes a function `A => M[B]` and returns `M[B]`. Try to read more about monads, maybe not just wiki as that explanation is kind of unclear. Try http://stackoverflow.com/questions/44965/what-is-a-monad – Łukasz Jan 18 '16 at 15:20
  • @Łukasz please see update – blue-sky Jan 18 '16 at 17:12
  • This is a step in right direction. You should use monad when it does something for you, current code doesn't take advantage of it. `Option` monad is represents some context in which value may be present or not, here, your value is always present. If let's say your actions could fail your `convertBr` could return `Some(replacedText)` or `None` if replacing failed. Having a many operations of this kind and combining them using monad would make your life easier as the final result after all transformations would be `Some(result)` or `None` if failed (no nested checks). – Łukasz Jan 18 '16 at 17:31
  • Perhaps when you get deeper understanding of some common monads, the general concept will become clearer. You could read about `Option`, `Try`, `Either`, `Future`. Maybe something from scalaz, there is a great presentation on `State` monad here https://www.youtube.com/watch?v=Jg3Uv_YWJqI – Łukasz Jan 18 '16 at 17:38
  • 1
    I recommend LYAH - http://learnyouahaskell.com/a-fistful-of-monads – Kevin Meredith Jan 18 '16 at 18:52

1 Answers1

1

I find that it's easier to understand that particular analogy of a monad when it's written in it's for comprehension form,

for {
  cbr <- convertBr(parseService.getHtml("")) //step 1
  cs <- convertStyle(cbr) //step 2
} yield cs

which is compiled directly to the flatmap form which you've written in your segment. Each of the lines is a step in this case and the Option monad provides the logic of how the steps are linked together and interpreted.

In this case the Option monad terminates the next steps when the previous step does not return a value which is present, i.e. a None but allows the computation to continue when a value is returned i.e. a Some.

def flatMap[B](f: A => Option[B]): A =  this match {
    case Some(a) => f(a)
    case None => None
}

The monad then can be thought of as the computational context in which the steps happen with the flatmap determining how the computation proceeds.

It's worth noting however that this is just an analogy/metaphor. A monad is simly something that follows the monadic laws.

The law which is most important can be written in scala as simply,

val ab = for {
 a <- genA
 b <- genB
} yield (a, b)

val ba = for {
 b <- genB
 a <- genA
} yield (a, b)

assert(ab == ba)
yw3410
  • 228
  • 3
  • 8