依赖方法类型以前曾是一个实验性功能,现在默认情况下已在中继中启用,显然这似乎在Scala社区中引起了一些兴奋.
初看起来,这并不是显而易见的.Heiko Seeberger在这里发布了一个简单的依赖方法类型示例,从评论中可以看出,可以很容易地在方法上使用类型参数进行复制.所以这不是一个非常引人注目的例子.(我可能会遗漏一些明显的东西.如果是这样,请纠正我.)
对于依赖方法类型的用例有哪些实用且有用的例子,它们明显优于替代方法?
我们可以用以前不可能/容易的事情做些什么有趣的事情?
他们通过现有的类型系统功能为我们买了什么?
此外,依赖方法类型是否类似于或从其他高级类型语言(如Haskell,OCaml)的类型系统中找到的任何功能中汲取灵感?
haskell type-systems programming-languages scala dependent-method-type
我将从一个例子开始.这里的List.fill元组与Scala 2.10中的宏相当:
import scala.language.experimental.macros
import scala.reflect.macros.Context
object TupleExample {
def fill[A](arity: Int)(a: A): Product = macro fill_impl[A]
def fill_impl[A](c: Context)(arity: c.Expr[Int])(a: c.Expr[A]) = {
import c.universe._
arity.tree match {
case Literal(Constant(n: Int)) if n < 23 => c.Expr(
Apply(
Select(Ident("Tuple" + n.toString), "apply"),
List.fill(n)(a.tree)
)
)
case _ => c.abort(
c.enclosingPosition,
"Desired arity must be a compile-time constant less than 23!"
)
}
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以使用以下方法:
scala> TupleExample.fill(3)("hello")
res0: (String, String, String) = (hello,hello,hello)
Run Code Online (Sandbox Code Playgroud)
这个家伙在几个方面都是一只奇怪的鸟.首先,arity参数必须是一个文字整数,因为我们需要在编译时使用它.在Scala的早期版本中,(根据我所知),方法甚至无法判断其中一个参数是否是编译时文字.
其次, …
所以我有这个宏:
import language.experimental.macros
import scala.reflect.macros.Context
class Foo
class Bar extends Foo { def launchMissiles = "launching" }
object FooExample {
def foo: Foo = macro foo_impl
def foo_impl(c: Context): c.Expr[Foo] =
c.Expr[Foo](c.universe.reify(new Bar).tree)
}
Run Code Online (Sandbox Code Playgroud)
我已经说了三次我想要foo返回一个Foo,但我可以做以下(在2.10.0-RC3中):
scala> FooExample.foo
res0: Bar = Bar@4118f8dd
scala> res0.launchMissiles
res1: String = launching
Run Code Online (Sandbox Code Playgroud)
如果我删除任何一个上的类型参数,也会发生同样的事情c.Expr.如果我真的想确保无论谁打电话foo都看不到他们正在获得Bar,我必须在树本身添加类型归属.
这实际上非常棒 - 例如,我可以将宏指向某种类型的模式,并Vocabulary使用表示词汇表中的术语的成员方法创建某个类的匿名子类,这些将在返回的对象上可用.
我想知道我到底在做什么,所以我有几个问题.首先,该foo方法实际上的返回类型是什么?它是否仅适用于(可选)文档?它明确地约束了返回类型(例如,Int在这种情况下我无法将其更改为),如果我将其完全删除,则会出现如下错误:
scala> FooExample.foo
<console>:8: error: type mismatch;
found : Bar
required: Nothing
FooExample.foo …Run Code Online (Sandbox Code Playgroud)