我发现了HList/KList,它们非常酷.我有一个实际的用例,其中具有保守类型信息的异构类型和可变长度容器将非常有用(更多信息,请参见下面的背景).但是,我还没有将H/KList的用法理解为方法参数,在这里我被迫完全键入 - 注释参数或松散类型信息.H/KLists甚至可以用作参数,如果完整类型当然不知道?如何在不丢失类型信息的情况下引用H/KList?
"类型列表"可以用来指代异构和可变长度类型参数的元组吗?在这里它说:
... the types of the elements can be tracked separate from the actual element values. To do this we create an purely abstract type (it has no instances) which models a list of types, let's call it TList.
我玩了它,但还没有理解如何使用它作为参数的类型注释HList.
基本上,我想要这样的东西:
implicit def hlistToTypedLink[TL](a: HList[TL]):TypedLink[TL] = new TypedLink[TL](a.map(a:X => new TypedHandle[X]))
Run Code Online (Sandbox Code Playgroud)
其中TL指的是Type List,X指的是当前元素的类型.所以这里的HList应该映射到另一个类似于Tuple的容器TypedLink,由类型列表TL进行参数化.元素将被包装在另一个参数化容器TypedHandle中,使用当前类型X键入.
这可能吗?
我看到了Shapeless的'HList及其"统一"方法,但问题仍然存在:除了可变长度之外,我不知道如何在参数列表中引用它.
我的第二个希望是使用KList.它适用于我的情况,因为TypedHandle是具有相同构造函数的公共容器.随着KLIST它似乎更容易输入注释,根据apocalisp:
val m = List(1, 2, 3, 4) :^: List("str1", "str2") :^: KNil
Run Code Online (Sandbox Code Playgroud)
将是类型:
KCons[Int,java.lang.String :: HNil,List]
Run Code Online (Sandbox Code Playgroud)
但问题仍然存在:在方法定义中,我不知道它是否会是一个 …
试图通过Miles Sabin 使用这个技巧来创建一个只接受一组预定义参数的函数types.
val bool = Boolean
val timestamp = new Timestamp(date.getTime())
val str = "My String"
Run Code Online (Sandbox Code Playgroud)
然后跟随应该在编译时通过
takeValue(bool)
takeValue(timestamp)
takeValue(str)
Run Code Online (Sandbox Code Playgroud)
但
这里takeValue应该失败takeValue(someIntValue),如果implicit用于type Int不defined.And这种故障会在编译的时候.
trait MyConv[K] { type V; def convert: AnyRef => V }
def iMakeConv[V0](con: AnyRef => V0) = new MyConv[con.type] {
override type V = V0
val convert = con
}
def takeValue(value:AnyRef)(implicit conv :MyConv[value.type]) : \/[Throwable,conv.V] = \/.fromTryCatch(conv.convert(value))
Run Code Online (Sandbox Code Playgroud)
然后
implicit val strAny = iMakeConv((x:Any) …Run Code Online (Sandbox Code Playgroud) 我有一个json库,它通过遵循Scala中的类型类模式来定义(定义如何读取json)的概念 ReadCodec.该库使用Shapeless ' Typeclass构造来免费为任何案例类派生自动实例 ReadCodec.
现在,我有一个代码生成器,它在Scala中生成的类不是case类(但可能应该是).我可以让代码生成器为每个类生成ReadCodec实例,这就是我们现在所拥有的.但是现在如果我希望生成的类支持一些新的序列化形式,我需要修改代码生成以输出这个新类型类的实例.
有没有办法可以修改代码生成器来输出具有实例 LabelledGeneric或其他东西的类,这些实例可以利用生成(通过宏)案例类自动实例的机制?这样,生成的代码可以与使用Shapeless'的任何类型类模式互操作以Typeclass实现实例.
我刚刚开始学习scala,今天我决定编写一个CSV解析器,它可以很好地加载到case类中,但是将数据存储在Shapeless的HList对象的行(列表)中,这样我就可以接触到类型级编程了.
这是我到目前为止所拥有的:
// LoadsCsv.scala
import shapeless._
import scala.collection.mutable
trait LoadsCsv[A, T <: HList] {
val rows: mutable.MutableList[T] = new mutable.MutableList[T]
def convert(t: T)(implicit gen: Generic.Aux[A, T]): A = gen.from(t)
def get(index: Int): A = {
convert(rows(index))
}
def load(file: String): Unit = {
val lines = io.Source.fromFile(file).getLines()
lines.foreach(line => rows += parse(line.split(",")))
}
def parse(line: Array[String]): T
}
Run Code Online (Sandbox Code Playgroud)
并且正在加载数据集的对象:
// TennisData.scala
import shapeless._
case class TennisData(weather:String, low:Int, high:Int, windy:Boolean, play:Boolean)
object TennisData extends LoadsCsv[TennisData, String :: Int :: Int :: …Run Code Online (Sandbox Code Playgroud) 该方法doesNotCompile仅接受仅包含Label[A]条目的HLists .有一个Mapper可以将Label [A]转换为String(准确地说:) Const[String]#?.但是,当我应用映射器时,返回类型为ev1.Out.我知道这实际上只是一个只有字符串的HList,但我怎么能说服编译器呢?
import shapeless._
import shapeless.poly._
import shapeless.ops.hlist._
import shapeless.UnaryTCConstraint._
object Util {
case class Label[A](name: String, value: A)
object GetLabelName extends (Label ~> Const[String]#?) {
def apply[A](label: Label[A]) = label.name
}
}
object Main {
import Util._
def bar(l: List[String]) = ???
def compiles = {
val names = "a" :: "b" :: HNil
bar(names.toList)
}
// A is an HList whose members are all Label[_]
def doesNotCompile[A <: HList : *->*[Label]#?](labels: …Run Code Online (Sandbox Code Playgroud) 本地副本:
/***
scalaVersion := "2.11.8"
addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.7.1")
libraryDependencies ++= {
val shapelessVersion = "2.2.5"
Seq(
"com.chuusai" %% "shapeless" % shapelessVersion
)
}
*/
import shapeless._
case class Foo()
trait Wrapper
case class S(s: String) extends Wrapper
case class I(i: Int) extends Wrapper
object Main extends App {
object wrap extends Poly1 {
implicit def caseString = at[String](S.apply)
implicit def caseInt = at[Int](I.apply)
implicit def caseOther[T] = at[T](identity)
}
type A = Foo :: String :: HNil …Run Code Online (Sandbox Code Playgroud) 我在Scala做的事情.我有以下案例类:
import shapeless._
case class Foo(param1: String, param2: HList)
Run Code Online (Sandbox Code Playgroud)
我想使用Circe获得这种类型的JSON表示.我还想将生成的JSON字符串映射回类型.
模块circe-shapes自动推导出HLists,并且很容易从HList到JSON再返回.看这个例子:
scala> import shapeless._
import shapeless._
scala> import io.circe._, io.circe.generic.auto._, io.circe.parser._, io.circe.syntax._
import io.circe._
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._
scala> import io.circe.shapes._
import io.circe.shapes._
scala> val myList = 30 :: "car" :: HNil
myList: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 30 :: car :: HNil
scala> val listJson = myList.asJson
listJson: io.circe.Json =
[
30,
"car"
]
scala> listJson.as[HList] // won't work
<console>:32: error: could not …Run Code Online (Sandbox Code Playgroud) 我的一个项目使用scala功能混合,看起来不能很好地混合在一起:
我遇到的问题是类型类实例派生失败,如果:
Lazy这是我可以编写的用于重现问题的最小代码量:
import shapeless._
trait Show[A] {
def show(a: A): String
}
object Show {
def from[A](f: A => String): Show[A] = new Show[A] {
override def show(a: A) = f(a)
}
implicit val intShow: Show[Int] = Show.from(_.toString)
implicit def singletonShow[A](implicit
sa: Show[A]
): Show[A :: HNil] = Show.from {
case (a :: HNil) => sa.show(a)
}
implicit def singletonCaseClassShow[A, H <: HList](implicit
gen: Generic.Aux[A, H],
sh: Lazy[Show[H]]
): Show[A] = Show.from …Run Code Online (Sandbox Code Playgroud) 在阅读了很多文章后,我仍然对scala Shapeless库感到困惑.似乎Shapeless使用scala编译功能?那么它是否使用反射并且对生产代码安全吗?
理想情况下,我想在Scala中的类型级别编写Haskell样式模式匹配,如下所示:
无形可以用于这样的事情吗?
object Test{
type F[Int] = String
type F[Boolean] = Int // but this line does not compile
implicitly[String =:= F[Int]]
implicitly[Int =:= F[Boolean]]
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,如果F需要Int则返回String,如果需要Boolean则返回Int.
澄清(基于这个答案)
以下是我想在函数和类型类中使用这些类型的方法:
abstract class WrappedF[T] {
type F
type Unwrap = T
}
type F[X <: WrappedF[_]] = X#F
class IntF extends WrappedF[Int] { type F = StringF }
class BooleanF extends WrappedF[Boolean] { type F = IntF }
class StringF …Run Code Online (Sandbox Code Playgroud) types scala pattern-matching type-level-computation shapeless