Created
December 22, 2015 22:32
-
-
Save steinybot/4fe5626f9f0800f0748f to your computer and use it in GitHub Desktop.
My attempt at learning Monads in Scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* I wrote this while trying to figure out what a monad was and how you would write one. No guarantees that this is | |
* actually a monad or good code at all. | |
* | |
* I wanted this monad to encapsulate side effects and apply them lazily. One interesting observation that I found | |
* from all the println statements was that in order for the bind (flatMap) to not evaluate the side effect was to use | |
* by-name parameters. Not sure if this is really a unit function anymore... | |
*/ | |
object StringOpsMonad extends App { | |
println("-----") | |
val a = NoOp("hello") | |
println("a") | |
println(a.op) | |
println("-----") | |
val b = a flatMap { CapitaliseOp.apply(_) } | |
println("b") | |
println(b.op) | |
println("-----") | |
val c = b flatMap { DuplicateOp.apply(_) } | |
println("c") | |
println(c.op) | |
println("-----") | |
val d = for { | |
a <- NoOp("hello") | |
b <- CapitaliseOp(a) | |
c <- DuplicateOp(b) | |
} yield c | |
println("d") | |
println(d.op) | |
println("-----") | |
val e = NoOp("hello") flatMap { str => | |
CapitaliseOp(str) flatMap { str => | |
DuplicateOp(str) map { str => | |
str | |
} | |
} | |
} | |
println("e") | |
println(e.op) | |
println("-----") | |
for { | |
a <- NoOp("hello") | |
b <- CapitaliseOp(a) | |
c <- DuplicateOp(b) | |
} { | |
println("f") | |
println(c) | |
} | |
} | |
sealed abstract class StringOp { | |
def op: String | |
def map(func: String => String): StringOp = NoOp(func(op)) | |
def flatMap(func: String => StringOp): StringOp = ComposedOp(op, func) | |
def foreach[T](func: String => T): Unit = func(op) | |
private object ComposedOp { | |
def apply(otherOp: => String, func: String => StringOp): StringOp = new StringOp { | |
def op: String = func(otherOp).op | |
} | |
} | |
} | |
object NoOp { | |
def apply(str: => String): StringOp = new NoOp(str) | |
} | |
class NoOp(str: => String) extends StringOp { | |
def op: String = { | |
println("NoOp operator") | |
str | |
} | |
} | |
object CapitaliseOp { | |
def apply(str: => String): StringOp = new CapitaliseOp(str) | |
} | |
class CapitaliseOp(str: => String) extends StringOp { | |
def op: String = { | |
println("CapitaliseOp operator") | |
str.capitalize | |
} | |
} | |
object DuplicateOp { | |
def apply(str: => String): StringOp = new DuplicateOp(str) | |
} | |
class DuplicateOp(str: => String) extends StringOp { | |
def op: String = { | |
println("DuplicateOp operator") | |
str + str | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment