1

Hi i am starsting to learn Scalaz.

I want to get a function and map over it with another function.

although i am able to write this:

import scalaz._, Scalaz._

import std.function._
import syntax.monad._

((x: Int) => x + 1) map {_ * 7}

and it works, when i use the explicit appraoch as per the examples in github project it does not work (see below)

import scalaz._, Scalaz._

import std.option._
import std.function._
import syntax.monad._

Functor[Function1[Int,Int]].map{x:Int => x * 4}{(x:Int) =>x * 7}

I get as error

Error:(10, 17) Function1 takes two type parameters, expected: one Functor[Function1].map{x:Int => x * 4}{(x:Int) =>x * 7}

I did inspired myself from an example in the doc that works

Functor[Option].map(Some("adsf"))(_.length)
MaatDeamon
  • 9,532
  • 9
  • 60
  • 127

2 Answers2

2

Expanding implicits of ((x: Int) => x * 4) map ((x: Int) => x * 7) we get

ToFunctorOps(((x: Int) => x * 4))(function1Covariant) map ((x: Int) => x * 7)

Signature of function1Covariant is

implicit def function1Covariant[T]: Monad[T => ?] with ...

whilst signature of Functor.apply is

def apply[F[_]](implicit F: Functor[F]): Functor[F] = F

Substituting F[_] with ({type F[B] = Int => B})#F, or using kind-projector with Int => ?, we make apply require implicit

Functor[Int => ?]

which is satisfied by function1Covariant[Int]: Monad[Int => ?] since Monad is a type of Functor. Thus we could write explicitly

Functor[({type F[B] = Int => B})#F].map((x: Int) => x * 4)((x: Int) => x * 7)

or using kind-projector as

Functor[Int => ?].map((x: Int) => x * 4)((x: Int) => x * 7)
Mario Galic
  • 47,285
  • 6
  • 56
  • 98
  • Thank you that make total sense. At the same time, I am trying to learn the scalaz library as in how it is structure and where is what in term of package and how to put the different pieces together to get what you want. So in a sense I want to understand the logic. How come my version that does not use Functor explicitly worked and not the one that used it explicitly ? Somehow Functor is of FunctionN is supporter but not the way one would expect, I wonder why ? Or is there something I am missing ? – MaatDeamon May 04 '19 at 08:02
  • The latest versions of Scala support partial unification of type constructors. So when you let the compiler infer the types it can infer something equivalent to `({type F[B] = Int => B})#F`. – Jasper-M May 04 '19 at 08:09
  • Got it. But then why is there not a typeclass for FunctionN like there is for Option which I get from std.option._, and what is std.function._ good for then ? – MaatDeamon May 04 '19 at 08:14
  • 1
    I think I was not completely accurate. The compiler can infer this even without partial unification. Anyway the point is that the type you provided explicitly was incorrect, but the compiler can infer the correct one, so that's why your first version worked. – Jasper-M May 04 '19 at 08:36
  • I think I have got the answer to my question after checking a bit stackoverflow and other. Please can you confirm that my understanding is right ? It is a scala limitation that makes it something that can not be generically baked in the library in advance. – MaatDeamon May 04 '19 at 10:49
0

I accepted the answer above because it solves the problem. It shows how to do what i wanted to do. Making a function a functor explicitly so as to map on it. However i was left a bit unsatisfied as to why i have to do this ({type F[B] = Int => B})#F for function ? why it can't be fully generic, why the library does not provide that out of the box, instead of having the user do it.

I believe I have found the answer in the following posts:

What are type lambdas in Scala and what are their benefits?

Why type lambdas?

Based on it I concluded that the library can not bake that for you whenever you do not have F[X] such as F[Int, INT] or Map[Int, INT]. One need to manually resort to Type lambdas which forces you to do something partial. Hence we can't have something generic baked in the library for FunctionX.

MaatDeamon
  • 9,532
  • 9
  • 60
  • 127