我正在使用Scala中的事件库.在我的库中,您可以定义如下事件:
val e1 = new ImperativeEvent[Int]
Run Code Online (Sandbox Code Playgroud)
您可以像这样触发它们:
e1(42)
Run Code Online (Sandbox Code Playgroud)
你可以创建这样的反应:
val r1 = (i: Int) => println(i)
Run Code Online (Sandbox Code Playgroud)
并将它们附加到这样的事件:
e1 += r1
Run Code Online (Sandbox Code Playgroud)
还有一些其他的东西(比如事件转换,组合等).我使用Esper CEP引擎作为我的库的后端.对于大多数操作,Esper使用类似SQL的语言EPL.
我正在尝试实现一些更高级的概念,如事件连接.所以现在你可以用这样的多个属性定义事件(使用元组类型):
val e2 = new ImperativeEvent[(Int, String)]
Run Code Online (Sandbox Code Playgroud)
然后像这样加入他们:
val e3 = e1 join e2 windowLength (30) on "E1.P1 = E2.P1"
Run Code Online (Sandbox Code Playgroud)
在它们各自的第一属性相等的条件下,它们在两者的最后30次出现上执行e1和e2的连接.
这没关系,但我想摆脱我的实现中的字符串,使事件表达式类型可检查.我想将连接表达式更改为以下内容:
val e3 = e1 join e2 windowLength (30) on e1._1 === e2._1
Run Code Online (Sandbox Code Playgroud)
类似于在例如中完成的方式.Squeryl.这个问题是,我无法访问元组类型元素的类型......
如何静态访问元组类型?现在我只能通过反射在运行时访问它们,这对我没有帮助.我很确定我想要实现的是元组不可能实现的,但我想知道是否使用无形库中的HLists或类似的东西可能有助于实现我的目标.
我如何通过一些HList作为参数?所以我可以这样做:
def HFunc[F, S, T](hlist: F :: S :: T :: HNil) {
// here is some code
}
HFunc(HList(1, true, "String")) // it works perfect
Run Code Online (Sandbox Code Playgroud)
但是,如果我有一个很长的清单,我不知道它,我怎么能对它做一些操作?我如何通过论证而不是松散其类型?
我想了解Shapeless,我遇到了这个:
// Base trait for type level natural numbers.
trait Nat {
type N <: Nat
}
// Encoding of successor.
case class Succ[P <: Nat]() extends Nat {
type N = Succ[P]
}
// Encoding of zero.
class _0 extends Nat {
type N = _0
}
Run Code Online (Sandbox Code Playgroud)
_0是一个特殊而独特的案例,就像Nil一个List._0没有前任.为什么它不是一个对象/案例对象(单例)? HList似乎这样做:
// `HList` ADT base trait.
sealed trait HList
// Non-empty `HList` element type.
final case class ::[+H, +T <: HList](head : H, …Run Code Online (Sandbox Code Playgroud) 我正在编写用于处理案例类实例列表的通用代码,在每个字段中收集值,组合然后将其传递给库.
使用无形LabelledGeneric和多态函数,它看起来像这样:
object toNamedSingletonListOfValues extends Poly1 {
implicit def caseField[K,T] =
at[FieldType[K, T]](field => { field.key -> List[T](field) })
}
val generic = LabelledGeneric[MyClass]
val records = listOfMyClassInstances.map(generic.to)
val values = records.map(_.map(toNamedSingletonListOfValues)) // Then combining and passing
Run Code Online (Sandbox Code Playgroud)
但是,我需要一种获取方式,field.key因为库需要参数名称.
你介意建议解决方案吗?
我开始时有这样的事情:
def nonEmpty[A] = (msg: String) => (a: Option[A]) => a.toSuccess(msg)
val postal: Option[String] = request.param("postal")
val country: Option[String] = request.param("country")
val params =
(postal |> nonEmpty[String]("no postal" )).toValidationNel |@|
(country |> nonEmpty[String]("no country")).toValidationNel
params { (postal, country) => ... }
Run Code Online (Sandbox Code Playgroud)
现在我认为减少样板以获得更好的可读性并且不必向更多的初级团队成员解释什么.toValidateNel和|@|意思是很好的.第一个想法是,List但最后一行将停止工作,我不得不放弃一些静态安全.所以我看向无形:
import shapeless._; import poly._; import syntax.std.tuple._
val params = (
postal |> nonEmpty[String]("no postal"),
country |> nonEmpty[String]("no country")
)
params.map(_.toValidatioNel).reduce(_ |@| _)
Run Code Online (Sandbox Code Playgroud)
然而,我似乎无法超越这.map(...)一点.我按照#scalaz的建议尝试过:
type Va[+A] = Validation[String, A]
type VaNel[+A] …Run Code Online (Sandbox Code Playgroud) 我想将两个不同案例类的字段合并为一个案例类.
例如,如果我有以下案例类:
case class Test(name:String, questions:List[Question], date:DateTime)
case class Answer(answers:List[Answers])
Run Code Online (Sandbox Code Playgroud)
我想要一个简洁的无形方式将两者合并为:
TestWithAnswers(name:String, questions:List[Question], date:DateTime, answers:List[Answer]).
Run Code Online (Sandbox Code Playgroud)
那里有一个很好的无形答案吗?
问题1 - 基本LUBConstraints
我第一次尝试使用现有的LUBConstraints失败,因为缺少证据(参见下面的代码块).任何暗示为什么?空列表不是有效的长列表吗?没有元素违反约束.
import shapeless.ops.coproduct
import shapeless.{::, :+:, Coproduct, HNil, HList}
object testLUBConstraints {
import shapeless.LUBConstraint._
// !!! see comment on question - this satisfies the implicit below!!!
// implicit val hnilLUBForLong = new LUBConstraint[HNil.type, Long] {}
def acceptLong[L <: HList : <<:[Long]#?](l: L) = true
val validLong = acceptLong(1l :: HNil)
val validEmpty = acceptLong(HNil)
// => WHY??? Error: could not find implicit value for evidence parameter of type shapeless.LUBConstraint[shapeless.HNil.type,Long]
// MY EXPECTATION WAS: 'implicit def hnilLUB[T] = …Run Code Online (Sandbox Code Playgroud) 正如我所知,无形提供了HList(异类列表)类型,它可以包含多种类型.
可折叠HList吗?例如,
// ref - Composable application architecture with reasonably priced monad
// code - https://github.com/stew/reasonably-priced/blob/master/src/main/scala/reasonable/App.scala
import scalaz.{Coproduct, Free, Id, NaturalTransformation}
def or[F[_], G[_], H[_]](f: F ~> H, g: G ~> H): ({type cp[?] = Coproduct[F,G,?]})#cp ~> H =
new NaturalTransformation[({type cp[?] = Coproduct[F,G,?]})#cp,H] {
def apply[A](fa: Coproduct[F,G,A]): H[A] = fa.run match {
case -\/(ff) ? f(ff)
case \/-(gg) ? g(gg)
}
}
type Language0[A] = Coproduct[InteractOp, AuthOp, A]
type Language[A] = Coproduct[LogOp, Language0, …Run Code Online (Sandbox Code Playgroud) 我有以下问题,我想将HList的项目映射到另一个HList,但如果"目标"类型是URL,则源HList中的字符串应仅转换为URL.
val name = "Stackoverflow"
val url = "https://stackoverflow.com/q"
val list = name :: url :: HNil
val mapped: String :: URL :: HNil = list.map(???)
Run Code Online (Sandbox Code Playgroud)
据我所知,我所有的Poly材料只关心输入类型,而不关心输出类型.那么有没有办法存档我的目标?
我可以很容易地为一个密封的案例类家族推导出一个编解码器,如下所示:
import io.circe._
import io.circe.generic.auto._
sealed trait Base
case class X(x: Int) extends Base
case class Y(y: Int) extends Base
object Test extends App {
val encoded = Encoder[Base].apply(Y(1))
val decoded = Decoder[Base].apply(encoded.hcursor)
println(decoded) // Right(Y(1))
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我将类型成员添加到基类中,我就不能再这样做了,即使它受到密封特性的限制:
import io.circe._
import io.circe.generic.auto._
sealed trait Inner
case class I1(i: Int) extends Inner
case class I2(s: String) extends Inner
sealed trait Base { type T <: Inner }
case class X[S <: Inner](x: S) extends Base { final type T = S …Run Code Online (Sandbox Code Playgroud)