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))
}
I have these types:
SomeTypeClass
A higher kinded type which has one type parameter of kind * => * => *
trait SomeTypeClass[P[_, _]] {
def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: P[A, B])
(implicit ev: Strong[P],
ev2: Choice[P],
ev3: Applicative[F]): P[S, T]
}
Target which accepts three type parameters: type constructor F[_] and two polymorphic types A, B
case class Target[F[_], A, B](f: A => F[B])
I want to implement an instance of SomeTypeClass of Target.
I am using the kind-projector plugin in order to create a partially applied type.
My desired method signature should be:
implicit def instance: SomeTypeClass[Target[F, *, *]] = new SomeTypeClass[Target[F, *, *]] {
override def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: Target[F, A, B])
(implicit ev: Strong[Target[F, *, *]],
ev2: Choice[Target[F, *, *]],
ev3: Applicative[F]): Target[F, S, T] = ???
}
I've tried using this syntax using two star parameters:
implicit def instance[F[_]]: SomeTypeClass[Target[F, *, *]] = new SomeTypeClass[Target[F, *, *]] {
override def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: Target[F, A, B])
(implicit ev: Strong[Target[F, *, *]],
ev2: Choice[Target[F, *, *]],
ev3: Applicative[F]): Target[F, S, T] = ???
}
But the F[_] declared at the instance level shadows the F[_] declared at the test method (I want them to be the same F), so I've moved to the λ syntax and got two different unwanted results.
The first one using λ[(F, A, B) => Target[F, A, B]] generated for the pab paramter,
pab: Target[A, B, B] instead of pab: Target[F, A, B] and also for the return type Target[S, T, B] instead of Target[F, S, T]
The second one using the F at the end of the triple type lambda parameters (why???) λ[(A, B, F) => Target[F, A, B]] generated the correct types for the pab parameter and the return type, but
for each one of the implicit parameters the type Strong[λ[(A, B, F) => Target[F, A, B]]] instead of
Strong[Target[F, *, *]]]
The full code:
import cats.Applicative
import cats.arrow.{Choice, Strong}
final case class Target[F[_], A, B](f: A => F[B])
trait SomeTypeClass[P[_, _]] {
def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: P[A, B])
(implicit ev: Strong[P],
ev2: Choice[P],
ev3: Applicative[F]): P[S, T]
}
object SomeTypeClass {
implicit def instance1: SomeTypeClass[λ[(F, A, B) => Target[F, A, B]]] = new SomeTypeClass[λ[(F, A, B) => Target[F, A, B]]] {
override def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: Target[A, B, B])
(implicit ev: Strong[Target],
ev2: Choice[Target],
ev3: Applicative[F]): Target[S, T, B] = ???
}
implicit def instance2: SomeTypeClass[λ[(A, B, F) => Target[F, A, B]]] = new SomeTypeClass[λ[(A, B, F) => Target[F, A, B]]] {
override def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: Target[F, A, B])
(implicit ev: Strong[λ[(A, B, F) => Target[F, A, B]]],
ev2: Choice[λ[(A, B, F) => Target[F, A, B]]],
ev3: Applicative[F]): Target[F, S, T] = ???
}
}
Can I achieve the desired syntax using this plugin? Why does the plugin generate different types
for different order of type lambda's 'parameters'?
If I understood
But the F[_] declared at the instance level shadows the F[_] declared at the test method (I want them to be the same F)
correctly, you want your instance for SomeTypeClass[Target[...]] to fix the F[_] parameter of test. But that's simply not possible with this test type signature. Once you have (for example)
val inst = implicitly[SomeTypeClass[Target[...]]
you can call
val res1 = inst.test[List, ...]
val res2 = inst.test[Option, ...]
Type lambdas don't offer a way around this problem. You need to either move F[_] parameter to SomeTypeClass or implement
implicit def instance[F[_]]: SomeTypeClass[Target[F, *, *]] = new SomeTypeClass[Target[F, *, *]] {
override def test[G[_], S, T, A, B](f: (A => G[B]) => S => G[T])
(pab: Target[F, A, B])
(implicit ev: Strong[Target[F, *, *]],
ev2: Choice[Target[F, *, *]],
ev3: Applicative[G]): Target[G, S, T] = ???
}
which I expect is impossible as you can't pass pab.f to f.
EDIT: the type of wander
class (Choice p, Strong p) => Traversing p where
traverse' :: Traversable f => p a b -> p (f a) (f b)
traverse' = wander traverse
wander :: (forall f. Applicative f => (a -> f b) -> s -> f t) -> p a b -> p s t
wander f pab = dimap (\s -> Baz $ \afb -> f afb s) sold (traverse' pab)
is a rank-2 type which aren't supported in Scala directly; instead you need to introduce a helper (which can't just be a type alias as it is in Control.Lens.Type)
trait Traversal[S, T, A, B] {
def apply[F[_]: Applicative](f: A => F[B]): S => F[T]
}
Then
trait Traversing[P[_, _]] extends Strong[P] with Choice[P] {
def wander[S, T, A, B](t: Traversal[S, T, A, B], pab: P[A, B]): P[S, T]
}
implicit def instance[F[_]: Applicative]: Traversing[Target[F, *, *]] = new Traversing[Target[F, *, *]] {
def wander[S, T, A, B](t: Traversal[S, T, A, B], pab: Target[F, A, B]): Target[F, S, T] = Target(t(pab.f))
// define Strong and Choice methods too
}
should work. (Though I am not sure this is the cats way to deal with Strong and Choice requirements.)
For learning purposes, I am trying to define a wrapper class called DoubleMap which provides the method mapBoth. It essentially takes two functions f and g, where the domain of g is the co-domain of f. The composition of this function (g o f) should then be mapped of the container wrapped by DoubleMap
This is my current code:
implicit class DoubleMap
[A, B, C, F[X] <: List[X]] // just List for now
(xs: F[A])(implicit cbf: CanBuildFrom[F[A], C, F[C]]) {
def mapBoth(f: A => B)(g: B => C): F[C] =
xs.map(f andThen g).to[F]
}
However, when I want to use the method like this:
List(true, false, false).mapBoth(!_)(!_)
I get a cryptical error message about the type mismatch between the (found) type CanBuildFrom[List[_], Nothing, List[Nothing]] and the (required) type CanBuildFrom[List[Boolean], C, List[C]]
Why does the compiler infer the first type?
Your call expands to
DoubleMap(xs).mapBoth(!_)(!_)
so all of DoubleMap's type parameters and cbf need to be inferred before the mapBoth call is handled. To fix it, just move these parameters to mapBoth:
implicit class DoubleMap
[A, F[X] <: List[X]] // just List for now
(xs: F[A]) {
def mapBoth[B, C](f: A => B)(g: B => C)(implicit cbf: CanBuildFrom[F[A], C, F[C]]): F[C] =
xs.map(f andThen g).to[F]
}
Then B and C are determined from f and g, and cbf from F, A and C.
If you wish to not be tied to List, consider Functor from Cats
implicit class DoubleMap[F[_]: Functor, A](xs: F[A]) {
def mapBoth[B, C](f: A => B)(g: B => C): F[C] =
xs.map(f andThen g)
}
or vanilla Scala 2.13 approach (inspired by Luis' 2.12 implementation)
implicit class DoubleMap[F[x] <: IterableOnce[x], A](xs: F[A]) {
def mapBoth[B, C](f: A => B)(g: B => C)(implicit bf: BuildFrom[F[A], C, F[C]]): F[C] =
bf.fromSpecific(xs)(xs.iterator.map(f andThen g))
}
which both output
List(true, false, false).mapBoth(!_)(!_)
Vector(true, false, false).mapBoth(!_)(!_)
res1: List[Boolean] = List(true, false, false)
res2: Vector[Boolean] = Vector(true, false, false)
I have a trait that is extended by multiple subclasses
trait Sup
case class Sub[A, B](a: A, f: B => B)(implicit val ev: A =:= B) extends Sup
case class Sub2[A, B](a: A, f: B => Unit)(implicit val ev: A =:= B) extends Sup
And two functions:
def foo[A, B](a: A, f: B => B)(implicit ev: A =:= B) = f(a)
def bar[A, B](a: A, f: B => Unit)(implicit ev: A =:= B) = f(a)
Now I can do some form of dynamic dispatching and call foo if the object is a Sub and bar if the object is a Sub2.
def dispatch(obj: Sup) = {
obj match {
case Sub(a, f) => foo(a, f)
case Sub2(a, f) => bar(a, f) // type mismatch: found: Nothing => Unit. required: B => Unit
}
}
I've also tried to pass the evidence explicitly but it results in the same error:
case o # Sub2(a, f) => bar(a, f)(o.ev) // type mismatch
It is very weird that f: B => B works (I can call foo), but f: B => Unit doesn't work (I can't call bar).
Not an answer but something to think about:
case class Sub1[A, B](a: A, f: B => B)
case class Sub2[A, B](a: A, f: B => Unit)
def foo[A, B](a: A, f: B => B)(implicit ev: A =:= B) = f(a)
def bar[A, B](a: A, f: B => Unit)(implicit ev: A =:= B) = f(a)
def dispatch(obj: Any) = obj match {
case Sub1(a, f) => foo(a, f)
case Sub2(a, f) => bar(a, f) // type mismatch: found: Nothing => Unit. required: B => Unit
}
This code have the same problem as yours but Sub1 and Sub2 case classes don't even have implicit blocks.
implicit section in case class doesn't effect pattern resolution. This section is just syntax sugar for calling apply(a: A, f: B => B)(implicit val ev: A =:= B) method on Sub1/2's companion objects. Pattern matching use unapply method to match the pattern at runtime and this unapply don't even know about evidences.
But I'm still wondering why first case is compiled without having this evidence.
Edit: Adding helpful comment from #AlexeyRomanov
More type inference than type erasure. But yes, the compiler infers type Any for a and Any => Any for f and then produces and uses evidence that Any =:= Any. In the second case it infers Nothing => Unit for f, because B => Unit is contravariant in B, and fails to find Any =:= Nothing.
You can actually make it work using type variable patterns:
def dispatch(obj: Sup) = {
obj match {
case obj: Sub[a, b] => foo(obj.a, obj.f)(obj.ev)
case obj: Sub2[a, b] => bar(obj.a, obj.f)(obj.ev)
}
}
This part is an answer to the comments, because it doesn't really fit in there:
Btw, there is still one subtlety I do not get: why is B => Unit contravariant in B
what is compiler's logic for this Nothing => Unit inference staff
You need to start with function variance. X => Y is a subtype of X1 => Y1 if and only if X is a supertype of X1 and Y is a subtype of Y1. We say it's contravariant in X and covariant in Y.
So if you fix Y = Unit, what remains is just contravariant in X. Any => Unit is a subtype of String => Unit, which is a subtype of Nothing => Unit. In fact, Nothing => Unit is the most general of all B => Unit, and that's why it gets inferred in the Sub2 case.
and B => B not (since it infers Any => Any) ?
The situation with B => B is different: String => String is neither a subtype nor a supertype of Any => Any, or of Nothing => Nothing. That is, B => B is invariant. So there is no principled reason to infer any specific B, and in this case the compiler uses the upper bound for B (Any), and B => B becomes Any => Any.
Does there exist a utility in Scala or Scalaz to transform a container/collection of functions to a function that maps from the same input to a collection output values? The signature would look something like
def transform[M[_], A, B](m: M[A => B]): A => M[B] = ???
Here's an example implementation for the List container:
def transform[A, B](fs: List[A => B]): A => List[B] = x =>
fs.foldRight[List[B]](Nil) {
(f, acc) => f(x) :: acc
}
Ideally, this would work for any function container, including a tuple of functions, an Option[Function1[A, B]], or even a TupleN[Option[Function1[A, B]], ...].
EDIT:
I've just realized that (at least for the special case of a List) the map function works:
def transform[A, B](fs: List[A => B]): A => List[B] = x => fs map (_(x))
This can generalize to anything that has a map function with the appropriate semantics. What's the appropriate type class for this?
Assuming M is a Functor, mapply in scalaz's Functor has a similar type signature:
def mapply[A, B](a: A)(f: F[A => B]): F[B] = map(f)((ff: A => B) => ff(a))
So you could write transform in terms of that:
def transform[M[_],A,B](m: M[A => B])(implicit f:Functor[M]):A => M[B] = f.mapply(_)(m)
Edit: Another implementation using features from FunctorSyntax:
def transform[M[_]:Functor,A,B](m: M[A => B]):A => M[B] = _.mapply(m)
I searched through the Scalaz source code and it looks like Functor does the trick:
def transform[M[_]: Functor, A, B](fs: M[A => B]): A => M[B] = a => fs map (_(a))