2016-09-21 263 views
3

我有一个多态的功能,可以将列表成为集:将一个额外的参数传递给多态函数?

import shapeless.PolyDefns.~> 
import shapeless._ 

val lists = List(1,2) :: List("A", "B") :: List(1.1, 2.2) :: HNil 

object sss extends (List ~> Set) { 
    def apply[T](l:List[T]):Set[T] = { 
    l.toSet 
    } 
} 

lists.map(sss) // I want: Set(1,2) :: Set("A", "B") :: Set(1.1, 2.2) :: HNil 

但是如果我想改变这个函数的行为 - 我现在想添加将在输入指定项目额外的参数清单应该放入集合中。这是一个不正确的语法 - 你能告诉我正确的方法吗?

object sss extends (List ~> Set) { // Compiler says no! 
    def apply[T](i:Int)(l:List[T]):Set[T] = { 
    l.slice(i,i+1).toSet 
    } 
} 

我认为这是失败,因为额外的参数使得它不再适合列表〜>设置的签名,所以我如何克服这个问题?

+0

出错了:// //我要:1 ::“A”:: 3.5 :: HNil' – pedrofurla

+0

已更正,谢谢! –

回答

1

正如您已经指出的那样,您不能更改多态函数的签名。但可以动态创建功能:

class sss(i: Int) extends (List ~> Set) { 
    def apply[T](l:List[T]): Set[T] = { 
    l.slice(i, i+1).toSet 
    } 
} 

val sss1 = new sss(1) 
lists.map(sss1) // Set(2) :: Set(B) :: Set(2.2) :: HNil 
+0

除非你让'sss1'成为一个对象(相当神秘的原因),否则这是行不通的。 –

+0

奇怪的是,它在我的测试案例中工作(如果我创建了一个'val'持有该实例)。 – devkat

3

有来设定参数,一个Poly,其中之一在对方的回答中提到了几个解决方法,但确切的实施不会有工作。相反,你需要做到这一点:

import shapeless._, shapeless.poly.~> 

val lists = List(1, 2) :: List("A", "B") :: List(1.1, 2.2) :: HNil 

class sss(i: Int) extends (List ~> Set) { 
    def apply[T](l: List[T]): Set[T] = l.slice(i, i+1).toSet 
} 

object sss1 extends sss(1) 

lists.map(sss1) 

...这里是sss1被定义为一个对象(不是val)的事实是必要的最后一行进行编译。

该方法编译,但不可能在很多情况下使用它 - 例如,你不能在hlist的类型是通用的方法中定义你的sss1(或其他)对象。

这里有一个稍微混乱,但更灵活的解决办法之前,我用:你实际上可以写了一个通用的L <: HListi -you'd只需要几个隐含的方法和切片参数

import shapeless._ 

val lists = List(1, 2) :: List("A", "B") :: List(1.1, 2.2) :: HNil 

object sss extends Poly2 { 
    implicit def withI[T]: Case.Aux[List[T], Int, Set[T]] = 
    at((l, i) => l.slice(i, i + 1).toSet) 
} 

lists.zipWith(lists.mapConst(1))(sss) 
// Set(2) :: Set(B) :: Set(2.2) :: HNil 

现在参数支持mapConstzipWith应用程序。

虽然这两种方法都非常优雅,但我个人倾向于在大多数情况下避免使用Poly--定义一个自定义类型类几乎会更干净,并且在很多情况下都是必需的。

+0

“虽然这两种方法都不是很优雅,但我个人倾向于避免Poly大部分时间 - 定义一个自定义类型类将几乎变得更清晰,并且在很多情况下都是必需的。” - 你能指点我这个替代实现吗? –

相关问题