Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
818 views
in Technique[技术] by (71.8m points)

scala - Passing a Shapeless Extensible Record to a Function

I am trying to learn Shapeless (using version 2.10.2). I have created a very simple extensible record:

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

According to the REPL, this has type

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

I am trying to define a simple function:

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

but it does not even compile. I cannot use a String("foo") in the type declaration, and get an error.

I have two questions:

  1. How can I specify the type of the extensible record in my code?
  2. When working with records with more fields, the length and complexity of the type declaration will be unmanageable. Is there a way to create an alias for the type, given a particular instance of a record, or some other workaround?

EDIT

I have found that:

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

works well. I conclude rec1, rec2, and x are of the same type. I just don't know how to express that type in code!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here's something a little more general that I think might answer your question. Suppose we want to write a method that will work on any record with a "foo" key. We can use a combination of a witness and a selector:

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

And then:

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

Or:

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

If we really wanted to only allow records with no other fields, we could write the following:

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

But that's somewhat at odds with the way records are generally used.

We have to define the witness precisely because Scala 2.10 doesn't provide any way to refer to a singleton type directly—see for example my fork of Alois Cochard's Shona project for some discussion.

I will add as a final disclaimer that I'm only just now getting familiar with Shapeless 2.0 myself, but I don't think even Miles is magical enough to get around this limitation.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...