Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/facebook/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 如何将返回的函数与诸如`和`之类的运算符进行一般性的链式连接?_Scala - Fatal编程技术网

Scala 如何将返回的函数与诸如`和`之类的运算符进行一般性的链式连接?

Scala 如何将返回的函数与诸如`和`之类的运算符进行一般性的链式连接?,scala,Scala,问题:链接多个返回函数,其中左侧的都是从一个公共密封特征内部错误继承的失败。但是,编译器抱怨链返回的是或[\uu,成功],而不是或[InternalError,Success] 以下是进行链接的代码: import scala.language.implicitConversions object EitherExtension { implicit class AndThenEither[A,B](val e: Function1[A,Either[_,B]]) { //get a

问题:链接多个返回函数,其中
左侧的
都是从一个公共密封特征
内部错误继承的失败。但是,编译器抱怨链返回的是
或[\uu,成功]
,而不是
或[InternalError,Success]

以下是进行链接的代码:

import scala.language.implicitConversions
object EitherExtension {
  implicit class AndThenEither[A,B](val e: Function1[A,Either[_,B]]) {
    //get ability to chain/compose functions that return aligning Eithers
    def andThenE[C](f:Function1[B, Either[_,C]]): Function1[A, Either[_,C]] = {
      (v1: A) => e.apply(v1).flatMap(b => f.apply(b))
    }
  }
}
正如在评论中指出的,这将丢弃
Left
类型。如果我在下面更改它,它将不起作用,因为最终输出的类型可以是
other[X | Y,C]
,解析为
other[|Y,C]
,我回到了第一步

implicit class AndThenEither[A,B,X](val e: (A) => Either[X, B]) {
    def andThenE[C,Y](f:(B) => Either[Y, C]): (A) => Either[_, C] = {
      (v1: A) => e.apply(v1).flatMap(b => f.apply(b))
    }
  }
下面是显示类型对齐组合失败的示例:

import EitherExtension._
object AndThenComposition {
  //sample type definitions of failure responses
  sealed trait InternalError
  case class Failure1() extends InternalError
  case class Failure2() extends InternalError
  //sample type definitions
  case class Id(id: Int)
  case class Stuff()
  //sample type definitions of successful responses
  case class Output1()
  case class Output2()
  case class InputRequest()

  val function1: (InputRequest) => Either[Failure1, Output1] = ???
  val function2: (Output1)  => Either[Failure2, Output2] = ???

  def doSomething(s:Id, l:List[Stuff]): Either[InternalError, Output2] = {
    val pipeline = function1 andThenE function2
    pipeline(InputRequest()) //Why is this of type Either[_, Output2]
  }
}

我错过了什么?我如何才能使返回类型不是
或[Any,Output2]
,而是基本/密封特征?这是通用的吗?

如果您在生产中使用它,并且它不仅仅是一个学习的东西,您正在寻找的东西叫做Kleisli,幸运的是,
cats core
已经实现了它

根据cats核心:

Kleisli允许组合返回一元值的函数, 例如,选项[Int]或[String,List[Double]],不带 让函数将选项或其中一个作为参数,可以 奇怪而笨拙

由于Kleisli由两个签名为
A=>F[B]
的函数组成,因此您只需要一个抽象就可以使用Kleisli,它正在为您的操作创建一个新类型:

类型操作[A]=任一[InternalFailure,A]
通过这样做,您应该能够像这样使用Kleisli:

导入cats.data.Kleisli
val first:Kleisli[操作,输入请求,输出1]=Kleisli{请求:输入请求=>
左(故障1())
}
val second:Kleisli[操作,输出1,输出2]=Kleisli{output:Output1=>
右(Output2())
}
val组合=第一个。第二个(第二个)

您需要保留左的类型,因此我们将修改扩展方法来实现这一点

请注意,由于两个eithers可以具有不同的左类型,因此我们将使用一个类型绑定来要求编译器推断这些类型之间的LUB;多亏了
Any
,这始终是可能的(尽管并非总是有用)

对象扩展{
隐式类和另一个[I,L1,R1](私有值f:I=>其中一个[L1,R1])扩展了AnyVal{
def和thene[L2>:L1,R2](g:R1=>任一[L2,R2]):I=>任一[L2,R2]=
i=>f(i).flatMap(g)
}
}
可以这样使用:

导入EitherExtension_
宾语合成{
密封特性内部误差
最终案例对象失败1扩展内部错误
最终案例对象失败2扩展内部错误
val function1:Int=>[Failure1.type,String]=???
val function2:String=>Failure2.type,布尔值]=???
def doSomething(输入:Int):要么[InternalError,Boolean]={
(功能1和功能2)(输入)
}
}


查看正在运行的代码。

好吧,您的
将丢弃左侧的类型。。。所以我不知道你为什么问它为什么这样做,你告诉它这样做。我明白你的意思——但我怎么能让它不这样做呢?
和thene
的输出结果总是
或[uu,C]
,因为错误可能来自链中的前一个函数,也可能来自此函数,并且两者的类型不同。我不想在泛型函数中声明错误的类型,因此是
签名。@LuisMiguelMejíaSuárez-更新了问题以更好地反映问题的根源。@LuisMiguelMejíaSuárez-请您发表评论/链接,以便我接受它?它确实解决了我的问题,并使编译成功。如果出现新问题,我会问一个新的/后续问题是的,我知道
cats
中的
Kliesli
结构。你不需要导入一个库就可以运行它。通过强制所有
操作[A]
中的任意一个,您已经输入了别名
操作[A]
。左侧的
类型为
内部故障
。我也可以在
中修复它。但这并没有回答问题,而是通过回避我的问题提供了一个解决方案。此外,这样做或通过
进行都是IMHO“生产可行的”。创建
Function1
的抽象子类并向其添加
方法并完成这项工作相对容易-我尝试通过隐式来完成。我以为您只是在寻找一种方法来编写一个返回monad的函数。关于您的实际问题,我不认为仅因为
就可以使用flatMap。flatMap
期望A1(或Y,在您的情况下)是
X
的超类型,可以与Scala 3+联合类型一起使用,但是: