I am trying to convert the following rule from Parboiled v1 (Java) to v2 (Scala):
Rule SlopProximity() {
Var<ProximityMode> proximityMode = new Var<>(ProximityMode.NORMAL);
Var<Boolean> direct = new Var<>(true);
StringVar slop = new StringVar();
return Sequence(Optional(
FirstOf(
Sequence('!', proximityMode.set(ProximityMode.ANTI)),
Sequence('-', direct.set(false)))
),
Optional(Sequence(Slop(), slop.set(match()))),
FirstOf(
Sequence(IgnoreCase("WS"),
push(Builder.createWS(slop, direct.get(), proximityMode.get()))),
Sequence(IgnoreCase("W"),
push(Builder.createW(slop, direct.get(), proximityMode.get())))
));
}
I have no experience with Scala. I have come up with a following version:
class SlopParser(val input: ParserInput) extends Parser {
def SlopProximity = rule {
class State(var direct: Boolean, var proximityMode: ProximityMode)
push(new State(true, ProximityMode.NORMAL)) ~
optional(
ch('!') ~> (() => valueStack.peek.asInstanceOf[State].proximityMode = ProximityMode.ANTI) |
ch('-') ~> (() => valueStack.peek.asInstanceOf[State].direct = false)
) ~
optional(Slop) ~ (
ignoreCase("WS") ~> ((slop: Option[String], state: State) => Builder.createWS(slop, state.direct, state.proximityMode)) |
ignoreCase("W") ~> ((slop: Option[String], state: State) => Builder.createW(slop, state.direct, state.proximityMode))
)
}
def Slop = rule {
ch('0') | CharPredicate.Digit19 ~ zeroOrMore(CharPredicate.Digit)
}
}
but it does not compile:
[ERROR] C:/Workspace/src/main/scala/org/SlopParser.scala:23: Invalid rule definition: {
class State extends scala.AnyRef {
<paramaccessor> private[this] var direct: Boolean = _;
<accessor> <paramaccessor> def direct: Boolean = State.this.direct;
<accessor> <paramaccessor> def direct_=(x$1: Boolean): Unit = State.this.direct = x$1;
<paramaccessor> private[this] var proximityMode: org.model.ProximityMode = _;
<accessor> <paramaccessor> def proximityMode: org.model.ProximityMode = State.this.proximityMode;
<accessor> <paramaccessor> def proximityMode_=(x$1: org.model.ProximityMode): Unit = State.this.proximityMode = x$1;
def <init>(direct: Boolean, proximityMode: org.model.ProximityMode): State = {
State.super.<init>();
()
}
};
PQLOperatorParser3.this.push[State](new State(true, NORMAL))(support.this.HListable.fromAnyRef[State]).~[org.parboiled2.support.hlist.HNil, org.pa...
}
[ERROR] one error found
Any suggection how to fix above is welcomed.
Additionally:
When I remove ch() call in the rule, it does not compile, however from this example I see that it should be possible:
optional(
'!' ~> (...) |
'-' ~> (...)
)
I would expect that the order of arguments in action should be reversed, but this way it does not compile:
ignoreCase("WS") ~> ((state: State, slop: Option[String]) => ...)
Would be nice to know if the rule can be implemented without State class just by having all values on the stack:
push(true) ~ push(ProximityMode.NORMAL) ~
optional(
ch('!') ~> ((proximityMode: ProximityMode) => ProximityMode.ANTI) |
ch('-') ~> ((direct: Boolean, proximityMode: ProximityMode) => false :: proximityMode :: HNil)
) ~
however it results the following error:
The `optional`, `zeroOrMore`, `oneOrMore` and `times` modifiers can only be used on rules of type `Rule0`, `Rule1[T]` and `Rule[I, O <: I]`!
Related
I am trying to create a generic class that only accepts java.math.BigDecimal or Long. Here is the code:
class myClass[T]()
{
def display( x : T) = {
println(x.doubleValue())
}
}
val input = new java.math.BigDecimal(100)
// val input = 100L
val x = new myClass[java.math.BigDecimal]()
x.display(input)
Clearly I will have this error: ScalaFiddle.scala:22: error: value doubleValue is not a member of type parameter T.
I tried playing with implicit conversion, view bound, and context bound for hours. No result so far. Is there any way I can force Scala to believe me that T has method .doubleValue()? (java.big.Decimal and Long both has .doubleValue() method, but they don't share same super-class)
Try structural type bound
class myClass[T <: {def doubleValue(): Double}]
or type class
trait HasDoubleValue[T] {
def doubleValue(t: T): Double
}
object HasDoubleValue {
implicit val long: HasDoubleValue[Long] = t => t.doubleValue
implicit val bigDecimal: HasDoubleValue[BigDecimal] = t => t.doubleValue
}
implicit class DoubleValueOps[T: HasDoubleValue](x: T) {
def doubleValue(): Double = implicitly[HasDoubleValue[T]].doubleValue(x)
}
class myClass[T: HasDoubleValue]
In Dotty (Scala 3) we might use union types, for example,
class myClass[T <: (Long | java.math.BigDecimal)]() {
def display(x: T) =
println(
x match {
case t: Long => t.doubleValue
case t: java.math.BigDecimal => t.doubleValue
}
)
}
new myClass().display(new java.math.BigDecimal(100)) // OK
new myClass().display(100L) // OK
new myClass().display("100") // Error
scala> class C private (n: Number) {
| def this(i: Long) = this(i: Number)
| def this(b: BigDecimal) = this(b: Number)
| def d = n.doubleValue
| }
defined class C
scala> new C(42L).d
res0: Double = 42.0
scala> new C(BigDecimal("123456789")).d
res1: Double = 1.23456789E8
or with a type parameter
scala> class C[A <: Number] private (n: A) { def d = n.doubleValue ; def a = n } ; object C {
| def apply(i: Long) = new C(i: Number) ; def apply(b: BigDecimal) = new C(b) }
defined class C
defined object C
I want to implement generic and typesafe domain repository. Say I have
trait Repo[Value] {
def put(value: Value): Unit
}
case class IntRepo extends Repo[Int] {
override def put(value: Int): Unit = ???
}
case class StringRepo extends Repo[String] {
override def put(value: String): Unit = ???
}
case class DomainRepo(intRepo: IntRepo, stringRepo: StringRepo) {
def putAll[?](values: ?*): Unit // what type should be here?
}
As result I want to have following api:
domainRepo.putAll(1, 2, 3, "foo", "bar") //Should work
domainRepo.putAll(1, 2, true, "foo") // should not compile because of boolean value
The question is How to achieve this?
so, I see only one way to make it typesafe. It's to do pattern matching on Any type like
def putAll(values: Seq[Any]) => Unit = values.foreach {
case str: String => stringRepo.put(str)
case int: Int => intRepo.put(int)
case _ => throw RuntimeException // Ha-Ha
}
but what if I would have 10000 of types here? it would be a mess!
another not clear for me approach for now is to use dotty type | (or) like following:
type T = Int | String | 10000 other types // wouldn't be a mess?
def putAll(t: T*)(implicit r1: Repo[Int], r2: Repo[String] ...) {
val myTargetRepo = implicitly[Repo[T]] // would not work
}
so, what do you think? is it even possible?
the easies way I've saw was
Map[Class[_], Repo[_]]
but this way allows to do a lot of errors
It seems you are looking for a type class
trait Repo[Value] {
def put(value: Value): Unit
}
implicit val intRepo: Repo[Int] = new Repo[Int] {
override def put(value: Int): Unit = ???
}
implicit val stringRepo: Repo[String] = new Repo[String] {
override def put(value: String): Unit = ???
}
case object DomainRepo {
def putAll[Value](value: Value)(implicit repo: Repo[Value]): Unit = repo.put(value)
}
If you want domainRepo.putAll(1, 2, 3, "foo", "bar") to compile and domainRepo.putAll(1, 2, true, "foo") not to compile, you can try to use heterogeneous collection (HList).
import shapeless.{HList, HNil, ::, Poly1}
import shapeless.ops.hlist.Mapper
trait Repo[Value] {
def put(value: Value): Unit
}
implicit val intRepo: Repo[Int] = new Repo[Int] {
override def put(value: Int): Unit = ???
}
implicit val stringRepo: Repo[String] = new Repo[String] {
override def put(value: String): Unit = ???
}
case object DomainRepo {
def put[Value](value: Value)(implicit repo: Repo[Value]): Unit = repo.put(value)
object putPoly extends Poly1 {
implicit def cse[Value: Repo]: Case.Aux[Value, Unit] = at(put(_))
}
def putAll[Values <: HList](values: Values)(implicit
mapper: Mapper[putPoly.type, Values]): Unit = mapper(values)
}
DomainRepo.putAll(1 :: 2 :: 3 :: "foo" :: "bar" :: HNil)
// DomainRepo.putAll(1 :: 2 :: true :: "foo" :: HNil) // doesn't compile
In this snippet y.run doesn't typecheck.
object Test {
type StateStringTask[A] = StateStringT[Task, A]
type StateStringT[M[_], A] = StateT[M, String, A]
val x: Process[Task, Unit] = ???
val y: Process[StateStringTask, Unit] = ???
x.run // This typechecks
y.run // This fails
}
The compiler shows this error:
could not find implicit value for parameter C: scalaz.Catchable[[x]Test.StateStringTask[x]]
Do I have to create a Catchable instance for StateStringTask? How do I do that? Or is there an easier way to handle stateful effects when running a Process?
I guess this is suboptimal but I got it by making StateStringTask an instance of Catchable:
implicit val stateStringTaskInstance: Catchable[StateStringTask] =
new Catchable[StateStringTask] {
// `a.attempt` stackoverflows, don't ask me why :)
def attempt[A](a: StateStringTask[A]): StateStringTask[Throwable \/ A] = a >>= (
x => Catchable[Task].attempt(Applicative[Task].pure(x)).liftM[StateStringT]
)
def fail[A](err: Throwable) = Catchable[Task].fail(err).liftM[StateStringT]
}
To hoist the StateT on a Process with aTask as effect. For example:
def received(queue: Queue[Event]): Process[StateStringTask, Event] = {
val toStateStringTask = new (Task ~> StateStringTask) {
def apply[A](t: Task[A]): StateStringTask[A] = t.liftM[StateStringT]
}
// queue.dequeue: Process[Task, Event]
queue.dequeue.translate(toStateStringTask)
}
Long story short, I'm trying to figure out how to define a function from a generic input to a single-typed output.
The background: This is a continuation of Mapping over Shapeless record. After Travis's excellent answer, I now have the following:
import shapeless._
import poly._
import syntax.singleton._
import record._
type QueryParams = Map[String, Seq[String]]
trait RequestParam[T] {
def value: T
/** Convert value back to a query parameter representation */
def toQueryParams: Seq[(String, String)]
/** Mark this parameter for auto-propagation in new URLs */
def propagate: Boolean
protected def queryStringPresent(qs: String, allParams: QueryParams): Boolean = allParams.get(qs).nonEmpty
}
type RequestParamBuilder[T] = QueryParams => RequestParam[T]
def booleanRequestParam(paramName: String, willPropagate: Boolean): RequestParamBuilder[Boolean] = { params =>
new RequestParam[Boolean] {
def propagate: Boolean = willPropagate
def value: Boolean = queryStringPresent(paramName, params)
def toQueryParams: Seq[(String, String)] = Seq(paramName -> "true").filter(_ => value)
}
}
def stringRequestParam(paramName: String, willPropagate: Boolean): RequestParamBuilder[Option[String]] = { params =>
new RequestParam[Option[String]] {
def propagate: Boolean = willPropagate
def value: Option[String] = params.get(paramName).flatMap(_.headOption)
def toQueryParams: Seq[(String, String)] = value.map(paramName -> _).toSeq
}
}
In reality, the following would be a class constructor that takes this Map read from the query string as a parameter, but for simplicity's sake, I'm just defining a val:
val requestParams = Map("no_ads" -> Seq("true"), "edition" -> Seq("us"))
// In reality, there are many more possible parameters, but this is simplified
val options = ('adsDebug ->> booleanRequestParam("ads_debug", true)) ::
('hideAds ->> booleanRequestParam("no_ads", true)) ::
('edition ->> stringRequestParam("edition", false)) ::
HNil
object bind extends FieldPoly {
implicit def rpb[T, K](implicit witness: Witness.Aux[K]): Case.Aux[
FieldType[K, RequestParamBuilder[T]],
FieldType[K, RequestParam[T]]
] = atField(witness)(_(requestParams))
}
// Create queryable option values record by binding the request parameters
val boundOptions = options.map(bind)
This lets me do:
boundOptions.get('hideAds).value // -> true
The problem: Now I want to be able to reserialize options that have propagate = true. So basically, I need to filter my HList on the propagate field of every member, which should always return a Boolean, and then have each parameter reserialize itself to a Seq[(String, String)]. I've tried the following:
object propagateFilter extends (RequestParam ~> Const[Boolean]) {
override def apply[T](r: RequestParam[T]): Boolean = r.propagate
}
object unbind extends (RequestParam ~> Const[Seq[(String, String)]]) {
override def apply[T](r: RequestParam[T]): Seq[(String, String)] = r.toQueryParams
}
// Reserialize a query string for options that should be propagated
val propagatedParams = boundOptions.values.filter(propagateFilter).map(unbind).toList
// (followed by conventional collections methods)
, but it doesn't like my functions. I got the following error:
<console>:31: error: type mismatch;
found : Boolean
required: shapeless.Const[T]
(which expands to) AnyRef{type λ[T] = T}
override def apply[T](r: RequestParam[T]) = r.propagate
I believe I'm taking the wrong approach to a function that's supposed to have a polymorphic input but monomorphic output.
Other failed attempts:
object propagateFilter extends Poly1 {
implicit def default[T](implicit st: Case.Aux[RequestParam[T], Boolean]) = at[RequestParam[T]](_.propagate)
}
and
def propagate[T](x: RequestParam[T]): Boolean = x.propagate
and
object propagateFilter extends Poly1 {
implicit def default = at[RequestParam[_]](_.propagate)
}
and
object propagateFilter extends FieldPoly {
implicit def rpb[T, K](implicit witness: Witness.Aux[K]): Case.Aux[
FieldType[K, RequestParam[T]],
Boolean
] = atField(witness)(_.propagate)
}
None of which work, probably due to my own misunderstanding of what's going on.
I have been searching the forum and Google for answers to type erasure issues for Scala. However, I cannot find anything that answers my question.
I struggling with pattern matching on objects that match the type parameter of ParamClass. I need to pattern match on the type of incoming objects to the bar method. I have seen solutions such as
bar[X](a : X)(implicit m : Manifest[X])
which would solve my problem, but I cannot use this as the bar method is an overridden method. (Actually is the receive partial function in the Akka actor framework). The code is given below and should be self explanatory:
class ParamClass[A : Manifest] {
def bar(x : Any) = x match {
case a: A => println("Found A: " + a)
case _ => println("No match: " + x)
}
}
object ErasureIssue {
def main(args: Array[String]) {
val clz = new ParamClass[Int]
clz.bar("faf")
clz.bar(2.3)
clz.bar(12) // this should match, but does not
}
}
ErasureIssue.main(null)
Any help on solving this issue is greatly appreciated. I'm using Scala 2.9.1, BTW.
-J
In theory you could check in bar like this: x.getClass == implicitly[Manifest[A]].erasure, but that fails for primitive types such as Int for which the manifest correctly erases to Int, but bar is called with boxed type java.lang.Integer ... :-(
You could require A to be an AnyRef in order to get the boxed manifest:
class ParamClass[A <: AnyRef : Manifest] {
def bar(x : Any) = x match {
case _ if x.getClass == implicitly[Manifest[A]].erasure =>
println("Found A: " + x.asInstanceOf[A])
case _ => println("No match: " + x)
}
}
object ErasureIssue {
def main(args: Array[String]) {
val clz = new ParamClass[Integer] // not pretty...
clz.bar("faf")
clz.bar(2.3)
clz.bar(12) // ok
}
}
ErasureIssue.main(null)
Given your requirement to construct primitive arrays, you could store directly the boxed class, independently of the unboxed manifest:
object ParamClass {
def apply[A](implicit mf: Manifest[A]) = {
val clazz = mf match {
case Manifest.Int => classOf[java.lang.Integer] // boxed!
case Manifest.Boolean => classOf[java.lang.Boolean]
case _ => mf.erasure
}
new ParamClass[A](clazz)
}
}
class ParamClass[A] private[ParamClass](clazz: Class[_])(implicit mf: Manifest[A]) {
def bar(x : Any) = x match {
case _ if x.getClass == clazz =>
println("Found A: " + x.asInstanceOf[A])
case _ => println("No match: " + x)
}
def newArray(size: Int) = new Array[A](size)
override def toString = "ParamClass[" + mf + "]"
}
val pi = ParamClass[Int]
pi.bar("faf")
pi.bar(12)
pi.newArray(4)
val ps = ParamClass[String]
ps.bar("faf")
ps.bar(12)
ps.newArray(4)
If you try to compile with -unchecked, you immediately get the warning.
test.scala:3: warning: abstract type A in type pattern A is unchecked
since it is eliminated by erasure
case a: A => println("Found A: " + a)
If you now want to go deeper, you can use scalac -print
[[syntax trees at end of cleanup]]// Scala source: test.scala
package <empty> {
class ParamClass extends java.lang.Object with ScalaObject {
def bar(x: java.lang.Object): Unit = {
<synthetic> val temp1: java.lang.Object = x;
if (temp1.$isInstanceOf[java.lang.Object]())
{
scala.this.Predef.println("Found A: ".+(temp1))
}
else
{
scala.this.Predef.println("No match: ".+(x))
}
};
def this(implicit evidence$1: scala.reflect.Manifest): ParamClass = {
ParamClass.super.this();
()
}
};
final object ErasureIssue extends java.lang.Object with ScalaObject {
def main(args: Array[java.lang.String]): Unit = {
val clz: ParamClass = new ParamClass(reflect.this.Manifest.Int());
clz.bar("faf");
clz.bar(scala.Double.box(2.3));
clz.bar(scala.Int.box(12))
};
def this(): object ErasureIssue = {
ErasureIssue.super.this();
()
}
}
}
Now seeing this code you can see that your A has turned into a java.lang.Object, which cause all the parameters to match the clause