I'm trying to wrap my head around how Spray has implemented their Directives, and in particular the Parameter extraction DSL.
I understand the magnet pattern (barely) but am stuck on how the ParamDefMagnet and ParamDefMagnet2 work together.
def parameter(pdm: ParamDefMagnet): pdm.Out = pdm()
trait ParamDefMagnet {
type Out
def apply(): Out
}
trait ParamDefMagnet2[T] {
type Out
def apply(value: T): Out
}
type ParamDefMagnetAux[A, B] = ParamDefMagnet2[A] { type Out = B }
def ParamDefMagnetAux[A, B](f: A ⇒ B) = new ParamDefMagnet2[A] { type Out = B; def apply(value: A) = f(value) }
I'm trying to work out how a ParamDefManget2 is implicitly converted to a ParamDefMagnet by the the below implicit method.
object ParamDefMagnet {
implicit def apply[T](value: T)(implicit pdm2: ParamDefMagnet2[T]) = new ParamDefMagnet {
type Out = pdm2.Out
def apply() = pdm2(value)
}
}
If i call parameter("name"), how is "name" implicitly converted to a ParamDefMagnet? And if it converts it to a ParamDefMagnet2 first, then where does value: T come from in order to convert it to a ParamDefMagnet?
So after digging around with examples, I think i've finally got to the bottom of how the parameter function works:
def parameter(pdm: ParamDefMagnet): pdm.Out = pdm()
An example for extracting a parameter of type String:
val p: Directive1[String] = parameter("name")
// we can then apply the function with the extracted name
p { name =>
// stuff
}
Spray uses a bunch of implicit conversions but basically, if you have a String and a String => Directive1[String], you can construct a () => Directive1[String]:
// Our String => Directive1[String]
val pdm2: ParamDefMagnet2[String] { type Out = Directive1[String] } = ParamDefMagnet2.fromString
// Our () => Directive1[String]
val pdm: ParamDefMagnet { type Out = Directive1[String] } = new ParamDefMagnet {
type Out = Directive1[String]
def apply() = pdm2("name")
}
val directive: Directive1[String] = pdm()
// equivalent to:
val directive2: Directive1[String] = parameter("name")
All of this is what constitutes the simple parameter("name") call:
val p: Directive1[String] = parameter("name")
For how a Directive1[String] is applied in a DSL-ey way, see How do directives work in Spray?
Related
If we define the following function:
def methodWithImplicit(explicit: String)(implicit imp: String) = {
println(explicit + imp)
}
we can call it as follows:
methodWithImplicit("abc")("efg") //abc - explicit, efg - imp
And it works fine. Now consider the following TypeClass:
trait MyTypeClass[T] {
def accept(t: T): T
}
which is going to be used inside extractor object:
object TestExtractor {
def unapply(str: String)(implicit myTypeClass: MyTypeClass[String]): Option[String] =
if (!str.isEmpty)
Some(myTypeClass.accept(str))
else
None
}
So if we use it as follows:
implicit val myTypeClass:MyTypeClass[String] = new MyTypeClass[String] {
override def accept(t: String): Unit = t
}
"123" match {
case TestExtractor(str) => println(str)
}
It works ok. But how to pass the parameter explicitly when using with pattern matching? I tried
"123" match {
case TestExtractor(str)(myTypeClass) => println(str) //compile error
}
and
"123" match {
case TestExtractor(myTypeClass)(str) => println(str) //compile error
}
But it does not compile.
Since the left hand side seems to accept essentially nothing but trees built from stable identifiers, constant literals, and lower-case letters for variable names, I don't see any way to get closer to the desired syntax than this:
val `TestExtractor(myTypeClass)` = TestExtractor(myTypeClass)
"hello" match {
case `TestExtractor(myTypeClass)`(str) => println(str)
}
This of course requires that you define the weirdly named value TestExtractor(myTypeClass) (in backticks) right before the match-case, so you can use it as a single symbol.
Full code:
trait MyTypeClass[T] {
def accept(t: T): T
}
object TestExtractor { outer =>
def unapply(str: String)(implicit myTypeClass: MyTypeClass[String]): Option[String] =
if (!str.isEmpty)
Some(myTypeClass.accept(str))
else
None
class ExplicitTestExtractor(tc: MyTypeClass[String]) {
def unapply(t: String) = outer.unapply(t)(tc)
}
def apply(tc: MyTypeClass[String]): ExplicitTestExtractor =
new ExplicitTestExtractor(tc)
}
implicit val myTypeClass:MyTypeClass[String] = new MyTypeClass[String] {
override def accept(t: String): String = t.toUpperCase
}
val `TestExtractor(myTypeClass)` = TestExtractor(myTypeClass)
"hello" match {
case `TestExtractor(myTypeClass)`(str) => println(str)
}
How to use the map method in the Iterable trait in the example below?
As I understand this method will return a function which I have to call to execute internal logic.
trait Container[E] {
def += (e: E): Unit
}
trait Iterable[E, C[X] <: Container[X]]
{
def iterator(): Iterator[E]
def build[F](): C[F]
def map[F](f : (E) => F) : C[F] = {
val res = build[F]()
val iter = iterator()
while (iter.hasNext) res += f(iter.next())
res
}
}
class Buffer[T] extends Container[T]
{
val list = scala.collection.mutable.ListBuffer.empty[T]
def Children = list
def += (e: T): Unit = list += e
}
class Range(val low: Int, val high: Int) extends Iterable[Int, Buffer] {
def iterator() = new Iterator[Int]
{
private var i = low
def hasNext = i <= high
def next() = { i += 1; i - 1 }
}
def build[F]() = new Buffer[F]
}
val range = new Range(1, 3)
var list = range.map[String](_)
The method in question has the following signature:
trait Iterable[E, C[X] <: Container[X]] {
def map[F](f : (E) => F) : C[F]
// ...
}
First, let's look at the type of f argument. The signature (E) => F says that f is a function which takes a single argument of type E and returns a value of type F. Any function (or method) with this signature can be passed to map() as argument. See also Scala documentation.
Another important thing to understand is that the map function is generic with type parameter F. Value for this type parameter can either be specified manually or inferred by the compiler from the argument passed to map:
new Range(1,2).map[String](_.toString) // F is String
// new Range(1,2).map[Int](_.toString) // F is Int, compilation will fail
val mapFunction: Int => String = _.toString
new Range(1,2).map(mapFunction) // mapFunction is a function from Int to String,
// the compiler infers F is String
Basically, e.g. with Range, you can pass to the map() function any function which takes a single Int parameter (because Range binds E to Int) and returns anything (except for Unit). A few more examples:
val r = Range(1,2)
val v1: Buffer[String] = r.map(_.toString)
val v2: Buffer[Int] = r.map(i => i + 1)
val v3: Buffer[Double] = r.map(Int.int2double)
val i: Int = 1
val v4: Buffer[Int] = r.map(i.max)
As you can see, map() returns type Buffer[F] because that's what Range binds to the C[X] type parameter.
As #vitalii noted, the question is not related to higher-kinded types. For more information about those, check out other questions or blogs.
new Range(2,5).map(_.toString)
Can't I use a generic on the unapply method of an extractor along with an implicit "converter" to support a pattern match specific to the parameterised type?
I'd like to do this (Note the use of [T] on the unapply line),
trait StringDecoder[A] {
def fromString(string: String): Option[A]
}
object ExampleExtractor {
def unapply[T](a: String)(implicit evidence: StringDecoder[T]): Option[T] = {
evidence.fromString(a)
}
}
object Example extends App {
implicit val stringDecoder = new StringDecoder[String] {
def fromString(string: String): Option[String] = Some(string)
}
implicit val intDecoder = new StringDecoder[Int] {
def fromString(string: String): Option[Int] = Some(string.charAt(0).toInt)
}
val result = "hello" match {
case ExampleExtractor[String](x) => x // <- type hint barfs
}
println(result)
}
But I get the following compilation error
Error: (25, 10) not found: type ExampleExtractor
case ExampleExtractor[String] (x) => x
^
It works fine if I have only one implicit val in scope and drop the type hint (see below), but that defeats the object.
object Example extends App {
implicit val intDecoder = new StringDecoder[Int] {
def fromString(string: String): Option[Int] = Some(string.charAt(0).toInt)
}
val result = "hello" match {
case ExampleExtractor(x) => x
}
println(result)
}
A variant of your typed string decoder looks promising:
trait StringDecoder[A] {
def fromString(s: String): Option[A]
}
class ExampleExtractor[T](ev: StringDecoder[T]) {
def unapply(s: String) = ev.fromString(s)
}
object ExampleExtractor {
def apply[A](implicit ev: StringDecoder[A]) = new ExampleExtractor(ev)
}
then
implicit val intDecoder = new StringDecoder[Int] {
def fromString(s: String) = scala.util.Try {
Integer.parseInt(s)
}.toOption
}
val asInt = ExampleExtractor[Int]
val asInt(Nb) = "1111"
seems to produce what you're asking for. One problem remains: it seems that trying to
val ExampleExtractor[Int](nB) = "1111"
results in a compiler crash (at least inside my 2.10.3 SBT Scala console).
I have a Span[A] data type that tracks a minimum and maximum value of type A. Because of this, I require A to have a Scalaz Order instance. Here's what the implementation looks like:
trait Span[A] {
val min: A
val max: A
}
object Span {
def apply[A : Order](id: A): Span[A] = new Span[A] {
override val min = id
override val max = id
}
def apply[A : Order](a: A, b: A): Span[A] = {
val swap = implicitly[Order[A]].greaterThan(a, b)
new Span[A] {
override val min = if (swap) b else a
override val max = if (swap) a else b
}
}
implicit def orderSpanSemigroup[A : Order]: Semigroup[Span[A]] = new Semigroup[Span[A]] {
override def append(f1: Span[A], f2: => Span[A]): Span[A] = {
val ord = implicitly[Order[A]]
Span(ord.min(f1.min, f2.min), ord.max(f1.max, f2.max))
}
}
}
The apply method seems to work as expected, as I can do this:
val a = Span(1) // or Span.apply(1)
It breaks down if I try to map over this value using a functor, for example, an Option[Int]:
val b = 1.some map Span.apply
// could not find implicit value for evidence parameter of type scalaz.Order[A]
However, I can fix the error by using an explicit type parameter:
val c = 1.some map Span.apply[Int]
Why is this happening? Is there a way to avoid this explicit type parameter? I wonder if it's related to this issue as I originally ran into the problem while trying to use my own implicit Order instance. Of course, it's also failing on Int inputs so maybe it's just a limitation of parameterized methods.
I have the following method:
def save(entity: A): Either[List[Error],A] + {....
which I want to test using specs2
I want to test for the existence of a specific error when a required field is not specified, like this:
val noNickname = User(
nickname = "",
name = "new name",
)
noNickname.save must beLeft.like {
case errors => {
atLeastOnceWhen(errors) {
case error => {
error.errorCode must equalTo(Error.REQUIRED)
error.field must equalTo("nickname")
}
}
}
}
It works fine, but I'd like to define my own matcher to make it less verbose, like this:
noNickname.save must haveError.like {
case error => {
error.errorCode must equalTo(Error.REQUIRED)
error.field must equalTo("nickname")
}
}
}
I had a look at the documentation (http://etorreborre.github.com/specs2/guide/org.specs2.guide.Matchers.html#Matchers) but I can't figure out how to define a custom matcher like haveError.like
Here your code with a few changes to make it compile:
case class Error(errorCode: String, field: String)
def save[A](entity: A): Either[List[Error],A] = Left(List(Error("REQUIRED", "nickname")))
case class User(nickname: String, name: String)
val noNickname = User(nickname = "", name = "new name")
"save noNickName" >> {
save(noNickname) must haveError.like {
case error => {
error.errorCode must equalTo("REQUIRED")
error.field must equalTo("nickname")
}
}
}
def haveError[T] = new ErrorMatcher[T]
class ErrorMatcher[T] extends Matcher[Either[List[T], _]] {
def apply[S <: Either[List[T], _]](value: Expectable[S]) =
result(value.value.left.toOption.isDefined,
value.description + " is Left",
value.description + " is not Left",
value)
def like[U](f: PartialFunction[T, MatchResult[U]]) =
this and partialMatcher(f)
private def partialMatcher[U](f: PartialFunction[T, MatchResult[U]]) =
new Matcher[Either[List[T], _]] {
def apply[S <: Either[List[T], _]](value: Expectable[S]) = {
// get should always work here because it comes after the "and"
val errors = value.value.left.toOption.get
val res = atLeastOnceWhen[T, U](errors)(f)
result(res.isSuccess,
value.description+" is Left[T] and "+res.message,
value.description+" is Left[T] but "+res.message,
value)
}
}
}
Notice that the matcher is defined on Either[List[T], _] everywhere.
I'm also wondering about the failure messages that are returned in case you don't find the expected error message, they might not be very explicit when the partial function fails.
So you may want to aim for using a contain matcher. Like this:
"save noNickName" >> {
save(noNickname) must haveError.containing(Error("REQUIRED", "nickname"))
}
// I'm reusing the beLeft matcher here
def haveError[T]: Matcher[Either[List[T], _]] = beLeft
// and using an implicit conversion to extend it
implicit def toErrorListMatcher[T](m: Matcher[Either[List[T], _]]): ErrorListMatcher[T] =
new ErrorListMatcher[T](m)
class ErrorListMatcher[T](m: Matcher[Either[List[T], _]]) {
def containing(t: T) =
// the 'contain' matcher is adapted to take in an
// Either[List[T], _] and work on its left part
m and contain(t) ^^ ((e: Either[List[T], _]) => e.left.toOption.get)
}
[Update]
The first solution (using atLeastOnceWhen and a partial function) can be combined with the second one (using an implicit) and the beLike matcher, to get maximum reusability of existing specs2 code:
def haveError[T]: Matcher[Either[List[T], _] = beLeft
implicit def toErrorListMatcher[T](m: Matcher[Either[List[T], _]]): ErrorListMatcher[T] =
new ErrorListMatcher[T](m)
class ErrorListMatcher[T](m: Matcher[Either[List[T], _]]) {
// beLike checks one element
// beLike.atLeastOnce transforms that matcher on a
// matcher on a sequence of elements
def like[S](f: PartialFunction[T, MatchResult[S]]) = {
m and beLike(f).atLeastOnce ^^ ((e: Either[List[T], _]) => e.left.toOption.get)
}