For learning purposes, I am trying to define a wrapper class called DoubleMap which provides the method mapBoth. It essentially takes two functions f and g, where the domain of g is the co-domain of f. The composition of this function (g o f) should then be mapped of the container wrapped by DoubleMap
This is my current code:
implicit class DoubleMap
[A, B, C, F[X] <: List[X]] // just List for now
(xs: F[A])(implicit cbf: CanBuildFrom[F[A], C, F[C]]) {
def mapBoth(f: A => B)(g: B => C): F[C] =
xs.map(f andThen g).to[F]
}
However, when I want to use the method like this:
List(true, false, false).mapBoth(!_)(!_)
I get a cryptical error message about the type mismatch between the (found) type CanBuildFrom[List[_], Nothing, List[Nothing]] and the (required) type CanBuildFrom[List[Boolean], C, List[C]]
Why does the compiler infer the first type?
Your call expands to
DoubleMap(xs).mapBoth(!_)(!_)
so all of DoubleMap's type parameters and cbf need to be inferred before the mapBoth call is handled. To fix it, just move these parameters to mapBoth:
implicit class DoubleMap
[A, F[X] <: List[X]] // just List for now
(xs: F[A]) {
def mapBoth[B, C](f: A => B)(g: B => C)(implicit cbf: CanBuildFrom[F[A], C, F[C]]): F[C] =
xs.map(f andThen g).to[F]
}
Then B and C are determined from f and g, and cbf from F, A and C.
If you wish to not be tied to List, consider Functor from Cats
implicit class DoubleMap[F[_]: Functor, A](xs: F[A]) {
def mapBoth[B, C](f: A => B)(g: B => C): F[C] =
xs.map(f andThen g)
}
or vanilla Scala 2.13 approach (inspired by Luis' 2.12 implementation)
implicit class DoubleMap[F[x] <: IterableOnce[x], A](xs: F[A]) {
def mapBoth[B, C](f: A => B)(g: B => C)(implicit bf: BuildFrom[F[A], C, F[C]]): F[C] =
bf.fromSpecific(xs)(xs.iterator.map(f andThen g))
}
which both output
List(true, false, false).mapBoth(!_)(!_)
Vector(true, false, false).mapBoth(!_)(!_)
res1: List[Boolean] = List(true, false, false)
res2: Vector[Boolean] = Vector(true, false, false)
Scalaz has a thrush operator |> defined something like this:
implicit class ThrushOps[A](self: A) {
def |>[B](f: A ⇒ B): B = f(self)
}
I have a few functions of various arguments:
def f1(x:Int)=x+1
def f2(a:Int, b:Int)=(a+1,b+1)
def f3(a:Int, b:Int, c:Int)=(a+1,b+1,c+1)
The way I can call them is syntactically different dependending if they have 1 or more args:
4 |> f1
(1,2) |> (f2 _).tupled
(1,2,3) |> (f3 _).tupled
What is a way to make calling a function with one argument consistent to calling a function with n arguments from a syntactic point of view?
I want to be able to write
4 |> f1
(1,2) |> f2
I can come up with two ways, but both only let you write consistent
4 |> f1 _
(1,2) |> f2 _
and still require doing something for each arity.
Option 1:
class MyFn[A, B](f: A => B) {
def apply(x: A): B = f(x)
}
object MyFn {
implicit def from1[A, B](f: A => B): MyFn[A, B] = new MyFn(f)
implicit def from2[A1, A2, B](f: (A1, A2) => B): MyFn[(A1, A2), B] = new MyFn(f.tupled)
implicit def from3[A1, A2, A3, B](f: (A1, A2, A3) => B): MyFn[(A1, A2, A3), B] = new MyFn(f.tupled)
}
implicit class ThrushOps[A](self: A) {
def |>[B](f: MyFn[A, B]): B = f(self)
}
Option 2:
implicit class ThrushOps[A](self: A) {
def |>[B](f: A ⇒ B): B = f(self)
def |>[C1, C2, B](f: (C1, C2) ⇒ B)(implicit ev: A =:= (C1, C2)): B = f.tupled(self)
def |>[C1, C2, C3, B](f: (C1, C2, C3) ⇒ B)(implicit ev: A =:= (C1, C2, C3)): B = f.tupled(self)
}
Use apply:
implicit class ThrushOps[A](self: A) {
def |>[B](f: A ⇒ B): B = if (self.isInstanceOf[Product]) f.apply(self) else f(self)
}
You can also use manifest to enforce more accurate check
I'd like to build the equivalent of:
def applyWithHList2[A1, A2, R, L <: HList](l: L, f: Function2[A1, A2, R]): Try[R]
The values in the list are such that in the N choose 2 possible value combinations of l.unify there is at most one that could be used to call the function. No additional type information is available.
If there is no way to call the function, the result should be Failure with MatchError. Otherwise, the result should be Try(f(a1, a2)).
I am still getting used to shapeless and would appreciate suggestions for how to approach this problem.
Funnily enough it's a lot easier to write a version that just doesn't compile if appropriately typed elements aren't available in the HList:
import shapeless._, ops.hlist.Selector
def applyWithHList2[A1, A2, R, L <: HList](l: L, f: (A1, A2) => R)(implicit
selA1: Selector[L, A1],
selA2: Selector[L, A2]
): R = f(selA1(l), selA2(l))
If you really want a runtime error (in a Try) for cases where there's not an applicable pair, you could use the default null instance trick:
import scala.util.{ Failure, Success, Try }
def applyWithHList2[A1, A2, R, L <: HList](l: L, f: (A1, A2) => R)(implicit
selA1: Selector[L, A1] = null,
selA2: Selector[L, A2] = null
): Try[R] = Option(selA1).flatMap(s1 =>
Option(selA2).map(s2 => f(s1(l), s2(l)))
).fold[Try[R]](Failure(new MatchError()))(Success(_))
If you find that unpleasant (and it is), you could use a custom type class:
trait MaybeSelect2[L <: HList, A, B] {
def apply(l: L): Try[(A, B)] = (
for { a <- maybeA(l); b <- maybeB(l) } yield (a, b)
).fold[Try[(A, B)]](Failure(new MatchError()))(Success(_))
def maybeA(l: L): Option[A]
def maybeB(l: L): Option[B]
}
object MaybeSelect2 extends LowPriorityMaybeSelect2 {
implicit def hnilMaybeSelect[A, B]: MaybeSelect2[HNil, A, B] =
new MaybeSelect2[HNil, A, B] {
def maybeA(l: HNil): Option[A] = None
def maybeB(l: HNil): Option[B] = None
}
implicit def hconsMaybeSelect0[H, T <: HList, A](implicit
tms: MaybeSelect2[T, A, H]
): MaybeSelect2[H :: T, A, H] = new MaybeSelect2[H :: T, A, H] {
def maybeA(l: H :: T): Option[A] = tms.maybeA(l.tail)
def maybeB(l: H :: T): Option[H] = Some(l.head)
}
implicit def hconsMaybeSelect1[H, T <: HList, B](implicit
tms: MaybeSelect2[T, H, B]
): MaybeSelect2[H :: T, H, B] = new MaybeSelect2[H :: T, H, B] {
def maybeA(l: H :: T): Option[H] = Some(l.head)
def maybeB(l: H :: T): Option[B] = tms.maybeB(l.tail)
}
}
trait LowPriorityMaybeSelect2 {
implicit def hconsMaybeSelect2[H, T <: HList, A, B](implicit
tms: MaybeSelect2[T, A, B]
): MaybeSelect2[H :: T, A, B] = new MaybeSelect2[H :: T, A, B] {
def maybeA(l: H :: T): Option[A] = tms.maybeA(l.tail)
def maybeB(l: H :: T): Option[B] = tms.maybeB(l.tail)
}
}
And then:
def applyWithHList2[A1, A2, R, L <: HList](l: L, f: (A1, A2) => R)(implicit
ms2: MaybeSelect2[L, A1, A2]
): Try[R] = ms2(l).map(Function.tupled(f))
But that's a lot of work just to throw away some compile-time safety.
Note that none of these approaches enforce the constraint that there's only at most pair of elements in the HList that the function can be applied to, since I read that as a pre-condition in your question. It'd definitely be possible to write a solution that enforced the constraint at compile time (and it might even be a bit shorter than the MaybeSelect2 implementation above).
So comonad.com has an interesting series of articles on working with applicatives and I've been trying to bring what I can to scala (for fun, and to learn). So, haskell defines FixF –
newtype FixF f a = FixF (f (FixF f) a)
it is written ,"FixF is of kind ((* -> *) -> * -> *) -> * -> *). It takes the fixpoint of a "second-order Functor" (a Functor that sends a Functor to another Functor, i.e. an endofunctor on the functor category of hask), to recover a standard "first order Functor" back out."
kinds classify types
* type A
* -> * type F[_]
* -> * -> * type F[_,_]
((* -> *) -> *) type F[F'[_]]
((* -> *) ->* -> *) type F[F'[_], A]
Now I've seen this
case class Fix[F[_]](out: F[Fix[F]])
// ((* -> *) -> * )
and this
case class BFixF[F[_,_], A](out: F[A, BFixF[F,A]])
So it's not the first one Fix (wrong kinds) Is it the second? I don't the think the kinds are right
BFixF :: ((* -> * -> * ) -> * -> *) ?
is it -
// edit as of this morning it is really not this
class FixF[F[_[_], _], A] :: ((* -> *) -> * -> *) -> *)
is it ?
case class FixF'[F[_], A](run: F[Fix[F, A]])
if so I'd love to see the proper definition and functor
case class FixF[F[_], A] (out: F[Fix[F, A]])
trait FixFFunctor[F[_]: Functor] extends Functor[({type l[x] = FixF[F, x]})#l] {
def map[A, B](f: A => B): FixF[F, A] => FixF[F, B] = ???
}
now bonus question, can someone define the applicative ?
This is a pretty cool question—I'd also read those posts, and had wondered about how terrifying a Scala implementation would look, but I never actually tried it. So I'm going to respond in some detail, but please note that the following is extremely off-the-cuff (it's Saturday morning, after all) and doesn't necessarily represent the cleanest way to do this in Scala.
It's probably best to start by defining some of the types from the first post in the series:
import scala.language.higherKinds
import scalaz._, Scalaz._
case class Const[M, A](mo: M)
sealed trait Sum[F[_], G[_], A]
object Sum {
def inL[F[_], G[_], A](l: F[A]): Sum[F, G, A] = InL(l)
def inR[F[_], G[_], A](r: G[A]): Sum[F, G, A] = InR(r)
}
case class InL[F[_], G[_], A](l: F[A]) extends Sum[F, G, A]
case class InR[F[_], G[_], A](r: G[A]) extends Sum[F, G, A]
And a couple more from the blog post itself:
case class Embed[F[_], A](out: A)
case class ProductF[F[_[_], _], G[_[_], _], B[_], A](f: F[B, A], g: G[B, A])
If you've worked through the above, you should have some sense of what FixF should look like:
case class FixF[F[f[_], _], A](out: F[({ type L[x] = FixF[F, x] })#L, A])
It turns out that this is a little too strict, though, so we'll use the following instead:
class FixF[F[f[_], _], A](v: => F[({ type L[x] = FixF[F, x] })#L, A]) {
lazy val out = v
override def toString = s"FixF($out)"
}
Now suppose we want to implement lists as a "second-order fixpoint of polynomial functors", as in the blog post. We can start by defining some useful aliases:
type UnitConst[x] = Const[Unit, x]
type UnitConstOr[F[_], x] = Sum[UnitConst, F, x]
type EmbedXUnitConstOr[F[_], x] = ProductF[Embed, UnitConstOr, F, x]
type MyList[x] = FixF[EmbedXUnitConstOr, x]
And now we can define the Scala version of the examples from the post:
val foo: MyList[String] = new FixF[EmbedXUnitConstOr, String](
ProductF[Embed, UnitConstOr, MyList, String](
Embed("foo"),
Sum.inL[UnitConst, MyList, String](Const())
)
)
val baz: MyList[String] = new FixF[EmbedXUnitConstOr, String](
ProductF[Embed, UnitConstOr, MyList, String](
Embed("baz"),
Sum.inL[UnitConst, MyList, String](Const())
)
)
val bar: MyList[String] = new FixF[EmbedXUnitConstOr, String](
ProductF[Embed, UnitConstOr, MyList, String](
Embed("bar"),
Sum.inR[UnitConst, MyList, String](baz)
)
)
This looks like what we'd expect given the Haskell implementation:
scala> println(foo)
FixF(ProductF(Embed(foo),InL(Const(()))))
scala> println(bar)
FixF(ProductF(Embed(bar),InR(FixF(ProductF(Embed(baz),InL(Const(())))))))
Now we need our type class instances. Most of these are pretty straightforward:
implicit def applicativeConst[M: Monoid]: Applicative[
({ type L[x] = Const[M, x] })#L
] = new Applicative[({ type L[x] = Const[M, x] })#L] {
def point[A](a: => A): Const[M, A] = Const(mzero[M])
def ap[A, B](fa: => Const[M, A])(f: => Const[M, A => B]): Const[M, B] =
Const(f.mo |+| fa.mo)
}
implicit def applicativeEmbed[F[_]]: Applicative[
({ type L[x] = Embed[F, x] })#L
] = new Applicative[({ type L[x] = Embed[F, x] })#L] {
def point[A](a: => A): Embed[F, A] = Embed(a)
def ap[A, B](fa: => Embed[F, A])(f: => Embed[F, A => B]): Embed[F, B] =
Embed(f.out(fa.out))
}
implicit def applicativeProductF[F[_[_], _], G[_[_], _], B[_]](implicit
fba: Applicative[({ type L[x] = F[B, x] })#L],
gba: Applicative[({ type L[x] = G[B, x] })#L]
): Applicative[({ type L[x] = ProductF[F, G, B, x] })#L] =
new Applicative[({ type L[x] = ProductF[F, G, B, x] })#L] {
def point[A](a: => A): ProductF[F, G, B, A] =
ProductF(fba.point(a), gba.point(a))
def ap[A, C](fa: => ProductF[F, G, B, A])(
f: => ProductF[F, G, B, A => C]
): ProductF[F, G, B, C] = ProductF(fba.ap(fa.f)(f.f), gba.ap(fa.g)(f.g))
}
Including the applicative instance for FixF itself:
implicit def applicativeFixF[F[_[_], _]](implicit
ffa: Applicative[({ type L[x] = F[({ type M[y] = FixF[F, y] })#M, x] })#L]
): Applicative[({ type L[x] = FixF[F, x] })#L] =
new Applicative[({ type L[x] = FixF[F, x] })#L] {
def point[A](a: => A): FixF[F, A] = new FixF(ffa.pure(a))
def ap[A, B](fa: => FixF[F, A])(f: => FixF[F, A => B]): FixF[F, B] =
new FixF(ffa.ap(fa.out)(f.out))
}
We'll also define the terminal transformation:
implicit def terminal[F[_], M: Monoid]: F ~> ({ type L[x] = Const[M, x] })#L =
new (F ~> ({ type L[x] = Const[M, x] })#L) {
def apply[A](fa: F[A]): Const[M, A] = Const(mzero[M])
}
But now we're in trouble. We really need some extra laziness in here, so we'll cheat a little:
def applicativeSum[F[_], G[_]](
fa: Applicative[F],
ga: => Applicative[G],
nt: G ~> F
): Applicative[({ type L[x] = Sum[F, G, x] })#L] =
new Applicative[({ type L[x] = Sum[F, G, x] })#L] {
def point[A](a: => A): Sum[F, G, A] = InR(ga.point(a))
def ap[A, B](x: => Sum[F, G, A])(f: => Sum[F, G, A => B]): Sum[F, G, B] =
(x, f) match {
case (InL(v), InL(f)) => InL(fa.ap(v)(f))
case (InR(v), InR(f)) => InR(ga.ap(v)(f))
case (InR(v), InL(f)) => InL(fa.ap(nt(v))(f))
case (InL(v), InR(f)) => InL(fa.ap(v)(nt(f)))
}
}
implicit def myListApplicative: Applicative[MyList] =
applicativeFixF[EmbedXUnitConstOr](
applicativeProductF[Embed, UnitConstOr, MyList](
applicativeEmbed[MyList],
applicativeSum[UnitConst, MyList](
applicativeConst[Unit],
myListApplicative,
terminal[MyList, Unit]
)
)
)
Maybe there's a way to get this to work with Scalaz 7's encoding of applicatives without the hack, but if there is I don't want to spend my Saturday afternoon figuring it out.
So that sucks, but at least now we can check our work:
scala> println((foo |#| bar)(_ ++ _))
FixF(ProductF(Embed(foobar),InL(Const(()))))
Which is exactly what we wanted.
Just by looking at the Haskell data type, I'd try the following class:
import scala.language.higherKinds
class FixF[F[_,_],A](val ffix: F[FixF[F,_],A]) extends AnyVal;
I'll try to expand the answer later when I learn more about FixF.