使用shapeless
,我正在尝试定义一个函数:
import shapeless._
import ops.nat._
import nat._
def threeNatsLessThan3[N <: Nat](xs: Sized[List[N], N])
(implicit ev: LTEq[N, _3]) = ???
只有当输入xs
是List
(大小为3)Nat
且每个元素都是&lt; = 3时才会编译。
但是无法编译:
scala> threeNatsLessThan3[_3](List(_1,_2,_3))
<console>:22: error: type mismatch;
found : List[shapeless.Succ[_ >: shapeless.Succ[shapeless.Succ[shapeless._0]] with shapeless.Succ[shapeless._0] with shapeless._0 <: Serializable with shapeless.Nat]]
required: shapeless.Sized[List[shapeless.nat._3],shapeless.nat._3]
(which expands to) shapeless.Sized[List[shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]],shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]]a>
twoNatsFirstLtEqSecond[_3](List(_1,_2,_3))
^
如何正确实现上述功能?
我也很感激使用HList的解决方案,其中HList
仅包含Nat
个元素(如果可能)。
答案 0 :(得分:1)
您要输入的内容是签名为List
,其大小为N
,其中仅包含N
类型的元素。要发白,Sized[List[N], N]
表示以下其中一项:List(_1)
,List(_2, _2)
或最后List(_3, _3, _3)
,并考虑您的类型级别约束。这几乎是你想要的,并解释了编译器给你的错误:
required: shapeless.Sized[List[shapeless.nat._3],shapeless.nat._3]
要开始分解您想要完成的任务,我们需要注意您不能拥有List[Nat]
并保留各个类型。 Nat
的抽象性会掩盖它们。因此,如果您想在编译时执行操作,您将有三个选择:使用HList
,选择修复列表中Nat
的类型,以便{ {1}}或选择使用List[N]
来修正List[Nat]
的尺寸。
如果您想说Sized
的尺寸小于3,那么
List
如果您想说def lessThanThree[N <: Nat](sz: Sized[List[Nat], N])(implicit ev: LTEq[N, _3]) = sz
List
小于3 Nat
,N
内的List
也是如此:
def lessThanThree[N <: Nat, M <: Nat](sz: Sized[List[N], M])(implicit ev: LTEq[N, _3]) = sz
如果您希望使用Poly
,可以为任何at
定义Nat
,以便保留LTEq
约束,那么您可以#39;我需要了解Sized
确实使map
更符合大多数集合中的标准包map
,即它需要CanBuildFrom
。这与Nat
中个人List
的删除相结合意味着您在提出解决方案方面遇到了很多困难,这些解决方案为您提供了您正在寻找的灵活性类型
如果您使用HList
,则可以执行以下操作:
object LT3Identity extends Poly{
implicit def only[N <: Nat](implicit ev: LTEq[N, _3]) = at[N]{ i => i}
}
def lt3[L <: HList, M <: Nat](ls: L)(implicit lg: Length.Aux[L, M], lt: LTEq[M, _3]) = ls.map(LT3Identity)
同时将Hlist
的大小限制为小于3,同时仅允许包含HList
小于或等于3的Nat
。