Generics Issues while implementing monad - scala

I saw the below code on SO. But the problem it has is that it's map and flatMap definitions aren't fully correct. map must be able to transform the inside value of a monadic container/context, and the same way a flatMap should take a value, transform it and put it back in the monadic context/container. In the example below it's taking an A and giving an A or M[A] (instead of A->B or A->M[B])
trait Mine[A] {
def get(): A
def map(f: A => A): Mine[A]
def flatMap(f: A => Mine[A]): Mine[A]
}
case class Attempt1[A, B](a: (A, B)) extends Mine[(A, B)] {
def get(): (A, B) = a
def map(f: ((A, B)) => (A, B)): Mine[(A, B)] = {
Attempt1(f(a._1, a._2))
}
def flatMap(f: ((A, B)) => Mine[(A, B)]): Mine[(A, B)] = {
f(a._1, a._2)
}
}
So I thought of changing it and that's where I got stuck. The below code is failing for all the right reasons but can someone guide on how to implement something similar?
trait Opt[A] {
def map[B](f: A => B): Opt[B]
def flatMap[B](f: A => Opt[B]): Opt[B]
}
case class Osome[A, B](a: (A, B)) extends Opt[(A, B)] {
def flatMap[C, D](f: ((A, B)) => Opt[(C,D)]): Opt[(C, D)] = {
f(a._1, a._2)
}
def map [C, D] (f: ((A, B)) => (C, D)): Opt[(C, D)] = {
Osome(f(a._1, a._2))
}
}

The problem is, that you don't implement the map and flatMap methods of Opt in your Osome class, but you overload them. In your trait they both have one type parameter, but in your implementation they have two. Aside from that, your Osome would anyway not be a monad, as it restricts the resulting type of map and flatMap, where monads allow for arbitrary types.

Related

Type mismatch on moving method from companion object to a class

I'm new to Scala, so the answer might be obvious.
When going through FP in Scala FP in Scala I noticed that the unit method is placed on the companion object, but not the class, so I tried moving it to the class.
It resulted in an error which I don't understand, can someone explain it to me?
When you uncomment the unit method on the class and comment it out on the companion object it results in this error:
Why is that?
import State._
case class State[S, A](run: S => (A, S)) {
def map[B](f: A => B): State[S, B] =
flatMap(a => unit(f(a)))
def map2[B, C](sb: State[S, B])(f: (A, B) => C): State[S, C] =
flatMap(a => sb.map(b => f(a, b)))
def flatMap[B](f: A => State[S, B]): State[S, B] = State(s => {
val (a, s1) = run(s)
f(a).run(s1)
})
// This results in an error here:
// flatMap(a => unit(f(a))) ... Required A, found B
// def unit(a: A): State[S, A] = State(s => (a, s)) // ERROR
}
object State {
// Comment out when uncommenting above
def unit[S, A](a: A): State[S, A] = State(s => (a, s))
}
The error explains the problem, but here is the breakdown.
Start with map:
def map[B](f: A => B): State[S, B] =
flatMap(a => unit(f(a)))
Since f returns an unknown type B, this is calling unit with a value of type B. But unit is defined to take A, which is a type parameter of the case class:
def unit(a: A): State[S, A] = State(s => (a, s))
Since B might not be A, the compiler complains.
The code inside the companion object is different:
object State {
def unit[T, U](a: U): State[T, U] = State(s => (a, s))
}
I have re-named the type parameters to make it clear that they are now unrelated to the type parameters of the case class. And since the argument type of unit can be any type U it is OK to pass a value of type B to it.
To fix the definition of unit inside the case class, give it a type parameter:
case class State[S, A](run: S => (A, S)) {
// ...
def unit[T](a: T): State[S, T] = State(s => (a, s))
}

How to Remove Explicit Casting

How do I remove explicit casting asInstanceOf[XList[B]] in Cons(f(a), b).asInstanceOf[XList[B]] inside map function? Or perhaps redesign reduce and map functions altogether? Thanks
trait XList[+A]
case object Empty extends XList[Nothing]
case class Cons[A](x: A, xs: XList[A]) extends XList[A]
object XList {
def apply[A](as: A*):XList[A] = if (as.isEmpty) Empty else Cons(as.head, apply(as.tail: _*))
def empty[A]: XList[A] = Empty
}
def reduce[A, B](f: B => A => B)(b: B)(xs: XList[A]): B = xs match {
case Empty => b
case Cons(y, ys) => reduce(f)(f(b)(y))(ys)
}
def map[A, B](f: A => B)(xs: XList[A]): XList[B] = reduce((b: XList[B]) => (a: A) => Cons(f(a), b).asInstanceOf[XList[B]])(XList.empty[B])(xs)
You can merge two argument lists into one by replacing )( by ,:
def reduce[A, B](f: B => A => B, b: B)(xs: XList[A]): B = xs match {
case Empty => b
case Cons(y, ys) => reduce(f, f(b)(y))(ys)
}
def map[A, B](f: A => B)(xs: XList[A]): XList[B] =
reduce((b: XList[B]) => (a: A) => Cons(f(a), b), XList.empty[B])(xs)
This will force the type inference algorithm to consider both first arguments of reduce before making up its mind about what B is supposed to be.
You can either widen Cons to a XList[B] at the call site by providing the type parameters explicitly:
def map[A, B](f: A => B)(xs: XList[A]): XList[B] =
reduce[A, XList[B]]((b: XList[B]) => (a: A) => Cons(f(a), b))(XList.empty[B])(xs)
Or use type ascription:
def map[A, B](f: A => B)(xs: XList[A]): XList[B] =
reduce((b: XList[B]) => (a: A) => Cons(f(a), b): XList[B])(XList.empty[B])(xs)
As a side note, reduce is traditionally more strict at the method definition than what you've written. reduce usually looks like this:
def reduce[A](a0: A, a: A): A
Implicitly requiring a non empty collection to begin with. What you've implemented is similar in structure to a foldLeft, which has this structure (from Scalas collection library):
def foldLeft[B](z: B)(op: (B, A) => B): B

Implementing Monad.replicateM

Continuing on Functional Programming in Scala's exercises, I'm trying to implement:
def sequence[A](n: Int, ma: F[A]): F[List[A]]
Except for traverse, replicateOnce and replicateM, which I wrote, author is #pchiusano EDIT (spelled name incorrectly, sorry)
trait Monad[F[_]] extends Functor[F] {
def unit[A](a: => A): F[A]
def flatMap[A,B](ma: F[A])(f: A => F[B]): F[B]
def map[A,B](ma: F[A])(f: A => B): F[B] =
flatMap(ma)(a => unit(f(a)))
def map2[A, B, C](ma: F[A], mb: F[B])(f: (A,B) => C): F[C] =
flatMap(ma)(a => map(mb)(b => f(a, b)))
// Exercise 3: implement sequence() and traverse
// official answer from #pchiusano
def sequence[A](lma: List[F[A]]): F[List[A]] =
lma.foldRight(unit(List[A]()))((ma, mla) => map2(ma, mla)(_ :: _))
def traverse[A, B](la: List[A])(f: A => F[B]): F[List[B]] =
la.foldRight(unit(List[B]()))((ma, mla) => map2(f(ma), mla)(_ :: _))
def replicateOnce[A](ma: F[A]): F[List[A]] = {
map(ma)(x => List(x))
}
For replicateM, I'm getting a compile-time error, error: overloaded method value fill with alternatives.
// Exercise 4: implement replicateM
def replicateM[A](n: Int, ma: F[A]): F[List[A]] = {
sequence(List.fill(n, ma))
}
}
Please point me in the right direction as I'm a bit stuck.
You're calling List.fill incorrectly, it's a partially applied function so you need to first apply n and then ma:
def replicateM[A](n: Int, ma: F[A]): F[List[A]] = {
sequence(List.fill(n)(ma)) //note that the comma is removed
}

Scala flatmap signature definition

Maybe I don't understand some fundamentals, but what is the signature of flatMap in general? Let's imagine I'd like to implement type T supporting for expression, then I required map, flatmap and withFilter implemented by T. Is there any interface of something like that?
More precisely what is the source of the signature:
class T[+A] {
def flatMap[B](f: (A) => T[B]): T[B]
}
Or is it a definition? May I implement flatmap with different signature?
In general flatMap has signature:
class T[+A] {
def flatMap[B](f: (A) ⇒ T[B]): T[B]
def map[B](f: (A) ⇒ B): T[B]
}
For example for Option:
def flatMap[B](f: (A) ⇒ Option[B]): Option[B]
For Seq:
def flatMap[B](f: (A) ⇒ Seq[B]): Seq[B]
Of course in scala API you will see other signatures for Seq, List - because there is generic signature in trait TraversableLike for all collections.
For monad function map should:
m map f == m flatMap (x => unit(f(x)))
Where unit unit(x) = single(x), for example:
List is a monad with unit(x) = List(x)
Set is monad with unit(x) = Set(x)
Option is a monad with unit(x) = Some(x)
Update
There is no interface for flatMap/map. See example (copy to your REPL):
class C[+A](val a:A) {
def flatMap[B](f:(A) => C[B]):C[B] = f(a)
def map[B](f:(A)=>B):B = f(a)
}
Then call in REPL for method:
scala> for { k<- new C(3)} yield {k}
res2: Int = 3
No special interface needed.
But if so you can implement FilterMonadic[+A, +Repr] generic interface.
Update
SLS - 6.19 For Comprehensions and For Loops.
Methods: map, withFilter, flatMap, and foreach - can be implemented in different
ways for different carrier types. Code:
class A {
def map(f: Int => Boolean): Boolean = f(10)
def flatMap(f: Int => Boolean): Boolean = f(20)
}
for(x <- new A; y <- new A) yield x == y
And
class T[+A] {
def flatMap[B](f: (A) ⇒ T[B]): T[B]
}
is not single way to define flatMap method.

Type checker in trouble over #specialized

The trait below compiles fine without the #specialized annotations, or without the map method. Otherwise, it will fail with a compilation error, which doesn't make a lot of sense (at least to me):
[error] (compile:compile) scala.tools.nsc.symtab.Types$TypeError: type mismatch;
[error] found : U(in method foreach)(in method foreach)
[error] required: U(in method foreach)(in method foreach)
This is the trait that I'm talking about:
trait Tuple2Traversable[#specialized(Int, Byte) +A, #specialized(Int, Byte) +B] {
def foreach[T](fn: (A, B) => T)
def map[T](fn: (A, B) => T): Traversable[T] = new Traversable[T] {
def foreach[U](f: T => U) {
def composed(a: A, b: B) = f(fn(a, b))
Tuple2Traversable.this.foreach(composed)
}
}
def flatMap[T](fn: (A, B) => Traversable[T]): Traversable[T] = new Traversable[T] {
def foreach[U](f: (T) => U) {
def composed(a: A, b: B) = fn(a, b).foreach(f)
Tuple2Traversable.this.foreach(composed)
}
}
def filter(included: (A, B) => Boolean): Tuple2Traversable[A, B] = new Tuple2Traversable[A, B] {
def foreach[T](fn: (A, B) => T) {
def composed(a: A, b: B) = if (included(a, b)) fn(a, b)
Tuple2Traversable.this.foreach(composed)
}
}
def foldLeft[T](z: T)(fn: (T, A, B) => T): T = {
var current = z
def op(a: A, b: B) {
current = fn(current, a, b)
}
foreach(op)
current
}
def asTraversable = new Traversable[(A, B)] {
def foreach[U](f: ((A, B)) => U) {
def tupled(a: A, b: B) = f((a, b))
Tuple2Traversable.this.foreach(tupled)
}
}
}
I've been staring at this for a while now. Any suggestions on how to solve this would be highly appreciated.
Perhaps I should add that the purpose of this class is to have a Traversable of tuples, without forcing those tuples to ever be created. A Traversable[(A,B)] would accept a Tuple2[A,B] => T as the parameter of foreach. I want my 'traversable' to accept a function (A, B) => T. (Like def fn(a: Int, b: Int) = a + b.)
Looks like some internal compiler bug. I get the same error in scala 2.9.2, but it compiles fine in scala 2.10-RC2