Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala:如何强制将语句转换为文字?_Scala_Scala Macros_Dependent Type_Refined - Fatal编程技术网

Scala:如何强制将语句转换为文字?

Scala:如何强制将语句转换为文字?,scala,scala-macros,dependent-type,refined,Scala,Scala Macros,Dependent Type,Refined,我正在试验scala的一个库中提供的精致类型功能: 以下代码表示一个简单的情况: import eu.timepit.refined.auto._ import shapeless.{Witness => W} type Vec5 = List[Int] Refined Size[Equal[W.`5`.T]] val v1: Vec5 = List(1, 2, 3, 4, 5) val v2: Vec5 = List(1 to 5: _*) 在尝

我正在试验scala的一个库中提供的精致类型功能:

以下代码表示一个简单的情况:

  import eu.timepit.refined.auto._
  import shapeless.{Witness => W}

    type Vec5 = List[Int] Refined Size[Equal[W.`5`.T]]

    val v1: Vec5 = List(1, 2, 3, 4, 5)

    val v2: Vec5 = List(1 to 5: _*)
在尝试编译时,我遇到以下错误:


[Error] /home/peng/git/scalaspike/common/src/test/scala/com/tribbloids/spike/refined_spike/Example.scala:32: compile-time refinement only works with literals
[Error] /home/peng/git/scalaspike/common/src/test/scala/com/tribbloids/spike/refined_spike/Example.scala:34: compile-time refinement only works with literals
[Error] /home/peng/git/scalaspike/common/src/test/scala/com/tribbloids/spike/singleton_ops_spike/Example.scala:32: Cannot prove requirement Require[...]
three errors found
应该注意的是,v1和v2都可以在编译时轻松地进行内联计算,但是scala编译器似乎拒绝这样做,对于
List
类型,似乎没有办法建议这样做

那么这项功能怎么会有用呢?

根据
大小[Equals[X]]
编译时提升只在
字符串的宏中实现


顺便说一句,这是有意义的,因为作者必须在编译时对代码进行求值-
List(1,2,3,4,5)
看起来很容易,但是
Set(1,1,2,2,3,3)
需要进行一些求值,如果要求值的代码是
List(1,1,2,3,3)呢.distinct
-它也可以在编译时解决,但您必须将行设置在某个位置,除非您想冒执行任意代码的风险。即使在更简单的情况下,要分析的ADT也可能很复杂且容易出错。当然,可以添加一些“明显的特殊情况”,但就我个人而言,我更希望该库的作者关注更有用的东西。

问题是
eu.timepit.defined
宏适用于文本,
BigDecimal
BigInt

列表(1,2,3,4,5)
不是文本

对于像
List(1,2,3,4,5)
这样的非文字值,有
refineV
在运行时工作

val v1 = List(1, 2, 3, 4, 5)
val v2 = List(1, 2, 3, 4, 5, 6)
refineV[Size[Equal[5]]](v1) 
// Right(List(1, 2, 3, 4, 5))
refineV[Size[Equal[5]]](v2) 
// Left(Predicate taking size(List(1, 2, 3, 4, 5, 6)) = 6 failed: Predicate failed: (6 == 5).)
幸运的是,您可以在编译时运行
refineV

object myAuto {
  implicit def compileTimeRefineV[T, P](t: T): T Refined P = 
    macro compileTimeRefineVImpl[T, P]

  def compileTimeRefineVImpl[T: c.WeakTypeTag, 
                             P: c.WeakTypeTag](c: blackbox.Context)(t: c.Tree): c.Tree = {
    import c.universe._
    val pTyp = weakTypeOf[P]
    val tTyp = weakTypeOf[T]
    c.eval(c.Expr[Either[String, T Refined P]](c.untypecheck(
      q"_root_.eu.timepit.refined.`package`.refineV[$pTyp].apply[$tTyp]($t)"
    ))).fold(
      c.abort(c.enclosingPosition, _),
      _ => q"$t.asInstanceOf[_root_.eu.timepit.refined.api.Refined[$tTyp, $pTyp]]"
    )
  }
}

import myAuto._ // don't import eu.timepit.refined.auto._
type Vec5 = List[Int] Refined Size[Equal[5]]
val v1: Vec5 = List(1, 2, 3, 4, 5) // compiles
// val v2: Vec5 = List(1, 2, 3, 4, 5, 6) 
  // Error: Predicate taking size(List(1, 2, 3, 4, 5, 6)) = 6 failed: Predicate failed: (6 == 5).
如果您只需要静态大小的集合,可以使用
shapeless.sized


列表(1,2,3,4,5)
不是文字。非常感谢,答案显然是用scala 2.13编写的,我将尝试在2.12中复制它。我更喜欢避免无形状。大小是因为它使用Nat类型,它依赖church编码,而不是church编码efficient@tribbloid在2.12。您只需将类型
5
替换为
W.`5`.T
import eu.timepit.defined.W
)。“其他一切都应该起作用。”gitter的tribbloid I fthomas又名:“实现隐式转换不是一个好主意吗。他说:“如果我们允许在编译时细化任意值,我们将允许在编译时运行任意代码。如果传递给
refineV
的表达式有副作用,我们将在编译时运行它们。”这就是为什么我问scala是否有关键字来声明列表类型的文本。在大多数现代编译器体系结构中,编译时和运行时之间没有明确的界限。Scala的文本仅用于:
String
s、符号、
null
和一些原语,请参见:我明白了,哇,这似乎离完全依赖类型有相当大的距离。我会看看是否能找到其他的旁路。嗯,Scala从未声称它有完全依赖的类型。它实现了一个子集,路径依赖类型,并改进了Dotty中的思想,但完全依赖类型从来都不是目标。尽管如此,大多数情况下它仍然有效,请查看Miles Sabin post:
object myAuto {
  implicit def compileTimeRefineV[T, P](t: T): T Refined P = 
    macro compileTimeRefineVImpl[T, P]

  def compileTimeRefineVImpl[T: c.WeakTypeTag, 
                             P: c.WeakTypeTag](c: blackbox.Context)(t: c.Tree): c.Tree = {
    import c.universe._
    val pTyp = weakTypeOf[P]
    val tTyp = weakTypeOf[T]
    c.eval(c.Expr[Either[String, T Refined P]](c.untypecheck(
      q"_root_.eu.timepit.refined.`package`.refineV[$pTyp].apply[$tTyp]($t)"
    ))).fold(
      c.abort(c.enclosingPosition, _),
      _ => q"$t.asInstanceOf[_root_.eu.timepit.refined.api.Refined[$tTyp, $pTyp]]"
    )
  }
}

import myAuto._ // don't import eu.timepit.refined.auto._
type Vec5 = List[Int] Refined Size[Equal[5]]
val v1: Vec5 = List(1, 2, 3, 4, 5) // compiles
// val v2: Vec5 = List(1, 2, 3, 4, 5, 6) 
  // Error: Predicate taking size(List(1, 2, 3, 4, 5, 6)) = 6 failed: Predicate failed: (6 == 5).