2013-10-10 12 views
17

Próbuję się nauczyć Bezkształtnego (używając wersji 2.10.2). Stworzyłem bardzo prosty rozszerzalnej rekordu:Przekazywanie bezkształtnego, rozszerzalnego rekordu do funkcji

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

Według REPL, to musi wpisać

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

próbuję zdefiniować prostą funkcję:

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

, ale nie kompiluje się. Nie mogę użyć ciągu ("foo") w deklaracji typu i uzyskać błąd.

Mam dwa pytania:

  1. W jaki sposób można określić typ Extensible rekordu w moim kodu?
  2. Podczas pracy z rekordami zawierającymi więcej pól długość i złożoność deklaracji typu będą niemożliwe do zarządzania. Czy istnieje sposób na utworzenie aliasu dla danego typu, biorąc pod uwagę konkretne wystąpienie rekordu lub inne obejście?

EDIT

I odkryli, że:

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

działa dobrze. Wnioskuję rec1, rec2 i x są tego samego typu. Po prostu nie wiem, jak wyrazić ten typ w kodzie!

Odpowiedz

24

Oto coś trochę bardziej ogólnego, co według mnie może odpowiedzieć na twoje pytanie. Załóżmy, że chcemy napisać metodę, która zadziała na dowolnym rekordzie z kluczem "foo". Możemy użyć kombinacji świadka i selektora:

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") 

, a następnie:

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

czyli

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

Gdybyśmy naprawdę chcieli pozwolić tylko rekordy bez innych dziedzinach , możemy napisać:

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

Jest to jednak nieco sprzeczne ze sposobem, w jaki powszechnie używane są zapisy.

Musimy dokładnie zdefiniować świadka, ponieważ Scala 2.10 nie podaje żadnego sposobu bezpośredniego odniesienia się do typu singleton - patrz na przykład my fork projektu Alois Cochard: Shona.

Dodam jako ostateczne oświadczenie, że dopiero teraz poznaję samego Shapeless 2.0, ale nie sądzę, że nawet Miles jest na tyle magiczny, aby obejść to ograniczenie.

+0

Dla przypomnienia, Miles właśnie powiedział [na Twitterze] (https://twitter.com/milessabin/status/388623399624646656), że może być w stanie "usunąć część składniowego bałaganu przed końcem 2.0.0". –

+1

Jeśli mamy wiele funkcji, takich jak zabawa, musimy powtórzyć niejawny parametr dla każdego. Jest to bolesne i błąd, jeśli te funkcje muszą uzyskać dostęp do więcej niż jednego pola (np. Foo, bar, ...). Czy istnieje sposób na zliczanie deklaracji selektorów? – bhericher

5

Od bezkształtnej wersji 2.1.0 jest new syntax wyrazić typy rekordów:

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) 

Ale Selector jest prawdopodobnie najlepszym podejściem do użytkową przypadku OP.

Powiązane problemy