2016-09-21 116 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大部分時間 - 定義一個自定義類型類將幾乎變得更清晰,並且在很多情況下都是必需的。」 - 你能指點我這個替代實現嗎? –

相關問題