How to make your own for-comprehension compliant scala monad? - scala

I want to implement my own for-comprehension compatible monads and functors in Scala.
Let's take two stupid monads as an example. One monad is a state monad that contains an "Int" that you can map or flatmap over.
val maybe = IntMonad(5)
maybe flatMap( a => 3 * ( a map ( () => 2 * a ) ) )
// returns IntMonad(30)
Another monad takes does function composition like so...
val func = FunctionMonad( () => println("foo") )
val fooBar = func map ( () => println("bar") )
fooBar()
// foo
// bar
// returns Unit
The example may have some mistakes, but you get the idea.
I want to be able to use these two different types of made up Monads inside a for-comprehension in Scala. Like this:
val myMonad = IntMonad(5)
for {
a <- myMonad
b <- a*2
c <- IntMonad(b*2)
} yield c
// returns IntMonad(20)
I am not a Scala master, but you get the idea

For a type to be used within a for-comprehension, you really only need to define map and flatMap methods for it that return instances of the same type. Syntactically, the for-comprehension is transformed by the compiler into a series of flatMaps followed by a final map for the yield. As long as these methods are available with the appropriate signature, it will work.
I'm not really sure what you're after with your examples, but here is a trivial example that is equivalent to Option:
sealed trait MaybeInt {
def map(f: Int => Int): MaybeInt
def flatMap(f: Int => MaybeInt): MaybeInt
}
case class SomeInt(i: Int) extends MaybeInt {
def map(f: Int => Int): MaybeInt = SomeInt(f(i))
def flatMap(f: Int => MaybeInt): MaybeInt = f(i)
}
case object NoInt extends MaybeInt {
def map(f: Int => Int): MaybeInt = NoInt
def flatMap(f: Int => MaybeInt): MaybeInt = NoInt
}
I have a common trait with two sub-types (I could have as many as I wanted, though). The common trait MaybeInt enforces each sub-type to conform to the map/flatMap interface.
scala> val maybe = SomeInt(1)
maybe: SomeInt = SomeInt(1)
scala> val no = NoInt
no: NoInt.type = NoInt
for {
a <- maybe
b <- no
} yield a + b
res10: MaybeInt = NoInt
for {
a <- maybe
b <- maybe
} yield a + b
res12: MaybeInt = SomeInt(2)
Additionally, you can add foreach and filter. If you want to also handle this (no yield):
for(a <- maybe) println(a)
You would add foreach. And if you want to use if guards:
for(a <- maybe if a > 2) yield a
You would need filter or withFilter.
A full example:
sealed trait MaybeInt { self =>
def map(f: Int => Int): MaybeInt
def flatMap(f: Int => MaybeInt): MaybeInt
def filter(f: Int => Boolean): MaybeInt
def foreach[U](f: Int => U): Unit
def withFilter(p: Int => Boolean): WithFilter = new WithFilter(p)
// Based on Option#withFilter
class WithFilter(p: Int => Boolean) {
def map(f: Int => Int): MaybeInt = self filter p map f
def flatMap(f: Int => MaybeInt): MaybeInt = self filter p flatMap f
def foreach[U](f: Int => U): Unit = self filter p foreach f
def withFilter(q: Int => Boolean): WithFilter = new WithFilter(x => p(x) && q(x))
}
}
case class SomeInt(i: Int) extends MaybeInt {
def map(f: Int => Int): MaybeInt = SomeInt(f(i))
def flatMap(f: Int => MaybeInt): MaybeInt = f(i)
def filter(f: Int => Boolean): MaybeInt = if(f(i)) this else NoInt
def foreach[U](f: Int => U): Unit = f(i)
}
case object NoInt extends MaybeInt {
def map(f: Int => Int): MaybeInt = NoInt
def flatMap(f: Int => MaybeInt): MaybeInt = NoInt
def filter(f: Int => Boolean): MaybeInt = NoInt
def foreach[U](f: Int => U): Unit = ()
}

Related

Conflicting method when paramter is limited to AnyRef and AnyVal in Scala

Scala compiler detects the following two map functions as duplicates conflicting with each other:
class ADT {
def map[Output <: AnyVal](f: Int => Output): List[Output] = ???
def map[Output >: Null <: AnyRef](f: Int => Output): List[Output] = ???
}
The class type of Output parameter is different. First one limits to AnyVal and second one limits to AnyRef. How can I differentiate them?
The problem is not differentiating AnyVal from AnyRef so much as getting around the fact that both method signatures become the same after erasure.
Here is a neat trick to get around this kind of problem. It is similar to what #som-snytt did, but a bit more generic, as it works for other similar situations as well (e.g. def foo(f: Int => String): String = ??? ; def foo(f: String => Int): Int = ??? etc.):
class ADT {
def map[Output <: AnyVal](f: Int => Output): List[Output] = ???
def map[Output >: Null <: AnyRef](f: Int => Output)(implicit dummy: DummyImplicit): List[Output] = ???
}
The cutest thing is that this works "out of the box". Apparently, a DummyImplicit is a part of standard library, and you always have the thing in scope.
You can have more than two overloads this way too by just adding more dummies to the list.
scala 2.13.0-M5> :pa
// Entering paste mode (ctrl-D to finish)
object X {
def map[Output <: AnyVal](f: Int => Output) = 1
def map[O](f: Int => O)(implicit ev: O <:< AnyRef) = 2
}
// Exiting paste mode, now interpreting.
defined object X
scala 2.13.0-M5> X.map((x: Int) => x*2)
res0: Int = 1
scala 2.13.0-M5> X.map((x: Int) => "")
res1: Int = 2
You could use a typeclass for that map method.
Using your exact example:
trait MyTC[Output]{
def map(f: Int => Output): List[Output]
}
object MyTC{
def apply[A](a : A)(implicit ev : MyTC[A]) : MyTC[A] = ev
implicit def anyRefMyTc[A <: AnyRef] : MyTC[A] = new MyTC[A]{
def map(f: Int => A): List[A] = { println("inside sub-AnyRef"); List.empty }
}
implicit def anyValMyTc[A <: AnyVal] : MyTC[A] = new MyTC[A]{
def map(f: Int => A): List[A] = { println("inside sub-AnyVal"); List.empty }
}
}
import MyTC._
val r1 = Option("Test1")
val r2 = List(5)
val v1 = true
val v2 = 6L
// The functions here are just to prove the point, and don't do anything.
MyTC(r1).map(_ => None)
MyTC(r2).map(_ => List.empty)
MyTC(v1).map(_ => false)
MyTC(v2).map(_ => 10L)
That would print:
inside sub-AnyRef
inside sub-AnyRef
inside sub-AnyVal
inside sub-AnyVal
The advantage of this approach is that, should you then choose to specialise the behaviour further for just some specific type (e.g. say you want to do something specific for Option[String]), you can do that easily:
// This is added to MyTC object
implicit val optMyTc : MyTC[Option[String]] = new MyTC[Option[String]]{
def map(f: Int => Option[String]): List[Option[String]] = { println("inside Option[String]"); List.empty }
}
Then, re-running the code will print:
inside Option[String]
inside sub-AnyRef
inside sub-AnyVal
inside sub-AnyVal

Scala (scalaz) State monad - map over Option state type

How can I apply implement the following function?
def wrapIntoOption(state: State[S, A]): State[Option[S], Option[A]]
The bigger picture is this:
case class Engine(cylinders: Int)
case class Car(engineOpt: Option[Engine])
val engineOptLens = Lens.lensu((c, e) => c.copy(engineOpt = e), _.engineOpt)
def setEngineCylinders(count: Int): State[Engine, Int] = State { engine =>
(engine.copy(cylinders = count), engine.cylinders)
}
def setEngineOptCylinders(count: Int): State[Option[Engine], Option[Int]] = {
??? // how to reuse setEngineCylinders?
}
def setCarCylinders(count: Int): State[Car, Option[Int]] = {
engineOptLens.lifts(setEngineOptCylinders)
}
Is there nicer way to deal with Option properties?
One way to create the wrapIntoOption function would be to call run on the passed State[S, A] and convert the resulting (S, A) tuple into (Option[S], Option[A]).
import scalaz.State
import scalaz.std.option._
import scalaz.syntax.std.option._
def wrapIntoOption[S, A](state: State[S, A]): State[Option[S], Option[A]] =
State(_.fold((none[S], none[A])){ oldState =>
val (newState, result) = state.run(oldState)
(newState.some, result.some)
})
You could then define setEngineOptCylinders as :
def setEngineOptCylinders(count: Int): State[Option[Engine], Option[Int]] =
wrapIntoOption(setEngineCylinders(count))
Which you can use as :
scala> val (newEngine, oldCylinders) = setEngineOptCylinders(8).run(Engine(6).some)
newEngine: Option[Engine] = Some(Engine(8))
oldCylinders: Option[Int] = Some(6)

Overcoming Scala Type Erasure For Function Argument of Higher-Order Function

Essentially, what I would like to do is write overloaded versions of "map" for a custom class such that each version of map differs only by the type of function passed to it.
This is what I would like to do:
object Test {
case class Foo(name: String, value: Int)
implicit class FooUtils(f: Foo) {
def string() = s"${f.name}: ${f.value}"
def map(func: Int => Int) = Foo(f.name, func(f.value))
def map(func: String => String) = Foo(func(f.name), f.value)
}
def main(args: Array[String])
{
def square(n: Int): Int = n * n
def rev(s: String): String = s.reverse
val f = Foo("Test", 3)
println(f.string)
val g = f.map(rev)
val h = g.map(square)
println(h.string)
}
}
Of course, because of type erasure, this won't work. Either version of map will work alone, and they can be named differently and everything works fine. However, it is very important that a user can call the correct map function simply based on the type of the function passed to it.
In my search for how to solve this problem, I cam across TypeTags. Here is the code I came up with that I believe is close to correct, but of course doesn't quite work:
import scala.reflect.runtime.universe._
object Test {
case class Foo(name: String, value: Int)
implicit class FooUtils(f: Foo) {
def string() = s"${f.name}: ${f.value}"
def map[A: TypeTag](func: A => A) =
typeOf[A] match {
case i if i =:= typeOf[Int => Int] => f.mapI(func)
case s if s =:= typeOf[String => String] => f.mapS(func)
}
def mapI(func: Int => Int) = Foo(f.name, func(f.value))
def mapS(func: String => String) = Foo(func(f.name), f.value)
}
def main(args: Array[String])
{
def square(n: Int): Int = n * n
def rev(s: String): String = s.reverse
val f = Foo("Test", 3)
println(f.string)
val g = f.map(rev)
val h = g.map(square)
println(h.string)
}
}
When I attempt to run this code I get the following errors:
[error] /src/main/scala/Test.scala:10: type mismatch;
[error] found : A => A
[error] required: Int => Int
[error] case i if i =:= typeOf[Int => Int] => f.mapI(func)
[error] ^
[error] /src/main/scala/Test.scala:11: type mismatch;
[error] found : A => A
[error] required: String => String
[error] case s if s =:= typeOf[String => String] => f.mapS(func)
It is true that func is of type A => A, so how can I tell the compiler that I'm matching on the correct type at runtime?
Thank you very much.
In your definition of map, type A means the argument and result of the function. The type of func is then A => A. Then you basically check that, for example typeOf[A] =:= typeOf[Int => Int]. That means func would be (Int => Int) => (Int => Int), which is wrong.
One of ways of fixing this using TypeTags looks like this:
def map[T, F : TypeTag](func: F)(implicit ev: F <:< (T => T)) = {
func match {
case func0: (Int => Int) #unchecked if typeOf[F] <:< typeOf[Int => Int] => f.mapI(func0)
case func0: (String => String) #unchecked if typeOf[F] <:< typeOf[String => String] => f.mapS(func0)
}
}
You'd have to call it with an underscore though: f.map(rev _). And it may throw match errors.
It may be possible to improve this code, but I'd advise to do something better. The simplest way to overcome type erasure on overloaded method arguments is to use DummyImplicit. Just add one or several implicit DummyImplicit arguments to some of the methods:
implicit class FooUtils(f: Foo) {
def string() = s"${f.name}: ${f.value}"
def map(func: Int => Int)(implicit dummy: DummyImplicit) = Foo(f.name, func(f.value))
def map(func: String => String) = Foo(func(f.name), f.value)
}
A more general way to overcome type erasure on method arguments is to use the magnet pattern. Here is a working example of it:
sealed trait MapperMagnet {
def map(foo: Foo): Foo
}
object MapperMagnet {
implicit def forValue(func: Int => Int): MapperMagnet = new MapperMagnet {
override def map(foo: Foo): Foo = Foo(foo.name, func(foo.value))
}
implicit def forName(func: String => String): MapperMagnet = new MapperMagnet {
override def map(foo: Foo): Foo = Foo(func(foo.name), foo.value)
}
}
implicit class FooUtils(f: Foo) {
def string = s"${f.name}: ${f.value}"
// Might be simply `def map(func: MapperMagnet) = func.map(f)`
// but then it would require those pesky underscores `f.map(rev _)`
def map[T](func: T => T)(implicit magnet: (T => T) => MapperMagnet): Foo =
magnet(func).map(f)
}
This works because when you call map, the implicit magnet is resolved at compile time using full type information, so no erasure happens and no runtime type checks are needed.
I think the magnet version is cleaner, and as a bonus it doesn't use any runtime reflective calls, you can call map without underscore in the argument: f.map(rev), and also it can't throw runtime match errors.
Update:
Now that I think of it, here magnet isn't really simpler than a full typeclass, but it may show the intention a bit better. It's a less known pattern than typeclass though. Anyway, here is the same example using the typeclass pattern for completeness:
sealed trait FooMapper[F] {
def map(foo: Foo, func: F): Foo
}
object FooMapper {
implicit object ValueMapper extends FooMapper[Int => Int] {
def map(foo: Foo, func: Int => Int) = Foo(foo.name, func(foo.value))
}
implicit object NameMapper extends FooMapper[String => String] {
def map(foo: Foo, func: String => String) = Foo(func(foo.name), foo.value)
}
}
implicit class FooUtils(f: Foo) {
def string = s"${f.name}: ${f.value}"
def map[T](func: T => T)(implicit mapper: FooMapper[T => T]): Foo =
mapper.map(f, func)
}

Implicit conversions for defs/lambdas in Scala?

I just ran into a strange disparity between functions and objects (scala 2.10):
implicit def conv(c: Int => String) : (PrintStream => Int => Unit) = p => v => p.println(c(v))
def f(h: PrintStream => Int => Unit) : Unit = h(System.out)(1)
def a(x: Int) = x.toString
val b = (x: Int) => x.toString
// def main(args: Array[String]) = f(a) // fail
// def main(args: Array[String]) = f((x: Int) => x.toString) // fail
def main(args: Array[String]) = f(b) // ok
Why is there a difference between defs/lambda literals and lambda vals?
Update: apparently, the Problem does not occur for binary functions: Implicit conversion of a function to a second-order-function only works if the function to convert has at least two parameters
I checked this, and indeed the following code works:
implicit def conv(c: (Int,Unit) => String) : (PrintStream => Int => Unit) = p => v => p.println(c(v,()))
def f(h: PrintStream => Int => Unit) : Unit = h(System.out)(1)
def a(x: Int, y : Unit) = x.toString
val b = (x: Int, y : Unit) => x.toString
def main(args: Array[String]) = f(a) // ok
def main(args: Array[String]) = f((x: Int, y: Unit) => x.toString) // ok
def main(args: Array[String]) = f(b) // ok
Likewise, Nullary functions don't pose a problem, either:
implicit def conv(c: () => String) : (PrintStream => Int => Unit) = p => v => p.println(c())
def f(h: PrintStream => Int => Unit) : Unit = h(System.out)(1)
def a() = "1"
val b = () => "1"
def main(args: Array[String]) = f(a) // ok
def main(args: Array[String]) = f(() => "1") // ok
def main(args: Array[String]) = f(b) // ok
So, rephrasing the question: why does this not work for UNARY methods and functions?
Update: the problem also seems to be related to the target type (the type of f's argument h). The following also works (this time, in favour of "eta-expansion counts as hop", because we need to create a method value from a using _)
implicit def conv(c: Int => String) : Unit = ()
def f(h: Unit) : Unit = System.out.print("?")
def a(x: Int) = x.toString
val b = (x: Int) => x.toString
def main(args: Array[String]) = f(a _) // ok
def main(args: Array[String]) = f((x: Int) => x.toString) // ok
def main(args: Array[String]) = f(b) // ok
In scala defs are methods and are diffrent from functions.
scala> def a( x: Int, y: Int ): Int = x + y
a: (x: Int, y:Int)Int
scala> (x: Int, y: Int) => x + y
res0: (Int, Int) => Int = <function2>
You can convert a method to function by partially applying it.
scala> b _
res1: (Int, Int) => Int = <function2>
So.. you can do,
implicit def conv(c: Int => String) : (PrintStream => Int => Unit) = p => v => p.println(c(v))
def f(h: PrintStream => Int => Unit) : Unit = h(System.out)(1)
def a(x: Int) = x.toString
val af = a _
def main( args: Array[ String ] ) = f( af )
Alse, as #srgfed01 mentioned in his comment... for the second case the problem is that... they types are not explicitly specified, if you specify the type correctly... the second case will work.
scala> f( ( a => a.toString ): (Int => String) )
1
or
scala> f( ( _.toString ): (Int => String) )
1
Now, about differences between methods and functions...
You can call a method taking no arguments without parenthesis ()... but you can not call a function without ().
scala> def g() = 5
g: ()Int
scala> g
res15: Int = 5
scala> () => 5
res13: () => Int = <function0>
scala> res13
res14: () => Int = <function0>
scala> res13()
res15: 5
One of the most important reasons for methods being different from functions is because creators of Scala wanted seamless inter-interoperability with Java without being stuck with Java's limitations.
So methods (def) are very much similar to Java methods and keeping functions different from methods enabled them with limitless freedom to create Scala, the way they wanted.
Also... Another major difference is that methods can accept Type-classes where as functions can not. Basically you can have generic methods like
scala> :paste
trait Behave {
def behave
}
class A( elem: String ) extends Behave {
def behave() {
println( elem )
}
}
// Exiting paste mode, now interpreting.
defined trait Behave
defined class A
Now you can define a generic method,
scala> def check[ T <: Behave ]( t: T ): Unit = t.behave()
check: [T <: Behave](t: T)Unit
But you can not define a function like this,
scala> ( t: T ) => t.behave()
<console>:8: error: not found: type T
( t: T ) => t.behave()
or like this
scala> ( t: (T <: Behave) ) => t.behave()
<console>:1: error: ')' expected but '<:' found.
( t: (T <: A) ) => t.behave()

Scala: require that a function argument is a member of some class?

I want to do something like
class A {
def f1: Unit = ...
def f2: Unit = ...
}
def foo(f: => Unit) {
(new A).f // ???
}
where f is supposed to be a member function of class A. I believe the standard solution is
def foo(f: A => Unit) {
f(new A)
}
and use it in this way
foo(_.f1)
foo(_.f2)
But now I can pass in an arbitrary function that has this signature, which may be not desired. Is there anyway to ensure that, the function I pass in is a member of certain class?
Well, if you don't mind a few contortions, you can use the fact that a function IS a class after all...
// abstract class MyIntToString extends (Int => String) // declare here if you want
// to use from different classes
// EDIT: f1 and f2 are now val instead of def as per comment below
// by #RĂ©gis Jean-Gilles
class A {
abstract class MyIntToString private[A]() extends (Int => String)
// if MyIntToString is declared here
// with a constructor private to the enclosing class
// you can ensure it's used only within A (credit goes to #AlexeyRomanov
// for his comment below)
val f1 = new MyIntToString {
def apply(i: Int) = i.toString + " f1"
}
val f2= new MyIntToString {
def apply(i: Int) = i.toString + " f2"
}
}
def foo(f: A#MyIntToString) = f(42) // f: MyIntToString if MyIntToString not nested in A
val a = A
now you can do:
scala> foo((new A).f1)
res1: String = 42 f1
scala> foo((new A).f2)
res2: String = 42 f2
but foo will not accept Int => String signatures
scala> val itos = (i:Int) => i.toString
itos: Int => String = <function1>
scala> foo(itos)
<console>:11: error: type mismatch;
found : Int => String
required: MyIntToString
foo(itos)
^