Understanding implcit conversions - why aren't =:= and :> doing anything

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Understanding implcit conversions - why aren't =:= and :> doing anything

Hugo Ferreira
Hello,

I have experimenting with implicit conversions and seem to
have a fundamental misunderstanding regarding type inference.
Consider the following:

    implicit def duplicate0[ X ]( hc: Stream[ X ] ): Stream[ _ ] = {
      val crss = hc.flatMap { x: X => List( x, x ) }
      crss
    }

This compiles. Now what if I want to pass anything that has s flatMap
and not just a stream? So I tried:

    implicit def duplicate1[ X, H[ _ ] ]( hc: H[ X ] ): Stream[ X ] = {
      val crss = hc.flatMap { x: X => List( x, x ) }
      crss
    }

That compiles too but... hc is inferred to have the type Stream!?
So how about having any sequence as an input (they have flatMap).

    implicit def duplicate1[ X, H[ _ ] <: scala.collection.AbstractSeq[X] ]( hc: H[ X ] ): Stream[ X ] = {
      val crss = hc.toStream.flatMap { x: X => List( x, x ) }
      crss
    }

To get a Stream as an output, we have to convert the sequence to a stream.
That is doable, so no problem. So hc is a Sequence. Ok.

Now here is my issue - what if we want to have the output type the same as the input?
So I tried:

    implicit def duplicate1[ X, H[ _ ] <: scala.collection.AbstractSeq[X] ]( hc: H[ X ] ): H[ X ] = {
      val crss = hc.flatMap { x: X => List( x, x ) }
      crss
    }

But this fails saying "found crss.type (with underlying type Seq[X])
but  required: H[X]". So why does the compiler not simply infer that
H[X] is an AbstractSeq? Is it because it needs a concrete implementation?
Trying a List won't work either.

I also tried:

    implicit def duplicate2[ X, H[ _ ] ]( hc: H[ X ] )(implicit ev: H[X] =:= Stream[X]): H[ X ] = {
      val crss = hc.flatMap { x: X => List( x, x ) }
      crss
    }

and the type "=:=" also does not ensure that, for example, the output be a Stream.
We get he same kind of error as in the previous case. So why is this so?

Lets see a working example again:

    import scala.language.higherKinds
    implicit def duplicate3[ X, H[ _ ] >: Stream[ _ ] ]( hc: H[ X ] ) : Seq[X]= {
      val crss = hc.flatMap { x: X => List(x,x) }
      crss
    }

This compiles fine. Now I assumed that >: allowed the compiler to know
that H[_] is  a Stream, so flatMap is available. But the again, so is it available
in Seq. However the type of crss is not Stream but Seq. So it seems like the output
type is used to determine the input type and the "=:=" and ">:" have no effect
(<: wont work, to may compatible overload functions). Am I wrong?

And finally a contrived example (my actual case study): lets assume that we just want to
ensure the input type be of a given type, but it wont be used for the output. So we have:

    import scala.language.higherKinds
    // Must use >:, if <: then error: overloaded method value flatMap with alternatives
    implicit def duplicate3[ X, H[ _ ] >: Stream[ _ ] ]( hc: H[ X ] ) : Int = {
      def doMore(h : H[X]) : Stream[X] = {
        val crss = h.flatMap { x: X => List(x,x) }
        crss
      }
      doMore(hc)
      1
    }

Now why does this not work (value flatMap is not a member of type parameter H[X]) and
in the previous case does? The constraints on H[X] are the same, correct?

I would appreciate any pointers.

TIA,
Hugo F.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Understanding implcit conversions - why aren't =:= and :> doing anything

joe.pallas


On Friday, January 27, 2017 at 5:22:35 AM UTC-8, Hugo Ferreira wrote:
Hello,

I have experimenting with implicit conversions and seem to
have a fundamental misunderstanding regarding type inference.
Consider the following:

    implicit def duplicate0[ X ]( hc: Stream[ X ] ): Stream[ _ ] = {
      val crss = hc.flatMap { x: X => List( x, x ) }
      crss
    }

This compiles. Now what if I want to pass anything that has s flatMap
and not just a stream? So I tried:

    implicit def duplicate1[ X, H[ _ ] ]( hc: H[ X ] ): Stream[ X ] = {
      val crss = hc.flatMap { x: X => List( x, x ) }
      crss
    }

That compiles too but... hc is inferred to have the type Stream!?

I think you ran off the rails at this point, and everything following is going down a misleading path.  hc was not inferred to have type Stream.  What actually happened is that the implicit conversion defined by duplicate1 was implicitly applied recursively to convert hc to a Stream.

You can see this if you desugar the definition:

@ desugar {

  implicit def duplicate1[ X, H[ _ ] ]( hc: H[ X ] ): Stream[ X ] = {

        val crss = hc.flatMap { x: X => List( x, x ) }

        crss

      }

  } 

res0: Desugared = {

  implicit def duplicate1[X, H[_]](hc: H[X]): scala.`package`.Stream[X] = {

    val crss = duplicate1[X, H](hc).flatMap[X, scala.collection.immutable.Stream[X]](((x: X) => scala.collection.immutable.List.apply[X](x, x)))(scala.collection.immutable.Stream.canBuildFrom[X]);

    crss

  };

  ()

}


Actually invoking it will simply result in a stack overflow due to unbounded recursion.

Having an implicit conversion be available in the body of the definition of the method itself is probably perfectly logical and consistent, but it seems like a disaster waiting to trip the unwary.

joe

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Understanding implcit conversions - why aren't =:= and :> doing anything

Hugo Ferreira
Hi Joe,


On Friday, 27 January 2017 18:19:52 UTC, [hidden email] wrote:


On Friday, January 27, 2017 at 5:22:35 AM UTC-8, Hugo Ferreira wrote:
Hello,

I have experimenting with implicit conversions and seem to
have a fundamental misunderstanding regarding type inference.
Consider the following:

    implicit def duplicate0[ X ]( hc: Stream[ X ] ): Stream[ _ ] = {
      val crss = hc.flatMap { x: X => List( x, x ) }
      crss
    }

This compiles. Now what if I want to pass anything that has s flatMap
and not just a stream? So I tried:

    implicit def duplicate1[ X, H[ _ ] ]( hc: H[ X ] ): Stream[ X ] = {
      val crss = hc.flatMap { x: X => List( x, x ) }
      crss
    }

That compiles too but... hc is inferred to have the type Stream!?

I think you ran off the rails at this point, and everything following is going down a misleading path.  

Ran "off the rails"? I crashed and burned 8-}
 
hc was not inferred to have type Stream.  What actually happened is that the implicit conversion defined by duplicate1 was implicitly applied recursively to convert hc to a Stream.


Ok, from the code below this is obvious.
 
You can see this if you desugar the definition:

@ desugar {

  implicit def duplicate1[ X, H[ _ ] ]( hc: H[ X ] ): Stream[ X ] = {

        val crss = hc.flatMap { x: X => List( x, x ) }

        crss

      }

  } 

res0: Desugared = {

  implicit def duplicate1[X, H[_]](hc: H[X]): scala.`package`.Stream[X] = {

    val crss = duplicate1[X, H](hc).flatMap[X, scala.collection.immutable.Stream[X]](((x: X) => scala.collection.immutable.List.apply[X](x, x)))(scala.collection.immutable.Stream.canBuildFrom[X]);

    crss

  };

  ()

}



This is interesting. I have looked around an found a "desugar" macro and a way to invoke the compiler. I guess  you are using a macro. 
 
Actually invoking it will simply result in a stack overflow due to unbounded recursion.

Having an implicit conversion be available in the body of the definition of the method itself is probably perfectly logical and consistent, but it seems like a disaster waiting to trip the unwary.

Unintended.  Back to the drawing board then.

Thanks.


joe

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Understanding implcit conversions - why aren't =:= and :> doing anything

Joe Pallas
On Jan 28, 2017, at 7:31 AM, Hugo Ferreira <[hidden email]> wrote:

This is interesting. I have looked around an found a "desugar" macro and a way to invoke the compiler. I guess  you are using a macro. 

I used the Ammonite REPL http://www.lihaoyi.com/Ammonite/#Ammonite-REPL, which has desugar built in, and a few other handy things not in the standard Scala interpreter.

Joe

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Understanding implcit conversions - why aren't =:= and :> doing anything

Hugo Ferreira

Thanks for the info. Will have to look into it (already seen the video presentation).


On Sunday, 29 January 2017 01:54:18 UTC, Joe Pallas wrote:
On Jan 28, 2017, at 7:31 AM, Hugo Ferreira <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="174oc8YDBQAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">hugo6f...@...> wrote:

This is interesting. I have looked around an found a "desugar" macro and a way to invoke the compiler. I guess  you are using a macro. 

I used the Ammonite REPL <a href="http://www.lihaoyi.com/Ammonite/#Ammonite-REPL" target="_blank" rel="nofollow" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.lihaoyi.com%2FAmmonite%2F%23Ammonite-REPL\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFiU1kvMA3KFhINnFaflkkINwltDg&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.lihaoyi.com%2FAmmonite%2F%23Ammonite-REPL\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFiU1kvMA3KFhINnFaflkkINwltDg&#39;;return true;">http://www.lihaoyi.com/Ammonite/#Ammonite-REPL, which has desugar built in, and a few other handy things not in the standard Scala interpreter.

Joe

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.