2014-12-03 80 views
7

基本上,我希望能够写这样的事:Scala:有没有办法创建内联类型?

val x :('k1.type, Int) = 'k1 -> 1 
val y :('k2.type, Int) = 'k2 -> 2 

凡类型x和y的不兼容,但无论是共享的超类型或通过上下文边界进行标注,让我做这样的事情:

def mlt[T :MyLittleType](x :(T, Int)) = ??? 
mlt(x); mlt(y) 

关键词用在这里只是作为一个例子,我们的目标是能够为一些标识符/关键字/串同时提供文字和单类型。这些类型可能会在运行时被擦除/统一,我只对静态类型检查感兴趣。我想应该可以使用宏来实现,但我宁愿不要。

+3

我想你想要的东西像[基于字面值的单例类型](http://docs.scala-lang.org/sips/pending/42.type.html)。 – 2014-12-03 14:48:33

+0

Scala编译器的[Typelevel's fork](https://github.com/typelevel/scala)中提供了IIRC。 – 2014-12-03 14:54:14

+0

或者,[形状记录](https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#extensible-records)你想要什么? – lmm 2014-12-03 16:05:08

回答

1

您可以构建结构型式直列:

scala> val a = new {def hello = null} -> 1 // by the way hello is accessible in a (but scala uses reflection for that) 
a: (AnyRef{def hello: Null}, Int) = ([email protected],1) 

scala> var b = new {def hello = null} -> 2 
b: (AnyRef{def hello: Null}, Int) = ([email protected],2) 

scala> b = a 
b: (AnyRef{def hello: Null}, Int) = ([email protected],1) 

scala> var c = new {def helloooo = null} -> 1 
c: (AnyRef{def helloooo: Null}, Int) = ([email protected],1) 

scala> c = a 
<console>:15: error: type mismatch; 
found : (AnyRef{def hello: Null}, Int) 
required: (AnyRef{def helloooo: Null}, Int) 
     c = a 
     ^

所以,你可以将它们组合使用对象给他们键入独特:

new {def myTypeName = null} -> myObject //now your myObject tagged with 'myTypeName', but your methods should be aware about tuples 

def mlp(x: ((Any, YourObjectsType), Int)) = x 

或(东阳反射的稍微慢一点)

scala> def mlp(x: ({def obj: Symbol}, Int)) = x._1.obj -> x._2 
warning: there were 1 feature warning(s); re-run with -feature for details 
mlp: (x: (AnyRef{def obj: Symbol}, Int))(Symbol, Int) 

scala> mlp(new { def a1 = null; def obj = 'a1 } -> 1) 
res18: (Symbol, Int) = ('a1,1) 

scala> mlp(new { def a2 = null; def obj = 'a2 } -> 1) 
res19: (Symbol, Int) = ('a2,1) 

你可以用tags结合起来来注释类型,如:

import scalaz._ 
import Scalaz._ 

scala> def markALittle[T](a: T) = Tag[T, MyLittleType](a) 
markALittle: [T](a: T)[email protected]@[T,MyLittleType] 

scala> markALittle(new {def hello: Aaa = null}) 
res15: [email protected]@[AnyRef{def hello: Aaa},MyLittleType] = [email protected] 

更多标签例子:

scala> trait MyLittleType 

scala> trait Spike extends MyLittleType; val x = Tag[Symbol, Spike]('k1) -> 1 
x: ([email protected]@[Symbol,Spike], Int) = ('k1,1) 

scala> trait Rainbow extends MyLittleType; val y = Tag[Symbol, Rainbow]('k2) -> 1 
y: ([email protected]@[Symbol,Rainbow], Int) = ('k2,1) 

scala> val y: ([email protected]@[Symbol,Spike], Int) = Tag[Symbol, Rainbow]('k1) -> 1 
<console>:22: error: type mismatch; 
found : ([email protected]@[Symbol,Rainbow], Int) 
required: ([email protected]@[Symbol,Spike], Int) 
     val y: ([email protected]@[Symbol,Spike], Int) = Tag[Symbol, Rainbow]('k1) -> 1 


scala> val z: ([email protected]@[Symbol,_ <: MyLittleType], Int) = Tag[Symbol, Rainbow]('k1) -> 1 
z: ([email protected]@[Symbol, _ <: MyLittleType], Int) = ('k1,1) 

所以,你可以:

scala> def mlt[T <: MyLittleType](x :([email protected]@[Symbol,T], Int)) = x 
mlt: [T <: MyLittleType](x: ([email protected]@[Symbol,T], Int))([email protected]@[Symbol,T], Int) 

scala> mlt(x) 
res42: ([email protected]@[Symbol,Spike], Int) = ('k1,1) 

scala> mlt(y) 
res43: ([email protected]@[Symbol,Rainbow], Int) = ('k2,1) 

或者只需使用:

scala> val x = Tag[Int, Rainbow](1) 
x: [email protected]@[Int,Rainbow] = 1 

scala> val y = Tag[Int, Spike](1) 
y: [email protected]@[Int,Spike] = 1 

您可以操作x如同时使用IntTag.unwrap(x),或只是定义implicit def t[T] = Tag.unwrap[Int, T] _,使标签和Int之间没有什么区别,但要小心在这里 - 任何非标签导向功能将删除标记)

另一线上型构造解决方案:

一)丑

scala> class ___ 
defined class ___ 

scala> class __[T,U] extends ___ 
defined class __ 

scala> val x = Tag[Symbol, ___ __ ___]('k1) -> 1 
x: ([email protected]@[Symbol,__[___,___]], Int) = ('k1,1) 

scala> var y = Tag[Symbol, ___ __ ___ __ ___]('k1) -> 1 
y: ([email protected]@[Symbol,__[__[___,___],___]], Int) = ('k1,1) 

scala> y = x 
<console>:59: error: type mismatch; 
found : ([email protected]@[Symbol,__[___,___]], Int) 
required: ([email protected]@[Symbol,__[__[___,___],___]], Int) 
     y = x 
     ^

scala> def mlp[X <: [email protected]@[Symbol, _]](x: (X, Int)) = x 
mlp: [X <: [email protected]@[Symbol, _]](x: (X, Int))(X, Int) 

scala> mlp(x) 
res106: ([email protected]@[Symbol,__[___,___]], Int) = ('k1,1) 

二)搞笑:

class - [B <: -[_, _], A <: symbolic[A]] (a: A, b: B) { 
    def -[T <: symbolic[T]](c: T) = new - (c, this) 
} 

trait symbolic[F <: symbolic[F]] { 
    def - [T <: symbolic[T]](b: T) = new - [single[F],T](b, new single(this.asInstanceOf[F])) 
} 

class single[T <: symbolic[T]](a: T) extends - [single[_],T](a, null) 

val a = new a_; class a_ extends symbolic[a_] 
val b = new b_; class b_ extends symbolic[b_] 
val c = new c_; class c_ extends symbolic[c_] 
... 

scala> val x = h-e-l-l-o -> 1 
x: (-[o_,-[l_,-[l_,-[h_,end[e_]]]]], Int) = ([email protected],1) 

scala> var y = h-e-l-l-o-o -> 2 
y: (-[o_,-[o_,-[l_,-[l_,-[h_,end[e_]]]]]], Int) = ([email protected],2) 

scala> y = x 
<console>:13: error: type mismatch; 
found : (-[o_,-[l_,-[l_,-[h_,end[e_]]]]], Int) 
required: (-[o_,-[o_,-[l_,-[l_,-[h_,end[e_]]]]]], Int) 
     y = x 
     ^

scala> var z = h-e-l-l-o-o -> 2 
z: (-[o_,-[o_,-[l_,-[l_,-[h_,end[e_]]]]]], Int) = ([email protected],2) 

scala> z = y 
z: (-[o_,-[o_,-[l_,-[l_,-[h_,end[e_]]]]]], Int) = ([email protected],2) 
+0

谢谢,几个好主意来解决。我特别喜欢最后一个,因为它没有任何语法开销,不使用任何库,并且很容易第一次看到它,希望通过'不太聪明'的测试。顺便说一句,有没有办法告诉编译器在打印类型时使用中缀表示法?现在这个解决方案的唯一问题是错误如同地狱一样神秘。我最终在我的代码中使用了简单的结构类型,它不允许我想要的灵活性,并且有点冗长,但至少是易于理解的。 – Turin 2014-12-28 17:06:58

+0

Yrw!没有找到切换到中缀表示法(不包括编译器插件或(?)宏)的方法。我已经改变了一点,现在它打印出来了:'abcabcabc res22: - [ - [ - [ - [ - [single [a _],b _],c _],a _],b_] ,c _],a _],b _],c_]' – dk14 2014-12-28 17:38:12

+0

呵呵,我只是输入完全相同的解决方案,但是从平板电脑上,所以你更快:)再次感谢,这看起来很酷。 – Turin 2014-12-28 17:59:52

0

因此,为了保持简单,这个怎么样?

object xt; val x = (xt, 1); 
object yt; val y = (yt, 2); 

def mlt(x: (_, Int)) = 42 
mlt(x); mlt(y) 

好吧我欺骗了,它不是真的内联,但我认为它足够短,可以满足您的需求。 但是,如果你想存储在XT或YT一个值,你将不得不使用一些较长的: object xt {val get = 'k1}

相关问题