给出Success
和Failure
的以下AST:
sealed trait Success
case object FooGood extends Success
case object BarGood extends Success
sealed trait Failure
case object FooBad extends Failure
case object BarBad extends Failure
方法签名:
def go[A <: Failure, B <: Success](x: Int): Either[A, B] = ???
但是,我希望将Left
和Right
类型限制为特定于Foo
或Bar
。
但是下面的代码编译(违背我的意愿):
scala> go[FooBad.type, BarGood.type](5)
scala.NotImplementedError: an implementation is missing
如何在编译时实现此约束?
答案 0 :(得分:4)
这是一个依赖于类型类的解决方案。值得注意的是,它不需要为每个(一对)AST节点手动定义新的类型实例。 它确实涉及为每对引入一个共同的超类型(虽然你在技术上没有将它用作基类,但它仅用作标记类型)。 / p>
sealed trait Success[T]
abstract sealed class Foo
abstract sealed class Bar
case object FooGood extends Foo with Success[Foo]
case object BarGood extends Bar with Success[Bar]
sealed trait Failure[T]
case object FooBad extends Foo with Failure[Foo]
case object BarBad extends Bar with Failure[Bar]
@annotation.implicitNotFound("Expecting reciprocal Failure and Success alternatives, but got ${A} and ${B}")
trait IsGoodAndBadFacet[A,B]
implicit def isGoodAndBadFacet[T,A,B](implicit e1: A <:< Failure[T], e2: B<:<Success[T]): IsGoodAndBadFacet[A,B] = null
def go[A, B](x: Int)(implicit e: IsGoodAndBadFacet[A,B]): Either[A, B] = ???
Repl测试:
scala> go[FooBad.type, BarGood.type](5)
<console>:17: error: Expecting reciprocal Failure and Success alternatives, but got FooBad.type and BarGood.type
go[FooBad.type, BarGood.type](5)
^
scala> go[FooBad.type, FooGood.type](5)
scala.NotImplementedError: an implementation is missing
at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225)
at .go(<console>:11)
... 33 elided
scala> go[BarBad.type, BarGood.type](5)
scala.NotImplementedError: an implementation is missing
at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225)
at .go(<console>:11)
... 33 elided
答案 1 :(得分:2)
你遇到的问题是编译器不知道WITH
SET [OP] AS NONEMPTY([Z_OP].[LEVEL01].MEMBERS, [MEASURES].[EssentialMeasureInCube])
SET [NV] AS NONEMPTY([Z_NV].[LEVEL01].MEMBERS, [MEASURES].[EssentialMeasureInCube])
SET [DT] AS NONEMPTY([Z_DT].[LEVEL01].MEMBERS, [MEASURES].[EssentialMeasureInCube])
SELECT
NON EMPTY { } ON 0,
NON EMPTY [OP] * [NV] * [DT] ON 1
FROM
[Z_TEST/Z_TEST_REQ];
与FooGood
有某种关联,所以你需要以某种方式提示它。
这是我想出的,虽然我承认它不是很优雅:
FooBad
正如您所看到的,提示是通过创建trait Grouping[B, G]
object FooHelper {
implicit object fooGrouping Grouping[FooBad.type, FooGood.type]
}
object BarHelper {
implicit object barGrouping Grouping[BarBad.type, BarGood.type]
}
def go[A <: Failure, B <: Success](x: Int)(implicit ev: Grouping[A, B]): Either[A, B] = ???
import FooHelper._
import BarHelper._
// the following two type check
go[FooBad.type, FooGood.type](5)
go[BarBad.type, BarGood.type](5)
// while these two do not
go[FooBad.type, BarGood.type](5)
go[BarBad.type, FooGood.type](5)
并将正确的分组放入隐式范围来实现的。这种方法的问题在于用户可能会创建自己的分组,这可能无效。
答案 2 :(得分:0)
通过引入类型参数,可以将输出类型限制为Success
/ Failure
对:
sealed trait Success[T]
sealed trait Failure[T]
sealed trait Foo
sealed trait Bar
case object FooGood extends Success[Foo]
case object BarGood extends Success[Bar]
case object FooBad extends Failure[Foo]
case object BarBad extends Failure[Bar]
def go[T, A <: Failure[T], B <: Success[T]](x: Int): Either[A, B] = ???
但是!只有当你创建一个提供类型T
的具体实现时才有意义,因为其他方式创建这样的签名毫无意义。
我可以看到任何实用程序作为接口的一部分,它约束go
的结果,如下所示:
trait Paired[T] {
type A <: Failure[T]
type B <: Success[T]
def go(x: Int): Either[A, B]
}
如果你想明确地提供类型(但你将如何为此创建实现?) - 提供隐式分组的答案是非常合理的。