Shapeless:Foo[T, U] 的 UnaryTCConstraint

Shapeless: UnaryTCConstraint for Foo[T, U]

我有以下工作按预期进行:

import shapeless._
import shapeless.UnaryTCConstraint._
import shapeless.test.illTyped

case class Foo[R](result: R, dependencies: Set[Foo[_]] = Set.empty)

//This method only accepts an HList of Foo
def method[L <: HList](list: L)(implicit utcc: UnaryTCConstraint[L, Foo]) = println("checks")

val notFoos = "abc" :: 1 :: 5.5 :: HNil
illTyped { """method(notFoos)""" }

val aFoo = Foo("abc")
val bFoo = Foo(2, Set(aFoo))
val cFoo = Foo(true, Set(bFoo))
val onlyFoos = aFoo :: bFoo :: cFoo :: HNil
method(onlyFoos) // prints checks

经过一些重构后,我得出的结论是依赖项应该是 Foos 的 HList。所以我将代码更改为:

type FooWithAnyDependency[R] = Foo[R, _ <: HList]

case class Foo[R, L <: HList](result: R, dependencies: L = HNil)(implicit utcc: UnaryTCConstraint[L, FooWithAnyDependency])

def method2[L <: HList](list: L)(implicit utcc: UnaryTCConstraint[L, FooWithAnyDependency]) = println("checks")

这段代码可以编译,但是当我尝试使用它时:

val aFoo = Foo("abc")

我收到这个错误:

Could not find implicit value for parameter utcc: shapeless.UnaryTCConstraint[shapeless.HNil.type,FooWithAnyDependency]
Error occurred in an application involving default arguments.
val aFoo = Foo("abc")
               ^

我认为它失败是因为它试图找到一个 UnaryTCConstraint[HNil .type, FooWithAnyDependency.

我知道实现自定义约束可以解决问题(我已经做到了),但是每当我尝试使用其他东西时,我 运行 都会遇到同样的问题,例如:Comapped.Aux[L, FooWithAnyDependency, M].

所以问题是,我怎样才能克服这个问题,而不必为 Foo 重新实现大多数东西。

您完全正确,问题是推断的 HNil.type 单例类型。幸运的是,修复非常简单——您只需为 HNil:

提供类型注释
case class Foo[R, L <: HList](
  result: R,
  dependencies: L = HNil: HNil
)(implicit utcc: UnaryTCConstraint[L, FooWithAnyDependency])

通常,在使用 Shapeless 时,您需要为 HNil 提供这样的类型注释,以避免(或多或少无用的)单例类型 HNil.type,除非您写一些东西像这样:

val hlist = 1 :: HNil

它将具有推断类型 Int :: HNil 而不是 Int :: HNil.type 只是因为 HNil 有一个 :: 方法可以确保您获得正确的类型。