How to apply a function to a matrix? - scala

This is a follow-up to my previous question
Now I know that cats provides an instance of Apply for Vector. So I can write:
import cats.implicits._
scala> val f: Int => Int = _ + 2
f: Int => Int = <function1>
scala> Vector(f) ap Vector(1, 2, 3)
res18: scala.collection.immutable.Vector[Int] = Vector(3, 4, 5)
Now I wonder how apply to f to all elements of a matrix defined as Vector[Vector[Int]. Does cats provide an Apply instance for matrices ?

In order to use ap on Vector[Vector[Int]], you'll need f lifted to a Vector[Vector[A => B]]. One possible way is:
import cats.Apply
import cats.implicits._
val f: Int => Int = _ + 2
val vectorOfVectors = Apply[Vector] compose Apply[Vector]
val vec = Vector(Vector(1,2), Vector(3,4))
val res: Vector[Vector[Int]] = vectorOfVectors.ap(Vector(Vector(f)))(vec)
Yields:
Vector(3, 4)
Vector(5, 6)
A nicer way IMO is to use Nested:
Using kind-projector in build.sbt:
addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.4")
And then:
import cats.Functor
import cats.data.Nested
import cats.implicits._
val f: Int => Int = _ + 2
val vec = Vector(Vector(1,2), Vector(3,4))
val nested: Nested[Vector, Vector, Int] = Nested(vec)
val res: Nested[Vector, Vector, Int] = Functor[Nested[Vector, Vector, ?]].map(nested)(f)
val result: Vector[Vector[Int]] = res.value
Note how using Nested means we can apply f with no lifting at all.

Related

How to avoid calling toVector on each Scala for comprehension / yield?

I have several methods that operate on Vector sequences and the following idiom is common when combining data from multiple vectors into a single one with the use of a for comprehension / yield:
(for (i <- 0 until y.length) yield y(i) + 0.5*dy1(i)) toVector
Notice the closing toVector and the enclosing parentheses around the for comprehension. I want to get rid of it because it's ugly, but removing it produces the following error:
type mismatch;
found : scala.collection.immutable.IndexedSeq[Double]
required: Vector[Double]
Is there a better way of achieving what I want that avoids explicitly calling toVector many times to essentially achieve a non-operation (converting and indexed sequence...to an indexed sequence)?
One way to avoid collection casting, e.g. toVector, is to invoke, if possible, only those methods that return the same collection type.
y.zipWithIndex.map{case (yv,idx) => yv + 0.5*dy1(idx)}
for yield on Range which you are using in your example yields a Vector[T] by default.
example,
scala> val squares= for (x <- Range(1, 3)) yield x * x
squares: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4)
check the type,
scala> squares.isInstanceOf[Vector[Int]]
res14: Boolean = true
Note that Vector[T] also extends IndexedSeq[T].
#SerialVersionUID(-1334388273712300479L)
final class Vector[+A] private[immutable] (private[collection] val startIndex: Int, private[collection] val endIndex: Int, focus: Int)
extends AbstractSeq[A]
with IndexedSeq[A]
with GenericTraversableTemplate[A, Vector]
with IndexedSeqLike[A, Vector[A]]
with VectorPointer[A #uncheckedVariance]
with Serializable
with CustomParallelizable[A, ParVector[A]]
That's why above result is also an instance of IndexedSeq[T],
scala> squares.isInstanceOf[IndexedSeq[Int]]
res15: Boolean = true
You can define the type of your result as IndexedSeq[T] and still achieve what you want with Vector without explicitly calling .toVector
scala> val squares: IndexedSeq[Int] = for (x <- Range(1, 3)) yield x * x
squares: IndexedSeq[Int] = Vector(1, 4)
scala> squares == Vector(1, 4)
res16: Boolean = true
But for yield on Seq[T] gives List[T] by default.
scala> val squares = for (x <- Seq(1, 3)) yield x * x
squares: Seq[Int] = List(1, 9)
Only in that case if you want vector you must .toVector the result.
scala> squares.isInstanceOf[Vector[Int]]
res21: Boolean = false
scala> val squares = (for (x <- Seq(1, 3)) yield x * x).toVector
squares: Vector[Int] = Vector(1, 9)

How to select elements of collection based on another of different type?

I know I can do this:
scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)
scala> val b = List(2,4)
b: List[Int] = List(2, 4)
scala> a.filterNot(b.toSet)
res0: List[Int] = List(1, 3)
But I'd like to select elements of a collection based on their integer key, as in the following:
case class N (p: Int , q: Int)
val x = List(N(1,100), N(2,200), N(3,300))
val y = List(2,4)
val z = .... ?
Z // want Z to be ((N1,100), (N3,300)) after removing the items of type N with 'p'
// matching any item in list y.
I know one way to do it is is something like the following which makes the above broken code work:
val z = x.filterNot(e => y.contains(e.p))
but this seems very inefficient. Is there a better way?
Just do
val z = y.toSet
x.filterNot {z.contains(_.p)}
That's linear.
The problem with contains is that the search will be a linear search and you are looking at O(N^2) solution(which is still OK, if the dataset is not large)
Anyways, a simple solution can be to use Binary search to get O(NlnN) solution. You can easily convert val y to Array from list and then use java's binary search method.
scala> case class N(p: Int, q: Int)
defined class N
scala> val x = List(N(1, 100), N(2, 200), N(3, 300))
x: List[N] = List(N(1,100), N(2,200), N(3,300))
scala> val y = Array(2, 4) // Using Array directly.
y: Array[Int] = Array(2, 4)
scala> val z = x.filterNot(e => java.util.Arrays.binarySearch(y, e.p) >= 0)
z: List[N] = List(N(1,100), N(3,300))

`val (A) = (3)` is correct, but `val (A,B)=(2,3)` can't be compiled, why?

val A = 3
val (A) = (3)
Both correct. But:
val (A,B) = (2,3)
can't be compiled:
scala> val (A,B) = (2,3)
<console>:7: error: not found: value A
val (A,B) = (2,3)
^
<console>:7: error: not found: value B
val (A,B) = (2,3)
^
Why?
In the second code snippet, it using pattern matching to do assessment.
It is translated to the follow code:
val Tuple(A, B) = Tuple2(2,3)
When Scala is doing pattern matching, variable starts with a upper case in the pattern is considered as an constant value (or singleton Object), so val (a, b) = (2, 3) works but not val (A, B) = (2, 3).
BTW, your first code snippet does not using pattern matching, it's just an ordinary variable assignment.
If you using Tuple1 explicitly, it will have same error.
scala> val Tuple1(Z) = Tuple1(3)
<console>:7: error: not found: value Z
val Tuple1(Z) = Tuple1(3)
Here is some interesting example:
scala> val A = 10
A: Int = 10
scala> val B = 20
B: Int = 20
scala> val (A, x) = (10, 20)
x: Int = 20
scala> val (A, x) = (10, 30)
x: Int = 30
scala> val (A, x) = (20, 20)
scala.MatchError: (20,20) (of class scala.Tuple2$mcII$sp)
at .<init>(<console>:9)
at .<clinit>(<console>)

scalaz List[StateT].sequence - could not find implicit value for parameter n: scalaz.Applicative

I'm trying to figure out how to use StateT to combine two State state transformers based on a comment on my Scalaz state monad examples answer.
It seems I'm very close but I got an issue when trying to apply sequence.
import scalaz._
import Scalaz._
import java.util.Random
val die = state[Random, Int](r => (r, r.nextInt(6) + 1))
val twoDice = for (d1 <- die; d2 <- die) yield (d1, d2)
def freqSum(dice: (Int, Int)) = state[Map[Int,Int], Int]{ freq =>
val s = dice._1 + dice._2
val tuple = s -> (freq.getOrElse(s, 0) + 1)
(freq + tuple, s)
}
type StateMap[x] = State[Map[Int,Int], x]
val diceAndFreqSum = stateT[StateMap, Random, Int]{ random =>
val (newRandom, dice) = twoDice apply random
for (sum <- freqSum(dice)) yield (newRandom, sum)
}
So I got as far as having a StateT[StateMap, Random, Int] that I can unwrap with initial random and empty map states:
val (freq, sum) = diceAndFreqSum ! new Random(1L) apply Map[Int,Int]()
// freq: Map[Int,Int] = Map(9 -> 1)
// sum: Int = 9
Now I'd like to generate a list of those StateT and use sequence so that I can call list.sequence ! new Random(1L) apply Map[Int,Int](). But when trying this I get:
type StT[x] = StateT[StateMap, Random, x]
val data: List[StT[Int]] = List.fill(10)(diceAndFreqSum)
data.sequence[StT, Int]
//error: could not find implicit value for parameter n: scalaz.Applicative[StT]
data.sequence[StT, Int]
^
Any idea? I can use some help for the last stretch - assuming it's possible.
Ah looking at the scalaz Monad source, I noticed there was an implicit def StateTMonad that confirms that StateT[M, A, x] is a monad for type parameter x. Also monads are applicatives, which was confirmed by looking at the definition of the Monad trait and by poking in the REPL:
scala> implicitly[Monad[StT] <:< Applicative[StT]]
res1: <:<[scalaz.Monad[StT],scalaz.Applicative[StT]] = <function1>
scala> implicitly[Monad[StT]]
res2: scalaz.Monad[StT] = scalaz.MonadLow$$anon$1#1cce278
So this gave me the idea of defining an implicit Applicative[StT] to help the compiler:
type StT[x] = StateT[StateMap, Random, x]
implicit val applicativeStT: Applicative[StT] = implicitly[Monad[StT]]
That did the trick:
val data: List[StT[Int]] = List.fill(10)(diceAndFreqSum)
val (frequencies, sums) =
data.sequence[StT, Int] ! new Random(1L) apply Map[Int,Int]()
// frequencies: Map[Int,Int] = Map(10 -> 1, 6 -> 3, 9 -> 1, 7 -> 1, 8 -> 2, 4 -> 2)
// sums: List[Int] = List(9, 6, 8, 8, 10, 4, 6, 6, 4, 7)

Scalaz Kleisli question

There is a trait called Kleisli in the scalaz library. Looking at the code:
import scalaz._
import Scalaz._
type StringPair = (String, String)
val f: Int => List[String] = (i: Int) => List((i |+| 1).toString, (i |+| 2).toString)
val g: String => List[StringPair] = (s: String) => List("X" -> s, s -> "Y")
val k = kleisli(f) >=> kleisli(g) //this gives me a function: Int => List[(String, String)]
Calling the function k with the value of 2 gives:
println( k(2) ) //Prints: List((X,3), (3,Y), (X,4), (4,Y))
My question is: how would I use Scalaz to combine f and g to get a function m such that the output of m(2) would be:
val m = //??? some combination of f and g
println( m(2) ) //Prints: List((X,3), (X,4), (3,Y), (4,Y))
Is this even possible?
Seems like you want transpose. Scalaz doesn't supply this, but it should be easy to write. The function m that you want is val m = f andThen (_.map(g)) andThen transpose andThen (_.join)