kind-projector returns strange results - scala

I have these types:
SomeTypeClass
A higher kinded type which has one type parameter of kind * => * => *
trait SomeTypeClass[P[_, _]] {
def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: P[A, B])
(implicit ev: Strong[P],
ev2: Choice[P],
ev3: Applicative[F]): P[S, T]
}
Target which accepts three type parameters: type constructor F[_] and two polymorphic types A, B
case class Target[F[_], A, B](f: A => F[B])
I want to implement an instance of SomeTypeClass of Target.
I am using the kind-projector plugin in order to create a partially applied type.
My desired method signature should be:
implicit def instance: SomeTypeClass[Target[F, *, *]] = new SomeTypeClass[Target[F, *, *]] {
override def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: Target[F, A, B])
(implicit ev: Strong[Target[F, *, *]],
ev2: Choice[Target[F, *, *]],
ev3: Applicative[F]): Target[F, S, T] = ???
}
I've tried using this syntax using two star parameters:
implicit def instance[F[_]]: SomeTypeClass[Target[F, *, *]] = new SomeTypeClass[Target[F, *, *]] {
override def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: Target[F, A, B])
(implicit ev: Strong[Target[F, *, *]],
ev2: Choice[Target[F, *, *]],
ev3: Applicative[F]): Target[F, S, T] = ???
}
But the F[_] declared at the instance level shadows the F[_] declared at the test method (I want them to be the same F), so I've moved to the λ syntax and got two different unwanted results.
The first one using λ[(F, A, B) => Target[F, A, B]] generated for the pab paramter,
pab: Target[A, B, B] instead of pab: Target[F, A, B] and also for the return type Target[S, T, B] instead of Target[F, S, T]
The second one using the F at the end of the triple type lambda parameters (why???) λ[(A, B, F) => Target[F, A, B]] generated the correct types for the pab parameter and the return type, but
for each one of the implicit parameters the type Strong[λ[(A, B, F) => Target[F, A, B]]] instead of
Strong[Target[F, *, *]]]
The full code:
import cats.Applicative
import cats.arrow.{Choice, Strong}
final case class Target[F[_], A, B](f: A => F[B])
trait SomeTypeClass[P[_, _]] {
def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: P[A, B])
(implicit ev: Strong[P],
ev2: Choice[P],
ev3: Applicative[F]): P[S, T]
}
object SomeTypeClass {
implicit def instance1: SomeTypeClass[λ[(F, A, B) => Target[F, A, B]]] = new SomeTypeClass[λ[(F, A, B) => Target[F, A, B]]] {
override def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: Target[A, B, B])
(implicit ev: Strong[Target],
ev2: Choice[Target],
ev3: Applicative[F]): Target[S, T, B] = ???
}
implicit def instance2: SomeTypeClass[λ[(A, B, F) => Target[F, A, B]]] = new SomeTypeClass[λ[(A, B, F) => Target[F, A, B]]] {
override def test[F[_], S, T, A, B](f: (A => F[B]) => S => F[T])
(pab: Target[F, A, B])
(implicit ev: Strong[λ[(A, B, F) => Target[F, A, B]]],
ev2: Choice[λ[(A, B, F) => Target[F, A, B]]],
ev3: Applicative[F]): Target[F, S, T] = ???
}
}
Can I achieve the desired syntax using this plugin? Why does the plugin generate different types
for different order of type lambda's 'parameters'?

If I understood
But the F[_] declared at the instance level shadows the F[_] declared at the test method (I want them to be the same F)
correctly, you want your instance for SomeTypeClass[Target[...]] to fix the F[_] parameter of test. But that's simply not possible with this test type signature. Once you have (for example)
val inst = implicitly[SomeTypeClass[Target[...]]
you can call
val res1 = inst.test[List, ...]
val res2 = inst.test[Option, ...]
Type lambdas don't offer a way around this problem. You need to either move F[_] parameter to SomeTypeClass or implement
implicit def instance[F[_]]: SomeTypeClass[Target[F, *, *]] = new SomeTypeClass[Target[F, *, *]] {
override def test[G[_], S, T, A, B](f: (A => G[B]) => S => G[T])
(pab: Target[F, A, B])
(implicit ev: Strong[Target[F, *, *]],
ev2: Choice[Target[F, *, *]],
ev3: Applicative[G]): Target[G, S, T] = ???
}
which I expect is impossible as you can't pass pab.f to f.
EDIT: the type of wander
class (Choice p, Strong p) => Traversing p where
traverse' :: Traversable f => p a b -> p (f a) (f b)
traverse' = wander traverse
wander :: (forall f. Applicative f => (a -> f b) -> s -> f t) -> p a b -> p s t
wander f pab = dimap (\s -> Baz $ \afb -> f afb s) sold (traverse' pab)
is a rank-2 type which aren't supported in Scala directly; instead you need to introduce a helper (which can't just be a type alias as it is in Control.Lens.Type)
trait Traversal[S, T, A, B] {
def apply[F[_]: Applicative](f: A => F[B]): S => F[T]
}
Then
trait Traversing[P[_, _]] extends Strong[P] with Choice[P] {
def wander[S, T, A, B](t: Traversal[S, T, A, B], pab: P[A, B]): P[S, T]
}
implicit def instance[F[_]: Applicative]: Traversing[Target[F, *, *]] = new Traversing[Target[F, *, *]] {
def wander[S, T, A, B](t: Traversal[S, T, A, B], pab: Target[F, A, B]): Target[F, S, T] = Target(t(pab.f))
// define Strong and Choice methods too
}
should work. (Though I am not sure this is the cats way to deal with Strong and Choice requirements.)

Related

Mapping over collections and returning the same type of container as the input

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)

passing args to fns of n parameters in a syntactically consistent way

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

How do we end with GenTraversableOnce in flatMap method?

Here is the signature for flatMap:
def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That
For example it:Iterable[Option[T]] can be converted to Iterable[T] calling:
it.flatMap(x => x)
So That is Iterable[T], but what is then B, and how does x => x : (Option[T] => Option[T]) correspond to f ???
A is Option[T], B is T
There is implicit conversion from Option to Iterable, which is a subtype of GenTraversableOnce.

Invoke a Scala Function2 with a shapeless HList whose values do not match the argument order

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).

Defining Haskell FixF in scala

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.