Scala:有没有办法创建内联类型?

标签 scala types inline type-systems singleton-type

基本上,我希望能够写出这样的东西:

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

x 和 y 的类型不兼容,但可以共享一个父类(super class)型或可以用上下文边界注释,允许我做这样的事情:
def mlt[T :MyLittleType](x :(T, Int)) = ???
mlt(x); mlt(y)

关键字在这里仅用作示例,目标是能够为某些标识符/关键字/字符串提供文字和单例类型。类型也可能在运行时被删除/统一,我只对静态类型检查感兴趣。我想应该可以使用宏来实现这一点,但我宁愿不这样做。

最佳答案

您可以内联构造结构类型:

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) = ($anon$1@68e2da47,1)

scala> var b = new {def hello = null} -> 2
b: (AnyRef{def hello: Null}, Int) = ($anon$1@77147ad6,2)

scala> b = a
b: (AnyRef{def hello: Null}, Int) = ($anon$1@68e2da47,1)

scala> var c = new {def helloooo = null} -> 1
c: (AnyRef{def helloooo: Null}, Int) = ($anon$1@38def4a2,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)scalaz.@@[T,MyLittleType]

scala> markALittle(new {def hello: Aaa = null})
res15: scalaz.@@[AnyRef{def hello: Aaa},MyLittleType] = $anon$1@a8c48e8

更多标记示例:
scala> trait MyLittleType

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

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

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


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

这样你就可以:
scala> def mlt[T <: MyLittleType](x :(scalaz.@@[Symbol,T], Int)) = x
mlt: [T <: MyLittleType](x: (scalaz.@@[Symbol,T], Int))(scalaz.@@[Symbol,T], Int)

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

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

或者只是使用:
scala> val x = Tag[Int, Rainbow](1)
x: scalaz.@@[Int,Rainbow] = 1

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

您可以操作x作为两者 Int使用 Tag.unwrap(x) ,或者只是定义 implicit def t[T] = Tag.unwrap[Int, T] _ Tag 和 Int 之间没有区别,但在这里要小心 - 任何非面向标签的函数都会删除标签)

另一个内联类型构造函数解决方案:

a) 丑陋的
scala> class ___
defined class ___

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

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

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

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

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

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

b) 有趣:
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) = ($minus@350bc88,1)

scala> var y = h-e-l-l-o-o -> 2
y: (-[o_,-[o_,-[l_,-[l_,-[h_,end[e_]]]]]], Int) = ($minus@46d7fdc0,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) = ($minus@6b899d5d,2)

scala> z = y
z: (-[o_,-[o_,-[l_,-[l_,-[h_,end[e_]]]]]], Int) = ($minus@46d7fdc0,2)

关于Scala:有没有办法创建内联类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27273534/

相关文章:

scala - tomcat 网络套接字 : cannot connect to tomcat server

scala - 在 scala Spark 中分组并保存重叠列的最大值

struct - 使用hive复杂的struct数据类型,如何使用where子句编写查询

types - Erlang 的打字机推导出奇怪的字符串类型

css - 2 文本框不在行中显示

scala - 丢弃已在 Play Framework 2.x 上设置的 header

Scala延续和异常处理

C++:char** 到 const char** 的转换

kotlin - 了解Kotlin中的内联类

css - 如何在没有 float 方法的情况下将 2 个 div 并排放置