Scala Kleisli在IntelliJ中引发错误 [英] Scala Kleisli throws an error in IntelliJ

查看:59
本文介绍了Scala Kleisli在IntelliJ中引发错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

试图在Scala中为虚构的Partial类型实现Kleisli类别(请阅读Bartosz Milewski的程序员的类别理论",该知识将在第4章中进行扩展)

trying to implement Kleisli category for a made-up Partial type in Scala (reading Bartosz Milewski's "category theory for programmers", that's exersize for chapter 4)

object Kleisli {
  type Partial[A, B] = A => Option[B]

  implicit class KleisliOps[A, B](f1: Partial[A, B]) {

    def >=>[C](f2: Partial[B, C]): Partial[A, C] =
      (x: A) =>
        for {
          y <- f1(x)
          z <- f2(y)
        } yield z

    def identity(f: Partial[A, B]): Partial[A, B] = x => f(x)

  }

  val safeRecip: Partial[Double, Double] = {
    case 0d => None
    case x => Some(1d / x)
  }

  val safeRoot: Partial[Double, Double] = {
    case x if x < 0 => None
    case x => Some(Math.sqrt(x))
  }
  
  val safeRootRecip: Partial[Double, Double] = safeRoot.>=>(safeRecip) 
  
  safeRootRecip(1d)
  safeRootRecip(10d)
  safeRootRecip(0d)
}

IDE(IntelliJ)没有显示任何错误,但是运行此代码段时,我得到了:

IDE (IntelliJ) shows no errors, but when I run this snippet, I get:

Error:(27, 57) value >=> is not a member of $line5.$read.$iw.$iw.Kleisli.Partial[Double,Double]
val safeRootRecip: Partial[Double, Double] = safeRoot.>=>(safeRecip)

在隐式类之外定义> => 可以正常工作.可能是什么原因?

Defining >=> outside of implicit class works fine. What could be the reason?

推荐答案

@sinanspd 是正确的.在Dotty中,代码似乎可以编译: https://scastie.scala-lang.org/n17APWgMQkWqy93ct2cghw

@sinanspd was right. In Dotty the code seems to compile: https://scastie.scala-lang.org/n17APWgMQkWqy93ct2cghw

手动解决

val safeRootRecip: Partial[Double, Double] = KleisliOps(safeRoot).>=>(safeRecip)

可以编译,但编译器本身找不到此转换

compiles but compiler doesn't find this conversion itself

Information: KleisliOps{<null>} is not a valid implicit value 
  for App.safeRoot.type => ?{def >=> : ?} because:
type mismatch;
 found   : App.safeRoot.type (with underlying type App.Partial[Double,Double])
 required: App.Partial[A,Double]
    (which expands to)  A => Option[Double]
  val safeRootRecip: Partial[Double, Double] = safeRoot.>=>(safeRecip)

似乎没有推断出类型参数 A .

It seems type parameter A is not inferred.

(顺便说一句,马丁·奥德斯基(Martin Odersky)在这里解释了为什么语言中隐式转换的存在使类型推断变得更糟:-off-implicit-conversions/4388"rel =" nofollow noreferrer> https://contributors.scala-lang.org/t/can-we-wean-scala-off-implicit-conversions/4388 )

(By the way, here Martin Odersky explains why presence of implicit conversions in language makes type inference worse: https://contributors.scala-lang.org/t/can-we-wean-scala-off-implicit-conversions/4388)

尝试使 Partial B 协变,并且(尤其)与 A 协变(类似于 A => Option [B] 关于 B 是协变的,而关于 A 则是协变的)

Try to make Partial covariant with respect to B and (especially) contravariant with respect to A (similarly to A => Option[B] being covariant with respect to B and contravariant with respect to A)

type Partial[-A, +B] = A => Option[B]

然后代码似乎可以编译.

Then the code seems to compile.

另一种解决方法是用类型类( MyTransform )和隐式转换替换隐式转换( X => Y KleisliOps )( myConversion )根据此类类型定义(

Another workaround is to replace implicit conversions (X => Y, KleisliOps) with a type class (MyTransform) and implicit conversion (myConversion) defined in terms of this type class (sometimes this helps with implicit conversions)

trait MyTransform[X, Y] {
  def transform(x: X): Y
}
implicit def myConversion[X, Y](x: X)(implicit mt: MyTransform[X, Y]): Y = 
  mt.transform(x)

type Partial[A, B] = A => Option[B]

implicit def partialToKleisliOps[A, B]: MyTransform[Partial[A, B], KleisliOps[A, B]] = 
  f1 => new KleisliOps(f1)
class KleisliOps[A, B](f1: Partial[A, B]) {    
  def >=>[C](f2: Partial[B, C]): Partial[A, C] =
    (x: A) =>
      for {
        y <- f1(x)
        z <- f2(y)
      } yield z

  def identity(f: Partial[A, B]): Partial[A, B] = x => f(x)
}

这篇关于Scala Kleisli在IntelliJ中引发错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆