scala3 how to make generic zipWith extension method - scala

I was trying to make a simple extension method zipWith that just maps a collection C[A] to C[(A, B)] like this:
List(1,2,3) zipWith (_ * 2)
// List((1,2), (2,4), (3,6))
I tried with this:
scala> extension[A, C[_] <: Iterable[_]] (s: C[A]) def zipWith[B](f: A => B): C[(A, B)] = s map ((x) => (x, f(x)))
-- Error:
1 |extension[A, C[_] <: Iterable[_]] (s: C[A]) def zipWith[B](f: A => B): C[(A, B)] = s map ((x) => (x, f(x)))
| ^
| Found: (x : Any)
| Required: A
What am I missing with this?

You can use IterableOnceOps as explained here.
import scala.collection.IterableOnceOps
extension [A, CC[_]](it: IterableOnceOps[A, CC, Any])
def zipWith[B](f: A => B): CC[(A, B)] =
it.map(a => (a, f(a)))
You can see the code running here.

Related

How to write a exstension map inner for a generic iterator in scala without losing type information

I've tried
exstension[A] (f: Iterator[Iterator[A]){
def mapInner[B](f: A => B): Iterator[Iterator[B]
but this loses type information since if I give it a list[list[Int]] I get back Iterator[Iterator[Int]
Try functors and friends:
trait Functor[F[_]]:
extension [A](fa: F[A]) def fmap[B](fmap: A => B): F[B]
object Functor:
given Functor[List] with
extension [A](fa: List[A]) def fmap[B](fmap: A => B): List[B] =
fa.map(fmap)
given [F[_], G[_]](using F: Functor[F], G: Functor[G]): Functor[[x] =>> F[G[x]]] with
extension [A](fa: F[G[A]]) def fmap[B](fmap: A => B): F[G[B]] =
F.fmap(fa)(ga => G.fmap(ga)(fmap))
import Functor.given
val xs = List(1, 2, 3, 4)
val xss = xs.map(x => List(x, x))
val fxss = summon[Functor[[x] =>> List[List[x]]]]
println(fxss.fmap(xss)((a: Int) => a * 2))
It's a lot of setup but likely you don't have to do it yourself and use a library like scalaz or cats where all these things are already defined.

Why eta-expansion of polymorphic method does not result in polymorphic function value?

Scala 2 does not have polymorphic function values so eta-expanding polymorphic methods gives only
scala> def f[A](a: A): A = ???
def f[A](a: A): A
scala> f _
val res0: Nothing => Nothing = $Lambda$7757/1502613782#45af2c1
However Scala 3 does have polymorphic function values so why eta-expanding polymorphic methods does not give more than
scala> def f[A](a: A): A = ???
def f[A](a: A): A
scala> f
val res0: Any => Any = Lambda$7538/1430563609#4a905603
scala> val g: ([A] => A => A) = f
1 |val g: ([A] => A => A) = f
| ^
| Found: Any => Any
| Required: PolyFunction{apply: [A](x$1: A): A}

Inconsistency between `MkNthFieldLens` and `>>(n: Nat)` in Shapeless 2.1

Suppose, I want to modify the first element of a tuple using shapeless lenses.
With witness:
import shapeless._
def modifyKey[A,B](t: (A, B))(f: A => A)(implicit mk: MkNthFieldLens[(A,B), _1]) =
(lens[(A, B)] >> '_1).modify(t)(f)
With Nat:
import nat._
def modifyKey[A,B](t: (A, B))(f: A => A) = (lens[(A, B)] >> _0).modify(t)(f)
So I have to use >> _0 instead of >> _1 here, otherwise it's trying to take B:
scala> def modifyKey[A,B](t: (A, B))(f: A => A) = (lens[(A, B)] >> _1).modify(t)(f)
<console>:13: error: type mismatch;
found : A => A
required: B => B
def modifyKey[A,B](t: (A, B))(f: A => A) = (lens[(A, B)] >> _1).modify(t)(f)
^
Is such "0 vs 1" numeration is intentional, or am I having some trouble with my Shapeless (I use 2.1 version with scala 2.11.5)?

How should I write this higher order function where the parameter func needs an implicit view?

I have a function that makes use of an implicit view to a Seq[A], you can see it makes use of the head method and preserves types:-
scala> def needSeq[A, C <% Seq[A]](col: C) = { (col.head , col) }
needSeq: [A, C](col: C)(implicit evidence$1: C => Seq[A])(A, C)
scala> needSeq(List(1,2,3))
res0: (Int, List[Int]) = (1,List(1, 2, 3))
scala> needSeq(List("a","b"))
res1: (java.lang.String, List[java.lang.String]) = (a,List(a, b))
scala> needSeq(Array("a","b"))
res2: (java.lang.String, Array[java.lang.String]) = (a,Array(a, b))
I want to write a function that takes functions like needSeq and applies them to arguments
scala> def useFunc[A, C <% Seq[A], R](col: C)(f: C => R) = { f(col) }
useFunc: [A, C, R](col: C)(f: C => R)(implicit evidence$1: C => Seq[A])R
The problem is because only one type (C) is provided in the parameter list there is no implicit view from C => Seq[A] available
scala> useFunc(List(1,2,3))(needSeq)
<console>:10: error: No implicit view available from C => Seq[A].
useFunc(List(1,2,3))(needSeq)
^
How should I write useFunc?
The problem is in definition needSeq..
if you can try to refactor it to..
def needSeq[A](col : Seq[A]) = (col.head , col)
then both of these cases works..
useFunc(List(1,2,3))(needSeq) //> res1: (Int, Seq[Int]) = (1,List(1, 2, 3))
useFunc(List(1,2,3))(x => needSeq(x)) //> res2: (Int, Seq[Int]) = (1,List(1, 2, 3))
I think that solution from #Eastsun
useFunc(List(1,2,3))(x => needSeq(x))
works because the C from
def useFunc[A, C <% Seq[A], R](col: C)(f: C => R)
is now represented by the x and kind of connects the type of the List with the type of parameter that the needSeq takes
or one could say that the two lines above better resemble each other that way :
def useFunc[A, C <% Seq[A], R] (col: C) (f: C => R)
useFunc (List(1,2,3)) (x => needSeq(x))

Is it possible to implement liftM2 in Scala?

In Haskell, liftM2 can be defined as:
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 f m1 m2 = do
x1 <- m1
x2 <- m2
return $ f x1 x2
I'd like to translate this to Scala. My first attempt was the following:
def liftM2[T1, T2, R, M[_]](f: (T1, T2) => R)(ma: M[T1], mb: M[T2]) : M[R] = for {
a <- ma
b <- mb
} yield f(a, b)
This fails in what I guess is the most obvious way possible: "value flatMap is not a member of type parameter M[T1]". Right, I haven't indicated that M[_] is some kind of monad. So the next thing I tried was to define some structural type like:
type Monad[A] = {
def flatMap[B](f: (A) => Monad[B]): Monad[B]
}
... and to have M[A] <: Monad[A]. But that doesn't work, because Scala doesn't have recursive structural types.
So the next few things I tried involved gyrations similar to M[A] <: FilterMonadic[A, _]. Those all failed, probably because I wasn't able to figure out the right implicit-fu for CanBuildFrom.
The most closely-related question I could find here on StackOverflow was this one, touching both on recursive structural types and how to mimic Haskell's typeclasses in Scala. But that approach requires defining an implicit conversion from each type you care about to the trait defining the typeclass, which seems terribly circular in this case...
Is there any good way to do what I'm trying to do?
The usual way to encode type classes in Scala turns out to follow Haskell pretty closely: List doesn't implement a Monad interface (as you might expect in an object-oriented language), but rather we define the type class instance in a separate object.
trait Monad[M[_]] {
def point[A](a: => A): M[A]
def bind[A, B](ma: M[A])(f: A => M[B]): M[B]
def map[A, B](ma: M[A])(f: A => B): M[B] = bind(ma)(a => point(f(a)))
}
implicit object listMonad extends Monad[List] {
def point[A](a: => A) = List(a)
def bind[A, B](ma: List[A])(f: A => List[B]) = ma flatMap f
}
This idea is introduced in Poor Man's Type Classes and explored more deeply in Type Classes as Objects and Implicits. Notice that the point method could not have been defined in an object-oriented interface, as it doesn't have M[A] as one of it's arguments to be converted to the this reference in an OO encoding. (Or put another way: it can't be part of an interface for the same reason a constructor signature can't be represented in an interface.)
You can then write liftM2 as:
def liftM2[M[_], A, B, C](f: (A, B) => C)
(implicit M: Monad[M]): (M[A], M[B]) => M[C] =
(ma, mb) => M.bind(ma)(a => M.map(mb)(b => f(a, b)))
val f = liftM2[List, Int, Int, Int](_ + _)
f(List(1, 2, 3), List(4, 5)) // List(5, 6, 6, 7, 7, 8)
This pattern has been applied extensively in Scalaz. Version 7, currently in development, includes an index of the type classes.
In addition to providing type classes and instances for standard library types, it provides a 'syntactic' layer that allows the more familiar receiver.method(args) style of method invocation. This often affords better type inference (accounting for Scala's left-to-right inference algorithm), and allows use of the for-comprehension syntactic sugar. Below, we use that to rewrite liftM2, based on the map and flatMap methods in MonadV.
// Before Scala 2.10
trait MonadV[M[_], A] {
def self: M[A]
implicit def M: Monad[M]
def flatMap[B](f: A => M[B]): M[B] = M.bind(self)(f)
def map[B](f: A => B): M[B] = M.map(self)(f)
}
implicit def ToMonadV[M[_], A](ma: M[A])
(implicit M0: Monad[M]) =
new MonadV[M, A] {
val M = M0
val self = ma
}
// Or, as of Scala 2.10
implicit class MonadOps[M[_], A](self: M[A])(implicit M: Monad[M]) {
def flatMap[B](f: A => M[B]): M[B] = M.flatMap(self)(f)
def map[B](f: A => B): M[B] = M.map(self)(f)
}
def liftM2[M[_]: Monad, A, B, C](f: (A, B) => C): (M[A], M[B]) => M[C] =
(ma, mb) => for {a <- ma; b <- mb} yield f(a, b)
Update
Yep, its possible to write less generic version of liftM2 for the Scala collections. You just have to feed in all the required CanBuildFrom instances.
scala> def liftM2[CC[X] <: TraversableLike[X, CC[X]], A, B, C]
| (f: (A, B) => C)
| (implicit ba: CanBuildFrom[CC[A], C, CC[C]], bb: CanBuildFrom[CC[B], C, CC[C]])
| : (CC[A], CC[B]) => CC[C] =
| (ca, cb) => ca.flatMap(a => cb.map(b => f(a, b)))
liftM2: [CC[X] <: scala.collection.TraversableLike[X,CC[X]], A, B, C](f: (A, B) => C)(implicit ba: scala.collection.generic.CanBuildFrom[CC[A],C,CC[C]], implicit bb: scala.collection.generic.CanBuildFrom[CC[B],C,CC[C]])(CC[A], CC[B]) => CC[C]
scala> liftM2[List, Int, Int, Int](_ + _)
res0: (List[Int], List[Int]) => List[Int] = <function2>
scala> res0(List(1, 2, 3), List(4, 5))
res1: List[Int] = List(5, 6, 6, 7, 7, 8)