Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.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_Shapeless - Fatal编程技术网

Scala 形状不规则的线状特征,带有最少的样板

Scala 形状不规则的线状特征,带有最少的样板,scala,shapeless,Scala,Shapeless,我正在尝试定义一种生成类似字符串类型的通用方法。例如,我想 case class Foo1(s: String) extends AnyVal case class Foo2(s: String) extends AnyVal ... 比如scalaz.Show、scalaz.Equal、argonaut.CodecJson等实例。 我知道这是可能的使用黑客方法,如抓取由case类生成的apply/unapply函数,但我希望能想出一个类型安全、无模板、无形状的解决方案。以下是我想到的最好的:

我正在尝试定义一种生成类似字符串类型的通用方法。例如,我想

case class Foo1(s: String) extends AnyVal
case class Foo2(s: String) extends AnyVal
...
比如scalaz.Show、scalaz.Equal、argonaut.CodecJson等实例。 我知道这是可能的使用黑客方法,如抓取由case类生成的apply/unapply函数,但我希望能想出一个类型安全、无模板、无形状的解决方案。以下是我想到的最好的:

import scalaz._, Scalaz._
import argonaut._, Argonaut._
import shapeless._

trait HasName[A] {
  def to(v: A): String
  def fr(v: String): A
}

object HasName {
  def apply[A](implicit instance: HasName[A]): HasName[A] = instance
  def instance[A](f: A => String, g: String => A): HasName[A] = new HasName[A] { def to(v: A) = f(v); def fr(v: String) = g(v) }

  implicit val hlist: HasName[String :: HNil] = new HasName[String :: HNil] {
    def to(v: String :: HNil) = v.head
    def fr(v: String) = v :: HNil
  }

  implicit def generic[A, R](implicit F: Generic.Aux[A, R], G: HasName[R]): HasName[A] = instance(
    v => G.to(F.to(v)),
    v => F.from(G.fr(v))
  )
}

trait Name[A] {
  val F: HasName[A]
  implicit val show: Show[A] = Show.shows(F.to)
  implicit val read: Read[A] = Read.readUnsafe(F.fr)
  implicit val json: CodecJson[A] = CodecJson[A](v => jString(F.to(v)), c => c.as[String] map F.fr)
  implicit val equal: Equal[A] = Equal.equalA[A]
}
然后用户就可以做了

case class Foo1(s: String) extends AnyVal
object Foo1 extends Name[Foo1] {
  val F = cachedImplicit[HasName[Foo1]]
}
这不是太多的陈词滥调,但仍然有令人讨厌的F。我试过这个:

class Name[A](implicit F: HasName[A]) {
  implicit val show: Show[A] = Show.shows(F.to)
  implicit val read: Read[A] = Read.readUnsafe(F.fr)
  implicit val json: CodecJson[A] = CodecJson[A](v => jString(F.to(v)), c => c.as[String] map F.fr)
  implicit val equal: Equal[A] = Equal.equalA[A]
}
在呼叫站点哪一个更好:

object Foo1 extends Name[Foo1]
但它不起作用;不能有隐式的按名称参数,也不能传递非按名称循环引用


关于如何使调用者和被调用者代码保持良好状态,您有什么想法吗?

您可以利用您的
HasName
将隐含在范围内这一事实来执行以下操作

trait Name[A] {
  implicit def show(implicit F: HasName[A]): Show[A] = Show.shows(F.to)
  implicit def read(implicit F: HasName[A]): Read[A] = Read.readUnsafe(F.fr)
  implicit def json(implicit F: HasName[A]): CodecJson[A] = CodecJson[A](v => jString(F.to(v)), c => c.as[String] map F.fr)
  implicit def equal(implicit F: HasName[A]): Equal[A] = Equal.equalA[A]
}

好主意。谢谢