admin管理员组文章数量:1333168
So I tried to write an extension view to augment a PolyFunction:
object PolyFnExtension {
type Base[O] = Function1[Any, Any] {
def apply(x: Any): O
}
extension [O](base: Base[O]) {
def applyOption(x: Any): Option[O] = Some(base.apply(x))
}
val poly = { (x: Any) => x: x.type }
val poly2: [T] => (Seq[T] => Option[T]) = [T] => (x: Seq[T]) => x.headOption
@main def main(): Unit = {
println(Show.showType(poly))
println(Show.showType(poly2))
val r1: Option[Int] = poly.applyOption(1)
println(r1)
val r2: Option[String] = poly.applyOption("abc")
println(r2)
}
}
The extension apparently doesn't work:
> Task :core:compileScala
[Error] /home/peng/git/dottyspike/core/src/main/scala/com/tribbloids/spike/dotty/PolyFnExtension.scala:27:43: Found: Option[Any]
Required: Option[Int]
Explanation
===========
Tree: com.tribbloids.spike.dotty.PolyFnExtension.applyOption[Any](
com.tribbloids.spike.dotty.PolyFnExtension.poly)(1)
I tried to show that
Option[Any]
conforms to
Option[Int]
but none of the attempts shown below succeeded:
==> Option[Any] <: Option[Int] CachedAppliedType CachedAppliedType
==> Any <: Int CachedTypeRef CachedTypeRef = false
The tests were made under the empty constraint
[Error] /home/peng/git/dottyspike/core/src/main/scala/com/tribbloids/spike/dotty/PolyFnExtension.scala:30:46: Found: Option[Any]
Required: Option[String]
Explanation
===========
Tree: com.tribbloids.spike.dotty.PolyFnExtension.applyOption[Any](
com.tribbloids.spike.dotty.PolyFnExtension.poly)("abc")
I tried to show that
Option[Any]
conforms to
Option[String]
but none of the attempts shown below succeeded:
==> Option[Any] <: Option[String] CachedAppliedType CachedAppliedType
==> Any <: String CachedTypeRef CachedTypeRef = false
The tests were made under the empty constraint
two errors found
What's the proper extension in this case?
UPDATE 1: I forgot to add the goal of this question, so here it is:
{
val poly = { (x: Any) => x: x.type }
val r1: Option[Int] = poly.applyOption(1)
}
{
val poly = { (x: Any) => Seq(x: x.type) }
val r1: Option[Seq[Int]] = poly.applyOption(1)
}
It should be noted that we don't know what kind of dependent/poly function will be provided, but the 1 extension should work on all of them
So I tried to write an extension view to augment a PolyFunction:
object PolyFnExtension {
type Base[O] = Function1[Any, Any] {
def apply(x: Any): O
}
extension [O](base: Base[O]) {
def applyOption(x: Any): Option[O] = Some(base.apply(x))
}
val poly = { (x: Any) => x: x.type }
val poly2: [T] => (Seq[T] => Option[T]) = [T] => (x: Seq[T]) => x.headOption
@main def main(): Unit = {
println(Show.showType(poly))
println(Show.showType(poly2))
val r1: Option[Int] = poly.applyOption(1)
println(r1)
val r2: Option[String] = poly.applyOption("abc")
println(r2)
}
}
The extension apparently doesn't work:
> Task :core:compileScala
[Error] /home/peng/git/dottyspike/core/src/main/scala/com/tribbloids/spike/dotty/PolyFnExtension.scala:27:43: Found: Option[Any]
Required: Option[Int]
Explanation
===========
Tree: com.tribbloids.spike.dotty.PolyFnExtension.applyOption[Any](
com.tribbloids.spike.dotty.PolyFnExtension.poly)(1)
I tried to show that
Option[Any]
conforms to
Option[Int]
but none of the attempts shown below succeeded:
==> Option[Any] <: Option[Int] CachedAppliedType CachedAppliedType
==> Any <: Int CachedTypeRef CachedTypeRef = false
The tests were made under the empty constraint
[Error] /home/peng/git/dottyspike/core/src/main/scala/com/tribbloids/spike/dotty/PolyFnExtension.scala:30:46: Found: Option[Any]
Required: Option[String]
Explanation
===========
Tree: com.tribbloids.spike.dotty.PolyFnExtension.applyOption[Any](
com.tribbloids.spike.dotty.PolyFnExtension.poly)("abc")
I tried to show that
Option[Any]
conforms to
Option[String]
but none of the attempts shown below succeeded:
==> Option[Any] <: Option[String] CachedAppliedType CachedAppliedType
==> Any <: String CachedTypeRef CachedTypeRef = false
The tests were made under the empty constraint
two errors found
What's the proper extension in this case?
UPDATE 1: I forgot to add the goal of this question, so here it is:
{
val poly = { (x: Any) => x: x.type }
val r1: Option[Int] = poly.applyOption(1)
}
{
val poly = { (x: Any) => Seq(x: x.type) }
val r1: Option[Seq[Int]] = poly.applyOption(1)
}
It should be noted that we don't know what kind of dependent/poly function will be provided, but the 1 extension should work on all of them
Share Improve this question edited Nov 29, 2024 at 20:31 tribbloid asked Nov 28, 2024 at 3:56 tribbloidtribbloid 3,76415 gold badges70 silver badges116 bronze badges1 Answer
Reset to default 2First of all, we need to understand how polymorphic functions work in Scala and how they look like when decompiled:
As follows, you can see a monomorphic function and its decompiled code:
// scala
def monoFn(x: Int): Option[Int] = Some(x)
As we can see, Scala lifts the int
type into Integer
Object via .boxToInteger
static function.
// java
public Option<Object> monoFn(int x) {
return (Option<Object>)Some$.MODULE$.apply(BoxesRunTime.boxToInteger(x));
}
Lets write a polymorphic function and look at its decompiled code:
// scala
def polyFn[T](x: T): Option[T] = Some(x)
At this time, our function doesn't take its argument as primitive type, but as Object type.
// java
public <T> Option<T> polyFn(Object x) {
return (Option<T>)Some$.MODULE$.apply(x);
}
When we call the polyFn
, Scala converts the parameters into Object
types in runtime. (e.g., int
to Integer
)
// scala
val pfn: Option[Int] = polyFn(1)
val pfn2: Option[String] = polyFn("hello world")
// java
Option<Integer> pfn = polyFn(BoxesRunTime.boxToInteger(1));
Option<String> pfn2 = polyFn("hello world");
Lets write an extension method and observe how decompiled:
// scala
extension [T](t: T) {
def some: Option[T] = Some(t)
}
@main def main4(): Unit = {
val intSome = 1.some
val strSome = "hello world".some
}
As we can see, there is no exaggerated implementation in compiled the extension method:
// java
public <T> Option<T> some(Object t) {
return (Option<T>)Some$.MODULE$.apply(t);
}
public void main4() {
Option<Integer> intSome = some(BoxesRunTime.boxToInteger(1));
Option<String> strSome = some("hello world");
}
Okay lets back on your case. First we need to look what error we got:
[error] -- [E007] Type Mismatch Error: /home/csgn/Playground/stackof/src/main/scala/Main.scala:15:42
[error] 15 | val r1: Option[Int] = poly.applyOption(1)
[error] | ^^^^^^^^^^^^^^^^^^^
[error] | Found: Option[Any]
[error] | Required: Option[Int]
[error] |----------------------------------------------------------------------------
[error] | Explanation (enabled by `-explain`)
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |
[error] | Tree: PolyFnExtension.applyOption[Any](PolyFnExtension.poly)(1)
[error] | I tried to show that
[error] | Option[Any]
[error] | conforms to
[error] | Option[Int]
[error] | but none of the attempts shown below succeeded:
[error] |
[error] | ==> Option[Any] <: Option[Int]
[error] | ==> Any <: Int = false
[error] |
[error] | The tests were made under the empty constraint
So basically, Scala says, you can't directly assign to Option[Int]
because
the compiler cannot guarantee that the value is an Int
. Since, Option[Any]
can contain any type.
And also we know that the function (i.e., polly
) is the determiner of the return type of the variable.
As follows, you can see polly
returns Any
type not its parameter type.
// java
public <O> Option<O> applyOption(Function1 base, Object x) {
return (Option<O>)Some$.MODULE$.apply(base.apply(x));
}
static {
poly = (x -> x); // as you can see, there is no type indicated which means it will return any type.
}
public Function1<Object, Object> poly() {
return poly;
}
// and also look, we passing lambda function (i.e., polly) as it is, there is no type explicitly indicated.
Option<?> r1 = applyOption(poly(), BoxesRunTime.boxToInteger(1));
In the light of the decompiled code, we know that the poly.applyOption
does not works the way we want it to.
// scala
scala> :type poly.applyOption(1)
Any
scala> :type poly.applyOption("hello world")
Any
If we want the polly.applyOption
's result as its own parameter type then we can implement as follows:
// scala
object PolyFnExtensionFixed {
type Base[T] = Function1[Any, Any] {
def apply(x: Any): T
}
extension [T](base: Base[T]) {
def applyOption[R](x: R): Option[R] = Some(
~~~~^
base.apply(x).asInstanceOf[R]
)
}
}
From now on, return type can determined by applyOption
.
// scala
scala> :type poly.applyOption(1)
Option[Int]
scala> :type poly.applyOption("hello world")
Option[String]
You can see on decompiled code, base.apply(x)
determines the R
which is result type.
// java
public <T> Option<R> applyOption(Function1 base, Object x) {
return (Option<R>)Some$.MODULE$.apply(base.apply(x));
}
static {
poly = (x -> x);
poly2 = (x -> x.headOption());
}
public Function1<Object, Object> poly() {
return poly;
}
public Function1 poly2() {
return poly2;
}
public void main2() {
Option r1 = applyOption(poly(), (Function1)BoxesRunTime.boxToInteger(1));
Predef$.MODULE$.println(r1);
Option r2 = applyOption(poly(), (Function1)"abc");
Predef$.MODULE$.println(r2);
}
I hope this is what you want.
本文标签: In Scala 3how to write extension for a dependent or polymorphic functionStack Overflow
版权声明:本文标题:In Scala 3, how to write extension for a dependent or polymorphic function? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736220395a1913610.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论