Tagless final example in Scala requires superfluous second interp arg - scala

I'm playing around with implementing a tagless final DSL & interpreter in Scala, based on this blog post written in Haskell.
I can get an example running - see code below, but I don't quite understand why I need testVal(Interp)(Interp). If I only supply a single Interp argument, then I get the following compile errors:
Error:(29, 24) could not find implicit value for evidence parameter of type Test.Expr[Test.Id]
val x = testVal(Interp)
Error:(29, 24) not enough arguments for method testVal: (implicit evidence$1: Test.Expr[Test.Id])Test.Id[Int].
Unspecified value parameter evidence$1.
val x = testVal(Interp)
Is there a simple way to eliminate one of the Interp arguments?
object Test {
trait Expr[F[_]] {
def const(i: Int): F[Int]
def lam[A, B](f: F[A] => F[B]): F[A => B]
def app[A, B](f: F[A => B], a: F[A]): F[B]
def add(x: F[Int], y: F[Int]): F[Int]
}
type Id[A] = A
object Interp extends Expr[Id] {
override def const(i: Int): Id[Int] = i
override def lam[A, B](f: Id[A] => Id[B]): Id[A => B] = f
override def app[A, B](f: Id[A => B], a: Id[A]): Id[B] = f(a)
override def add(x: Id[Int], y: Id[Int]): Id[Int] = x + y
}
def testVal[F[_]: Expr](f: Expr[F]): F[Int] =
f.app(
f.lam[Int, Int](
x => f.add(x, f.const(1))),
f.const(10)
)
def main(args: Array[String]): Unit = {
// val x = testVal(Interp) -- won't compile
val x = testVal(Interp)(Interp)
println(x)
}
}

The syntax
def f[X: Y](args: Types): Res = { ... }
is a shortcut for
def f[X](args: Types)(implicit yx: Y[X]): Res = { ... }
so if you write
def testVal[F[_]: Expr](f: Expr[F]): F[Int] = { ... }
then it's the same as if you wrote
def testVal[F[_]](f: Expr[F])(implicit redundant: Expr[F]): F[Int] = { ... }
but you obviously don't need the same Expr[F] twice.
The signature should be either
def testVal[F[_]: Expr]: F[Int]
or
def testVal[F[_]](implicit f: Expr[F]): F[Int]
but not both at the same time.
Here is a full example, which also shows how to get the f using implicitly in the case that you decide to use the F: Expr variant (which does not assign a name to the implicit argument):
import scala.language.higherKinds
object Test {
trait Expr[F[_]] {
def const(i: Int): F[Int]
def lam[A, B](f: F[A] => F[B]): F[A => B]
def app[A, B](f: F[A => B], a: F[A]): F[B]
def add(x: F[Int], y: F[Int]): F[Int]
}
type Id[A] = A
object Interp extends Expr[Id] {
override def const(i: Int): Id[Int] = i
override def lam[A, B](f: Id[A] => Id[B]): Id[A => B] = f
override def app[A, B](f: Id[A => B], a: Id[A]): Id[B] = f(a)
override def add(x: Id[Int], y: Id[Int]): Id[Int] = x + y
}
def testVal[F[_]: Expr]: F[Int] = {
implicit val f = implicitly[Expr[F]]
f.app(
f.lam[Int, Int](
x => f.add(x, f.const(1))),
f.const(10)
)
}
def main(args: Array[String]): Unit = {
val x = testVal(Interp)
println(x)
}
}
Moreover, if you make Interp itself implicit, then you can omit all argument lists when invoking testVal, and instead write just
val x = testVal // no arguments at all.

Related

generalize Int -> Int, Int-> String, String -> String, String -> Int

I have 4 methods with one logic and 4 possible type mapping:
def convertStringToString(in: String): String = ???
def convertIntToString(in: Int): String = ???
def convertIntToInt(in: Int): Int = ???
def convertStringToInt(in: String): Int = ???
I want to generalize input and output type and write logic in one methods. Tried to generelize input parameter:
def convertToInt[IN](in: IN): Int = in match {
case x: String if x.forall(_.isDigit) => x.toInt
case y: Int => y
case _ => 0
}
def convertToString[IN](in: IN): String = convertToInt[IN](in).toString
Could you help me to generalize second:
def convertToInt[IN, OUT](in: IN): OUT = ???
If you really wanted to, you could have something typeclass-based:
def convert[I, O](in: I)(implicit c: ConversionRule[I, O]): O = {
if (c.isConvertible(in)) c.convert(in)
else c.zero
}
trait ConversionRule[I, O] {
def isConvertible(in: I): Boolean
def convert(in: I): O
def zero: O // Could possibly derive the zero from, e.g., a cats Monoid instance where such exists
}
The eagle-eyed may notice that the isConvertible/convert methods match the contract of PartialFunction[I, O]'s isDefinedAt/apply, so may as well just use PartialFunction (and rewrite convert with isDefinedAt/apply)
trait ConversionRule[I, O] extends PartialFunction[I, O] {
def zero: O
}
zero can be implemented in terms of PartialFunction.applyOrElse, but for the case where zero is constant (which is the case where referential transparency is preserved), this is much faster.
Smart constructors can be defined:
object ConversionRule {
def apply[I, O](zeroValue: O)(pf: PartialFunction[I, O]): ConversionRule[I, O] =
new ConversionRule[I, O] {
override def apply(i: I): O = pf(i)
override def isDefinedAt(i: I): Boolean = pf.isDefinedAt(i)
val zero: O = zeroValue
}
def totalConversion[I, O](f: I => O): ConversionRule[I, O] =
new ConversionRule[I, O] {
override def apply(i: I) = f(i)
override def isDefinedAt(i: I) = true
override def zero: O = throw new AssertionError("Should not call since conversion is defined")
}
// Might want to put this in a `LowPriorityImplicits` trait which this object extends
implicit def identityConversion[I]: ConversionRule[I, I] =
totalConversion(identity)
}
identityConversion means that a convertIntToInt gets automatically generated.
convertStringToInt can then be defined as
implicit val stringToIntConversion = ConversionRule[String, Int](0) {
case x if x.forAll(_.isDigit) => x.toInt
}
One can define a toString based conversion (basically the non-lawful Show proposed for alleycats):
implicit def genericToString[I]: ConversionRule[I, String] =
ConversionRule.totalConversionRule(_.toString)
And it should then be possible to define a stringViaInt ConversionRule derivation like:
implicit def stringViaInt[I, O](implicit toInt: ConversionRule[I, Int]): ConversionRule[I, String] =
convert(convert(in)(toInt))
The only really useful thing this provides is an opt-in to usage of implicit conversions. Whether that's enough of a gain to justify? shrug
(Disclaimer: only the scala compiler in my head has attempted to compile this)

compiler failure to resolve Implicit types with bounds (sometimes)

Edit:
Last revision was deemed unhelpful as it did not contain necessary information that help narrow down my issue. hence the need to also include the AST.
Below is a library in its entirety that allows parsing and writing of play-json's json based on user defined schema; Similar to what Scala's slick offers for database columns to some extent:
import scala.language.higherKinds
import play.api.libs.functional.syntax._
import play.api.libs.json._
import scala.language.{higherKinds, implicitConversions}
type PathNodes = List[PathNode]
sealed trait Field[A] {
def pathNodes: PathNodes
def jsPath: JsPath = JsPath(pathNodes)
def relativePath: JsPath = JsPath(List(pathNodes.last))
def format: Format[A]
def nestedFormatter(path: JsPath): OFormat[A]
def nestedFormat: OFormat[A] = nestedFormatter(relativePath)
}
case class PlainField[A: Format](prefix: PathNodes) extends Field[A] {
override def pathNodes: PathNodes = prefix
def format: Format[A] = implicitly[Format[A]]
override def nestedFormatter(path: JsPath): OFormat[A] = path.format(format)
}
abstract class JsonSchema[T](val _prefix: PathNodes) extends Field[T] with SchemaExtensionMethods {
override def pathNodes: PathNodes = _prefix
def format: OFormat[T]
protected def plain[A: Format](name: String): PlainField[A] = PlainField[A](_prefix :+ KeyPathNode(name))
protected def nested[N](name: String, factory: PathNodes => N): N = factory(_prefix :+ KeyPathNode(name))
protected def nested[B, G <: JsonSchema[B]](name: String)(implicit sm: HasJsonSchema[B, G]): G = sm.apply(_prefix :+ KeyPathNode(name))
override def nestedFormatter(path: JsPath): OFormat[T] = path.format(format)
}
case class Optional[F, A](field: F)(implicit ev: F <:< Field[A]) extends Field[Option[A]] {
override def pathNodes: PathNodes = field.pathNodes
override def format: Format[Option[A]] = {
implicit val writes: Writes[Option[A]] = JsPath.writeNullable(field.format)
implicit val reads: Reads[Option[A]] = JsPath.readNullable(field.format)
implicitly[Format[Option[A]]]
}
def map[G, B](f: F => G)(implicit ev: G <:< Field[B]): Optional[G, B] = new Optional[G, B](f(field))
def flatMap[G <: Field[B], B](f: F => Optional[G, B]): Optional[G, B] = f(field)
override def nestedFormatter(path: JsPath): OFormat[Option[A]] = path.formatNullable(field.format)
}
case class Collection[F, A](field: F)(implicit ev: F <:< Field[A], repath: Repath[F]) extends Field[Seq[A]] {
override def pathNodes: PathNodes = field.pathNodes
override def format: Format[Seq[A]] = {
implicit val writes: Writes[Seq[A]] = Writes.seq(field.format)
implicit val reads: Reads[Seq[A]] = Reads.seq(field.format)
implicitly[Format[Seq[A]]]
}
def apply(idx: Int): F = implicitly[Repath[F]].apply(field, IdxPathNode(idx))
override def nestedFormatter(path: JsPath): OFormat[Seq[A]] = path.format(format)
}
class FormatExtensionMethods[T](val arg: T) {
def <>[A, B, Fun](apply: Fun, unapply: B => Option[A])(implicit jss: JsonShape[A, B, T, Fun]): OFormat[B] = jss.format(arg, apply, unapply andThen (_.get))
}
class FieldExtensionMethods[F](val field: F) {
def optional[A](implicit ev: F <:< Field[A]): Optional[F, A] = new Optional[F, A](field)
def sequence[A](implicit ev: F <:< Field[A], repath: Repath[F]): Collection[F, A] = new Collection[F, A](field)
}
trait SchemaExtensionMethods {
implicit def formatExtensionMethods[M](t: M): FormatExtensionMethods[M] = new FormatExtensionMethods[M](t)
implicit def fieldExtensionMethods[M, A](t: M): FieldExtensionMethods[M] = new FieldExtensionMethods[M](t)
}
trait Repath[F] {
def apply(f: F, node: PathNode): F
}
object Repath {
implicit def plain[T]: Repath[PlainField[T]] = new Repath[PlainField[T]] {
override def apply(t: PlainField[T], node: PathNode): PlainField[T] =
PlainField[T](t.pathNodes :+ node)(t.format)
}
implicit def schema[S <: JsonSchema[_]](implicit sm: HasJsonSchema[_, S]): Repath[S] = new Repath[S] {
override def apply(t: S, node: PathNode): S =
sm.apply(t.pathNodes :+ node)
}
implicit def option[F <: Field[T] : Repath, T]: Repath[Optional[F, T]] = new Repath[Optional[F, T]] {
override def apply(t: Optional[F, T], node: PathNode): Optional[F, T] =
new Optional[F, T](implicitly[Repath[F]].apply(t.field, node))
}
implicit def sequence[F <: Field[T] : Repath, T]: Repath[Collection[F, T]] = new Repath[Collection[F, T]] {
override def apply(t: Collection[F, T], node: PathNode): Collection[F, T] =
new Collection[F, T](implicitly[Repath[F]].apply(t.field, node))
}
}
trait JsonShape[A, B, -T, Func] {
def format(t: T, apply: Func, unapply: B => A): OFormat[B]
}
object JsonShape {
type F[T] = Field[T]
implicit def cc1[A, B]: JsonShape[A, B, F[A], (A) => B] = (t: F[A], apply: (A) => B, unapply: B => A) => {
val name = t.pathNodes.last.asInstanceOf[KeyPathNode].key
OFormat[B](
Reads[B](jsv => (jsv \ name).validate[A](t.format).map(apply)),
OWrites[B](b => JsObject(Map(name -> Json.toJson(unapply(b))(t.format))))
)
}
implicit def cc2[T1, T2, B]: JsonShape[(T1, T2), B, (F[T1], F[T2]), (T1, T2) => B] = (t: (F[T1], F[T2]), apply: (T1, T2) => B, unapply: B => (T1, T2)) => {
(
t._1.nestedFormat and
t._2.nestedFormat
) (apply, unapply)
}
implicit def cc3[T1, T2, T3, B]: JsonShape[(T1, T2, T3), B, (F[T1], F[T2], F[T3]), (T1, T2, T3) => B] = (t: (F[T1], F[T2], F[T3]), apply: (T1, T2, T3) => B, unapply: B => (T1, T2, T3)) => {
(
t._1.nestedFormat and
t._2.nestedFormat and
t._3.nestedFormat
) (apply, unapply)
}
//this goes up to 22
}
abstract class HasJsonSchema[T, +S <: JsonSchema[T]](val apply: PathNodes => S) extends OFormat[T] {
val root: S = apply(Nil)
def format: OFormat[T] = root.format
def writes(o: T): JsObject = root.format.writes(o)
def reads(json: JsValue): JsResult[T] = root.format.reads(json)
}
Now let's write a small piece of client code that reproduce the issue:
case class MessageSchema(prefix: PathNodes) extends JsonSchema[Message](prefix) {
def underlying = plain[String]("underlying")
//def underlying = plain[String]("underlying").optional if I wanted the field to be Option[String]
//def underlying = plain[String]("underlying").sequence if I wanted the field to be Seq[String]
override def format = underlying <> (Message.apply _, Message.unapply)
}
case class Message(underlying: String)
object Message {
implicit object sm extends HasJsonSchema[Message, MessageSchema](MessageSchema.apply)
}
case class LanguageTaggedSchema[T, S <: JsonSchema[T]](prefix: PathNodes)(implicit evT: HasJsonSchema[T, S]) extends JsonSchema[LanguageTagged[T]](prefix) {
def lang = plain[String]("lang")
def data: S = nested("data")(evT)
def format = (lang, data) <> (LanguageTagged.apply[T] _, LanguageTagged.unapply[T])
}
case class LanguageTagged[T](lang: String, data: T)
object LanguageTagged {
implicit def schemaMapper[T, S <: JsonSchema[T]](implicit ev: HasJsonSchema[T, S]): HasJsonSchema[LanguageTagged[T], LanguageTaggedSchema[T, S]] =
new HasJsonSchema[LanguageTagged[T], LanguageTaggedSchema[T, S]](LanguageTaggedSchema.apply[T, S]) {}
}
def toJson[T, S <: JsonSchema[T]](a: T)(implicit ev: HasJsonSchema[T, S]): JsValue = Json.toJson(a)(ev.format)
toJson(Message("hi")) //Ok!
toJson(LanguageTagged("en", Message("hi"))) //Ok!
//or simply write
Json.toJson(LanguageTagged("en", Message("hi")))
//and if i wanted to traverse a json path i would do:
val schema = implicitly[HasJsonSchema[LanguageTagged[Message],LanguageTaggedSchema[Message,MessageSchema]]].root
schema.data.underlying.jsPath
//prints: res2: play.api.libs.json.JsPath = /data/underlying
//Now to where the problem starts:
def getSchema[T, S <: JsonSchema[T]](a: T)(implicit ev: HasJsonSchema[T, S]): S = ev.root
getSchema(Message("hi")) //Ok!
getSchema(LanguageTagged("en", Message("hi"))) //Not Ok but why?
//Error:(211, 11) could not find implicit value for
//parameter ev: A$A6.this.HasJsonSchema[A$A6.this.LanguageTagged[A$A6.this.Message],S]
//getSchema(LanguageTagged("en", Message("hi")));//
//^
I have a huge suspicion that the compiler runs into issues because of the bounded type of S inHasJsonSchema[T, S <: JsonSchema[T]] when infering the implicit type S. and so far only in that specific situation as shown on the last line of all the code. as a dubugging attempt I created a similar situation and realized that if the type S was not bounded I wouldn't have this issue. Any sort of solution that refactors the code such that it doesn't depend on bounded types or one that simply solves the implicit resolution is appreciated
What You're trying to achieve cannot be done with subtyping. You should use type-classes instead, a more in-depth explanation:
http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html

Scala: abstracting over a path-dependent type in impilicit parameter

Let's say I have a class:
abstract class NumericCombine[A:Numeric,B:Numeric]{
type AB <: AnyVal
}
I want to define a function that returns a value of type NumericCombine[A,B].AB. for instance:
def plus[A: Numeric,B:Numeric](x: A, y: B): NumericCombine[A,B].AB
but the compiler doesn't let me reference .AB in plus.
FYI, this is the context of this question.
I want to provide:
implicit object IntFloat extends NumericCombine[Int,Float]{override type AB = Float}
implicit object FloatInt extends NumericCombine[Float,Int]{override type AB = Float}
and its other 44 friends (7*6-2) so that I can define my plus as below:
def plus[A: Numeric,B:Numeric](x: A, y: B): NumericCombine[A,B].AB =
{
type AB = Numeric[NumericCombine[A,B].AB]
implicitly[AB].plus(x.asInstanceOf[AB],y.asInstanceOf[AB])
}
plus(1f,2)//=3f
plus(1,2f)//=3f
I am aware of the fact that value conversions in Scala allows me to define
def plus[T](a: T, b: T)(implicit ev:Numeric[T]): T = ev.plus(a,b)
and achieve the behaviour above as suggested here, but since I want to use this function as part of a bigger function (which is described in the link mentioned as the context of this question), I need to parametrize the function with both A and B.
Update:
I made some good progress with this.
My NumericCombine now looks like this:
abstract class NumericCombine[A: Numeric, B: Numeric] {
type AB <: AnyVal
def fromA(x: A): AB
def fromB(y: B): AB
val numeric: Numeric[AB]
def plus(x: A, y: B): AB = numeric.plus(fromA(x), fromB(y))
def minus(x: A, y: B): AB = numeric.minus(fromA(x), fromB(y))
def times(x: A, y: B): AB = numeric.times(fromA(x), fromB(y))
}
and My plus function looks like:
def plus[A: Numeric, B: Numeric](x: A, y: B)(implicit ev:NumericCombine[A,B])
: ev.AB = ev.plus(x, y)
The weighted average function requiring plus ended up becoming a bit more complicated:
def accumulateWeightedValue[A: Numeric,B: Numeric]
(accum: (A, NumericCombine[A, B]#AB), ValueWithWeight: (A, B))
(implicit combine: NumericCombine[A, B], timesNumeric: Numeric[NumericCombine[A, B]#AB])
:(A,NumericCombine[A, B]#AB)=
this is a function that takes (A,AB),(A,B) and returns (A,AB). I use it internally inside weightedSum which just aggregates over this:
def weightedSum[A: Numeric,B: Numeric](weightedValues: GenTraversable[(A, B)])
(implicit numericCombine: NumericCombine[A, B], plusNumeric: Numeric[NumericCombine[A, B]#AB])
: (A, NumericCombine[A, B]#AB)
Now, this compiles fine. It does seem to have a problem with the second implicit parameter. ie Numeric[AB] when I run it with implicit values for say NumericCombine[Int,Float] present. It gives me:
could not find implicit value for parameter plusNumeric:
Numeric[NumericCombine[Int,Float]#AB]
note that in NumericCombine, I have a Numeric[AB] which should be available for implicit look-up. storing it locally, in the case of [Int,Float]:
val lst: Seq[(Int, Float)] =List((1,3f),(1,4f))
implicit val num: Numeric[Float] = IntFloat.numeric //IntFloat extends NumericCombine[Int,Float]
weightedSum(lst)
in a local variable before invoking the function needing it doesn't seem to have any impact. So why is it being picked up by the implicit system.
Just use
def plus[A: Numeric,B:Numeric](x: A, y: B): NumericCombine[A,B]#AB
Note the # (hash) instead of . (dot). This is called "type projection". Dot notation is called "path dependent type". I'm telling you these names so that you can google for more info easily. Simply put, # is used for accessing types from classes/traits, and . is used for accessing types from objects/values.
Example:
trait Foo {
type T
}
val fooObj: Foo = new Foo {
type T = Int
}
type t1 = fooObj.T
type t2 = Foo#T
* 18 Apr 2017: updated base on the latest code from author *
* 19 Apr 2017 *
Add NumericCombine#Implicits for convinence
Remove AnyVal constraints to support any Numeric types e.g. BigInt
Refactor NumericCombine
You need Aux pattern:
import scala.collection.GenSeq
trait NumericCombine[A, B] {
type AB
def fromA(x: A): AB
def fromB(y: B): AB
val numericA: Numeric[A]
val numericB: Numeric[B]
val numericAB: Numeric[AB]
// For convenience, caller can 'import combine.Implicits._'
// to bring the Numeric's into the current scope
object Implicits {
implicit def implicitNumericA = numericA
implicit def implicitNumericB = numericB
implicit def implicitNumericAB = numericAB
}
def plus(x: A, y: B): AB = numericAB.plus(fromA(x), fromB(y))
def minus(x: A, y: B): AB = numericAB.minus(fromA(x), fromB(y))
def times(x: A, y: B): AB = numericAB.times(fromA(x), fromB(y))
}
object NumericCombine {
type Aux[A, B, _AB] = NumericCombine[A, B] {
type AB = _AB
}
private def combine[A, B, _AB](fa: A => _AB, fb: B => _AB)
(implicit
_numericA: Numeric[A],
_numericB: Numeric[B],
_numericAB: Numeric[_AB]
): NumericCombine[A, B] = new NumericCombine[A, B] {
override type AB = _AB
override def fromA(x: A): AB = fa(x)
override def fromB(y: B): AB = fb(y)
override val numericA: Numeric[A] = _numericA
override val numericB: Numeric[B] = _numericB
override val numericAB: Numeric[AB] = _numericAB
}
implicit lazy val IntFloat = combine[Int, Float, Float](_.toFloat, identity)
implicit lazy val BigIntBigDecimal = combine[BigInt, BigDecimal, BigDecimal](i => BigDecimal(i), identity)
}
implicit class ValuesWithWeight[A, B](val weightedValue: (A, B)) {
def weight: A = weightedValue._1
def value: B = weightedValue._2
}
def weightedSum[A, B, AB]
(valuesWithWeight: GenSeq[(A, B)])
(implicit combine: NumericCombine.Aux[A, B, AB]):
(A, AB) = {
import combine.Implicits._
val z: (A, AB) =
(combine.numericA.zero, combine.numericAB.zero)
def accumulateWeightedValue(accum: (A, AB), valueWithWeight: (A, B)): (A, AB) = {
val weightedValue = combine.times(valueWithWeight.weight, valueWithWeight.value)
(
combine.numericA.plus(accum.weight, valueWithWeight.weight),
combine.numericAB.plus(accum.value, weightedValue)
)
}
valuesWithWeight.aggregate(z)(
accumulateWeightedValue,
// dataOps.tuple2.plus[A,AB]
{
case ((a1, ab1), (a2, ab2)) =>
(combine.numericA.plus(a1, a2) ->
combine.numericAB.plus(ab1, ab2))
}
)
}
weightedSum(Seq(1 -> 1.5f, 2 -> 1f, 3 -> 1.7f))
weightedSum(Seq(BigInt(1) -> BigDecimal("1.5"), BigInt(2) -> BigDecimal("1"), BigInt(3) -> BigDecimal("1.7")))
An alternative to #slouc's answer is
def plus[A, B](x: A, y: B)(implicit ev: NumericCombine[A, B]): ev.AB
I'd also enhance NumericCombine:
trait NumericCombine[A, B] {
type AB <: AnyVal
def fromA(a: A): AB
def fromB(b: B): AB
val num: Numeric[AB]
}
abstract class NumericCombineImpl[A, B, R](implicit val num: Numeric[R], f1: A => R, f2: B => R) {
type AB = R
def fromA(a: A) = f1(a)
def fromB(b: B) = f2(b)
}
implicit object IntFloat extends NumericCombineImpl[Int,Float,Float]
...
This would allow to actually implement plus, no casts required:
def plus[A, B](x: A, y: B)(implicit ev: NumericCombine[A, B]): ev.AB =
ev.num.plus(ev.fromA(x), ev.fromB(y))

Lifting a function which takes implicit parameter using functor (Scalaz7)

Just started learning Scalaz. Here is my code
trait Monoid[A] {
def mappend(a1: A, a2: A): A
def mzero: A
}
object Monoid {
implicit val IntMonoid: Monoid[Int] = new Monoid[Int] {
def mappend(a1: Int, a2: Int): Int = a1 + a2
def mzero: Int = 0
}
implicit val StringMonoid: Monoid[String] = new Monoid[String] {
def mappend(a1: String, a2: String): String = a1 + a2
def mzero: String = ""
}
}
trait MonoidOp[A] {
val F: Monoid[A]
val value: A
def |+|(a2: A): A = F.mappend(value, a2)
}
object MonoidOp{
implicit def toMonoidOp[A: Monoid](a: A): MonoidOp[A] = new MonoidOp[A]{
val F = implicitly[Monoid[A]]
val value = a
}
}
I have defined a function (just for the sake of it)
def addXY[A: Monoid](x: A, y: A): A = x |+| y
I want to lift it so that it could be used using Containers like Option, List, etc. But when I do this
def addXYOptioned = Functor[Option].lift(addXY)
It says error: could not find implicit value for evidence parameter of type scalaz.Monoid[A]
def addOptioned = Functor[Option].lift(addXY)
How to lift such functions?
Your method addXY needs a Monoid[A] but there is no Monoid[A] in scope when used in addXYOptioned, so you also need to add the Monoid constraint to addXYOptioned.
The next problem is that Functor.lift only lifts a function A => B, but we can use Apply.lift2 to lift a function (A, B) => C.
Using the Monoid from Scalaz itself :
import scalaz._, Scalaz._
def addXY[A: Monoid](x: A, y: A): A = x |+| y
def addXYOptioned[A: Monoid] = Apply[Option].lift2(addXY[A] _)
We could generalize addXYOptioned to make it possible to lift addXY into any type constructor with an Apply instance :
def addXYApply[F[_]: Apply, A: Monoid] = Apply[F].lift2(addXY[A] _)
addXYApply[List, Int].apply(List(1,2), List(3,4))
// List[Int] = List(4, 5, 5, 6)
addXYApply[Option, Int].apply(1.some, 2.some)
// Option[Int] = Some(3)

Pulling out shapeless polymorphic functions that have dependencies

New to shapeless and I have a question on using polymorphic functions that need some dependencies. I basically have this code and want to pull somePoly object out of the run method:
import shapeless._
object SomeObject {
type SomeType = Int :+: String :+: (String, Int) :+: CNil
def run( someList: List[SomeType], someInt:Int, someWord:String ) = {
object somePoly extends Poly1 {
implicit def doIt = at[Int]( i => i + someInt + someWord.length)
implicit def doIt2 = at[String]( i => i.length + someWord.length)
implicit def doIt3 = at[(String, Int)]( i => i._1.length + someWord.length)
}
someList.map( _.map(somePoly) )
}
}
One way I thought of doing it was like this, but it seems messy:
object TypeContainer {
type SomeType = Int :+: String :+: (String, Int) :+: CNil
}
case class SomePolyWrapper( someList: List[TypeContainer.SomeType], someInt:Int, someWord:String ){
object somePoly extends Poly1 {
implicit def doIt = at[Int]( i => i + someInt + someWord.length)
implicit def doIt2 = at[String]( i => i.length + someWord.length)
implicit def doIt3 = at[(String, Int)]( i => i._1.length + someWord.length)
}
}
object SomeObject {
def run( someList: List[TypeContainer.SomeType], someInt:Int, someWord:String ) = {
val somePolyWrapper = SomePolyWrapper(someList, someInt, someWord)
someList.map( _.map(somePolyWrapper.somePoly) )
}
}
Anyone have any advice?
The limitations of Scala's implicit resolution system mean the Poly definition needs to be a stable identifier, which makes this kind of thing more painful than it should be. As I mentioned on Gitter, there are a couple of workarounds that I know of (there may be others).
One approach would be to make the Poly1 a PolyN, where the extra arguments are for the someInt and someWord values. If you were mapping over an HList, you'd then use mapConst and zip to make the input HList have the right shape. I've never done this for a coproduct, but something similar is likely to work.
Another approach is to use a custom type class. In your case that might look something like this:
import shapeless._
trait IntFolder[C <: Coproduct] {
def apply(i: Int, w: String)(c: C): Int
}
object IntFolder {
implicit val cnilIntFolder: IntFolder[CNil] = new IntFolder[CNil] {
def apply(i: Int, w: String)(c: CNil): Int = sys.error("Impossible")
}
def instance[H, T <: Coproduct](f: (H, Int, String) => Int)(implicit
tif: IntFolder[T]
): IntFolder[H :+: T] = new IntFolder[H :+: T] {
def apply(i: Int, w: String)(c: H :+: T): Int = c match {
case Inl(h) => f(h, i, w)
case Inr(t) => tif(i, w)(t)
}
}
implicit def iif[T <: Coproduct: IntFolder]: IntFolder[Int :+: T] =
instance((h, i, w) => h + i + w.length)
implicit def sif[T <: Coproduct: IntFolder]: IntFolder[String :+: T] =
instance((h, i, w) => h.length + i + w.length)
implicit def pif[T <: Coproduct: IntFolder]: IntFolder[(String, Int) :+: T] =
instance((h, i, w) => h._1.length + i + w.length)
}
And then you could write a more generic version of your run:
def run[C <: Coproduct](
someList: List[C],
someInt: Int,
someWord: String
)(implicit cif: IntFolder[C]): List[Int] = someList.map(cif(someInt, someWord))
And use it like this:
scala> run(List(Coproduct[SomeType](1)), 10, "foo")
res0: List[Int] = List(14)
scala> run(List(Coproduct[SomeType](("bar", 1))), 10, "foo")
res1: List[Int] = List(16)
The specificity of the operation makes this approach look a little weird, but if I really needed to do something like this for different coproducts, this is probably the solution I'd choose.