固定大小和元素界限的列表

时间:2016-09-29 00:43:22

标签: scala shapeless

使用shapeless,我正在尝试定义一个函数:

import shapeless._
import ops.nat._
import nat._

def threeNatsLessThan3[N <: Nat](xs: Sized[List[N], N])
   (implicit ev: LTEq[N, _3]) = ???

只有当输入xsList(大小为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个元素(如果可能)。

1 个答案:

答案 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 NatN内的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