使用 shapeless,可以LabelledGeneric像这样更新 case 类字段:
case class Test(id: Option[Long], name: String)
val test = Test(None, "Name")
val gen = LabelledGeneric[Test]
scala> gen.from(gen.to(test) + ('id ->> Option(1L)))
res0: Test = Test(Some(1),Name)
Run Code Online (Sandbox Code Playgroud)
我希望Test类(和其他类)扩展一个抽象类Model,该类将实现一个方法withId,该方法将使用LabelledGeneric类似于上述代码来更新id字段,如果它有一个(它应该)。
我的尝试将 a 的隐式参数添加LabelledGeneric[A]到 的构造函数中Model,它实现得很好。我还需要以某种方式为LabelledGeneric#Repr具有id要替换的字段的记录语法提供证据。添加一个隐式Updater参数来withId满足编译器,这样下面的代码会编译,但它不可用。
import shapeless._, record._, ops.record._, labelled._, syntax.singleton._, tag._
abstract class Model[A](implicit gen: LabelledGeneric[A] { type Repr <: HList }) { this: A => …Run Code Online (Sandbox Code Playgroud) 使用Shapeless,我试图获得一个Generic[F]通道:
import shapeless._
class F(x: Int)
Run Code Online (Sandbox Code Playgroud)
但它失败了:
scala> Generic[F]
<console>:20: error: could not find implicit value for parameter gen: shapeless.Generic[F]
Generic[F]
^
Run Code Online (Sandbox Code Playgroud)
可以无形生产Generic[F]?如果是这样,怎么样?
在我的应用程序中,我有很多地方,我需要获取元组列表,groupBy它由元组的第一个元素,并从其余元素中删除.例如,我有元组
(1, "Joe", "Account"), (1, "Tom", "Employer"), (2, "John", "Account"), and result should be Map(1 -> List(("Joe", "Account"), ("Joe", "Account")), 2 -> List(("John", "Account")))
Run Code Online (Sandbox Code Playgroud)
它很容易实现
data.groupBy(_._1).map { case (k, v) => k -> v.map(f => (f._2, f._3)) }
Run Code Online (Sandbox Code Playgroud)
但我正在寻找一般的解决方案,因为我可以有不同的元素,2,3,4或甚至7的元组.我认为Shapeless或Scalaz可以帮助我,但我在这些库中的经验很少,请指出一些例子
shapeless是否提供了一个类型类/宏来召唤一个HList包含案例类所有参数的默认值?
假设我们有这个案例类:
case class User(name: String, age: Int = 18)
Run Code Online (Sandbox Code Playgroud)
然后我想得到这样一个HList:
None :: Some(() => 18) :: HNil
Run Code Online (Sandbox Code Playgroud) 我正在尝试实现用于获取第一个元素的通用函数:
import shapeless.ops.hlist.IsHCons
import shapeless.{Generic, HList}
object App {
def main(args : Array[String]) {
val a: Int = getFirst((1, 2, 3))
val b: String = getFirst(("a", "b", 10, 45, "aaa"))
}
def getFirst[A, Head, Repr <: HList, Tail <: HList](input: A)
(implicit hcons: IsHCons.Aux[Repr, Head, Tail],
gen: Generic.Aux[A, Repr]): Head = gen.to(input).head
}
Run Code Online (Sandbox Code Playgroud)
问题是编译器无法正确推断Repr并将Tail它们设置为Nothing. 就这个:
Error:(9, 26) could not find implicit value for parameter gen: shapeless.Generic.Aux[(Int, Int, Int),Repr]
val a: Int = getFirst((1, 2, …Run Code Online (Sandbox Code Playgroud) functional-programming scala generic-programming type-level-computation shapeless
不确定正确的术语是否是“分配财产”,但我记得在学校学过这个,所以这里是我想做的一个例子:
鉴于:
type MyHList = (A :+: B :+: C :+: CNil) :: (Foo :+: Bar :+: CNil) :: HNil
Run Code Online (Sandbox Code Playgroud)
Shapeless 中是否有任何内置类型类可以解决这个问题:
type Out = (A, Foo) :+: (A, Bar) :+: (B, Foo) :+: (B, Bar) :+: (C, Foo) :+: (C, Bar) :+: CNil
Run Code Online (Sandbox Code Playgroud)
?
谢谢
我正在尝试在Miles Sabin的博客文章中定义的Scala的联合类型:
http://www.chuusai.com/2011/06/09/scala-union-types-curry-howard/
并在中讨论过
对于那里定义的简单情况,它们工作正常,但我要做的是使用它们在Play Framework中创建一个只接受某些值(String,Boolean,Int,Undefined)的通用JSON解析器,然后成功传递它们.
这是我的代码:
type UpdateType = Option[String] |?| Option[Int] |?| Option[Boolean] |?| Option[List[Int]]
def withValue[T : (UpdateType)#?](request: Request[JsValue])(block: (String, T) => Future[SimpleResult]) = {
val field = request.body \ ("field")
val value = request.body \ ("value")
(field, value) match {
case (x: JsString, y: JsString) => block(x.value.toString, Some(y.value.toString))
case (x: JsString, y: JsNumber) => block(x.value.toString, Some(y.value.intValue))
case (x: JsString, y: JsBoolean) => block(x.value.toString, Some(y.value.booleanValue))
case (x: JsString, y: JsUndefined) => block(x.value.toString, None)
case _ => …Run Code Online (Sandbox Code Playgroud) 作为一个练习,我试图看看我是否可以List[Any]使用无形的方法将其"投射"到案例类中.
我想要实现的一个非常基本的例子:
case class Foo(i: Int, j: String)
val foo: Option[Foo] = fromListToCaseClass[Foo]( List(1:Any, "hi":Any) )
Run Code Online (Sandbox Code Playgroud)
以下是我如何塑造我的解决方案(这可能非常不合适):
def fromListToCaseClass[CC <: Product](a: List[Any]): Option[CC] = a.toHList[???].map( x => Generic[CC].from(x) )
Run Code Online (Sandbox Code Playgroud)
这是我的推理:
我知道你可以从case类转到HList [T](CC - > HList [T]); 其中T是HList的类型.我也知道你可以从列表中创建一个HList(list - > Option [HList]),只要你知道HList的类型.最后我知道你可以从HList转到案例类(HList - > CC).
CC -> HList[T]
list -> Option[HList[T]] -> Option[CC]
Run Code Online (Sandbox Code Playgroud)
我想知道这是否有意义,或者我是否离开这里.我们能做到这一点吗?还有其他建议吗?谢谢!
我发现了两种可以在无形副产品上进行模式匹配的方法.我也搜索了这个主题并找到了这个
import shapeless._
object ShapelessEx3 extends App {
case class Red()
case class Green()
case class Blue()
type Colors = Red :+: Green :+: Blue :+: CNil
val blue = Coproduct[Colors](Blue())
val green = Coproduct[Colors](Green())
printColor1(blue)
printColor2(green)
def printColor1(c: Colors) : Unit = {
(c.select[Red], c.select[Green], c.select[Blue]) match {
case (Some(_), None, None) => println("Color is red")
case (None, Some(_), None) => println("Color is green")
case (None, None, Some(_)) => println("Color is blue")
case _ => println("unknown color")
} …Run Code Online (Sandbox Code Playgroud) 假设我有一个case类定义如下:
case class User(name: String, age: Int)
Run Code Online (Sandbox Code Playgroud)
我想像这样重写它的toString方法:
case class User(name: String, age: Int) {
override def toString: String =
s"name = $name
age = $age"
Run Code Online (Sandbox Code Playgroud)
这样,如果我跑步print(user.toString),我会得到:
name = nameOfUser
age = ageOfUser
Run Code Online (Sandbox Code Playgroud)
现在我有另一个类Computer,它被定义为
case class Computer(make: String, RAM: int, clockSpeed: Double)
Run Code Online (Sandbox Code Playgroud)
我想为所有值打印相同的内容。我想要类似的东西:
make = makeOfComputer
RAM = RAMOfComputer
clockSpeed = speedOfComputer
Run Code Online (Sandbox Code Playgroud)
与其将上面的toString函数复制,粘贴和调整到Computer该类中,不如将其抽象化,以便任何case类都可以使用它。
我有一些想法可以使用
CaseClassType.unapply(caseClassInstance).get.productIterator.toList
Run Code Online (Sandbox Code Playgroud)
获取案例类的值,并
classOf[CaseClass].getDeclaredFields.map(_.getName)
Run Code Online (Sandbox Code Playgroud)
获取字段名称。这意味着我可以在不知道案例类的实际结构的情况下,找到案例类中所有值的列表以及所有字段名称的列表。
一旦有了这两个集合,就可以递归地遍历它们来创建字符串。我在想像下面这样的东西可以工作,但是不幸的是,scala不允许案例类继承自其他案例类。
case class StringifiableCaseClass(){
override def toString: String =
//get the values …Run Code Online (Sandbox Code Playgroud) 考虑在无形状回购中找到的单例函数的定义:
/** Polymorphic function selecting an arbitrary element from a non-empty `Set`. */
object choose extends (Set ~> Option) {
def apply[T](s : Set[T]) = s.headOption
}
Run Code Online (Sandbox Code Playgroud)
def在以下示例中,将其与传统语法进行对比:
package utils
object UtilWithASingleMethod {
def isSatisfyingSomePredicate(foo: Foo): Boolean = ???
}
Run Code Online (Sandbox Code Playgroud)
与
package utils
object isSatisfyingSomePredicate extends (Foo => Boolean) {
def apply(foo: Foo): Boolean = ???
}
Run Code Online (Sandbox Code Playgroud)
注意呼叫站点现在如何变成
isSatisfyingSomePredicate(foo)
Run Code Online (Sandbox Code Playgroud)
代替
UtilWithASingleMethod.isSatisfyingSomePredicate(foo)
Run Code Online (Sandbox Code Playgroud)
要么
import UtilWithASingleMethod._
isSatisfyingSomePredicate(foo)
Run Code Online (Sandbox Code Playgroud)
就个人而言,UtilWithASingleMethod软件包似乎只是为了能够使用熟悉的def语法而没有添加任何有用的信息。
除了主观的缺点(例如不熟悉或与工厂模式中使用的对象+应用样式混淆)之外,单例函数定义还有其他技术缺点吗?
标题可能很模糊,但这是代码: https: //github.com/amorfis/why-no-implicit
所以有一个工具可以转化Map[String, Any]为简单的案例类。测试通过了,这段代码说明了它的全部内容:
case class TargetData(
groupId: String,
validForAnalysis: Boolean,
applicationId: Int
)
val map = Map(
"groupId" -> "123456712345",
"applicationId" -> 31,
"validForAnalysis" -> true
)
val transformed: TargetData = MapDecoder.to[TargetData](map).transform
Run Code Online (Sandbox Code Playgroud)
这段代码有效。当提供简单的情况时,它很好地创建了案例类实例map
但是,该transform方法必须在“外部”调用 - 就像示例中一样。当我尝试将其移至该MapDecoder.to方法时 - 编译器抱怨缺少隐式。
所以我将代码更改MapDecoder.to为:
def to[A](map: Map[String, Any]) = new MapDecoderH[A](map)
Run Code Online (Sandbox Code Playgroud)
对此:
def to[A](map: Map[String, Any]) = new MapDecoderH[A](map).transform
Run Code Online (Sandbox Code Playgroud)
它停止工作了。这是为什么?为什么在一种情况下提供了隐含的内容,而在另一种情况下则没有提供?所有的变化是我想transform在其他地方调用该方法以MapDecoder.to返回案例类而不是某个转换器。
更新:
to[A]如果我想在要转换的对象内实现方法怎么办?让我们称之为DataFrame,我希望这段代码能够工作:
val df: DataFrame = ... …Run Code Online (Sandbox Code Playgroud)