2013-10-10 28 views
17

我正在嘗試學習無形(使用版本2.10.2)。我創建了一個非常簡單的可擴展的記錄:將無形可擴展記錄傳遞給函數

val rec1 = ("foo" ->> 42) :: HNil

按照REPL,這有鍵入

shapeless.::[Int with shapeless.record.KeyTag[String("foo"),Int],shapeless.HNil]

我試圖定義一個簡單的函數:

def fun(x: ::[Int with KeyTag[String("foo"), Int], HNil]) = x("foo") 

但它甚至沒有編譯。我不能在類型聲明中使用一個String(「foo」),並得到一個錯誤。

我有兩個問題:

  1. 我如何指定在我的代碼的可擴展記錄的類型?
  2. 當處理具有更多字段的記錄時,類型聲明的長度和複雜性將無法管理。有沒有辦法爲這個類型創建一個別名,給定一個特定的記錄實例或其他解決方法?

編輯

我發現:

val rec1 = ("foo" ->> 42) :: HNil 
val rec2 = ("foo" ->> 43) :: HNil 
var x = rec1 
x = rec2 

效果很好。我得出結論rec1,rec2和x是相同的類型。我只是不知道如何在代碼中表達這種類型!

回答

24

這裏有一些更一般的東西,我認爲可能會回答你的問題。假設我們要編寫一個方法,該方法可以在任何使用"foo"鍵的記錄上工作。我們可以用一個證人的組合和選擇:

import shapeless._, record._, syntax.singleton._ 

val w = Witness("foo") 

def fun[L <: HList](xs: L)(implicit sel: ops.record.Selector[L, w.T]) = xs("foo") 

然後:

scala> fun(("foo" ->> 42) :: HNil) 
res0: Int = 42 

或者:

scala> fun(("bar" ->> 'a) :: ("foo" ->> 42) :: HNil) 
res1: Int = 42 

如果我們真的想只允許沒有其他字段的記錄,我們可以寫出以下內容:

def fun(l: Int with KeyTag[w.T, Int] :: HNil) = l("foo") 

但這與記錄通常使用的方式有些不一致。

我們必須定義見證,正是因爲Scala 2.10沒有提供任何直接引用單例類型的方法 - 例如參見Alois Cochard的Shona項目的my fork進行一些討論。

我將添加一個最後的免責聲明,我現在纔剛剛熟悉Shapeless 2.0自己,但我不認爲即使邁爾斯也足夠了解這個限制。

+0

邁爾斯在Twitter上寫道(https://twitter.com/milessabin/status/388623399624646656)他可能能夠「在2.0.0版本之前刪除一些語法混亂」。 –

+1

如果我們有很多好玩的功能,我們必須重複每個隱含的參數。如果這些函數必須訪問多個字段(例如:foo,bar,...),那麼這將是痛苦的和錯誤的。有沒有辦法將選擇器的聲明分解? – bhericher

5

由於不成形2.1。0有一個new syntax表示記錄類型:

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

import shapeless._ 
import shapeless.record._ 
import shapeless.syntax.singleton._ 

def fun(x: Record.`"foo" -> Int`.T) = x("foo") 

// Exiting paste mode, now interpreting. 

import shapeless._ 
import shapeless.record._ 
import shapeless.syntax.singleton._ 
fun: (x: shapeless.::[Int with shapeless.labelled.KeyTag[String("foo"),Int],shapeless.HNil])Int 

scala> fun(("foo" ->> 42) :: HNil) 
res2: Int = 42 

scala> fun(("foo" ->> 42) :: ("bar" ->> 43) :: HNil) 
<console>:30: error: type mismatch; 
found : shapeless.::[Int with shapeless.labelled.KeyTag[String("foo"),Int],shapeless.::[Int with shapeless.labelled.KeyTag[String("bar"),Int],shapeless.HNil]] 
required: shapeless.::[Int with shapeless.labelled.KeyTag[String("foo"),Int],shapeless.HNil] 
     fun(("foo" ->> 42) :: ("bar" ->> 43) :: HNil) 

但選擇可能是對OP的用例的最佳方法。