Decoder
's map
method return the correct type without using F-bound types, which is noisy and seems to have become something of a code smell
You can make things a little cleaner by adding a type parameter rather than using subtyping to distinguish "formats":
trait Decoder[C, A] {
def map[B](f: A => B): Decoder[C, A]
// ...
}
The C
type parameter could be completely unconstrained, could be a type-level string representing a content type, etc.
Decoder
for each new decoded type, everything could just be a Decoder[E, D, F, C]
, where E
is the encoded type, D
the decoded type, F
the failure type (the left part of an Either
like structure) and C
solely used for specialisation
The idea is that you could enumerate all possible formats that could be used as the C
type with something like this:
class ContentType(val contentType: String)
case object ApplicationJson extends ContentType("application/json")
case object PlainText extends ContentType("text/plain")
...
But that's hugely verbose and not extensible in the right ways.
"application/json".type
is shorthand for shapeless.Witness.`"application/json"`.T
or whatever technique you're using to refer to the type-level string.)
type CsvDecoder[A] = Decoder[CsvTag, A]
and never even really expose CsvTag
X
".
Decoder
instance for a give content type would have the same type, regardless of the library that implements it
import io.circe.generic.auto._
or by defining an Argonaut instance, but that doesn't (and shouldn't have to) matter to my code.
Decoder
s to work from in-memory strings, or is that just a shortcut?
Node
once and evaluate my expressions on this
Decoder
type class you have in mind, right?