I recently happen to work with scalaz >>=. I put all the methods which should be bind with >>= in a list and foldleft as follows,
val dataMap:Map[K,V]
def call[F](funcList:List[funcOb[K, V, F]]):Either[F,Seq[(K,Option[V])]] = {
type t[a] = Either[F,a]
funcList.
map(v => {
v.funcs.
foldLeft((v.name,dataMap.get(v.name)).right[F])( _ >>= _ )
}
).sequence[t,(K,Option[V])]
}
case class funcOb[K,V,F]( name:K,
funcs:List[(K,Option[V]) => Either[F, (K, Option[V])]] = List.empty )
now I'm getting a funny error complaining that the required is similar to found
...: type mismatch;
[error] found : (K, Option[V]) => Either[F,(K, Option[V])]
[error] required: (K, Option[V]) => Either[F,(K, Option[V])]
[error] foldLeft((v.name,dataMap.get(v.name)).right[F])( _ >>= _ )
I cannot understand this behavour. Is there anything missing?
It requires a Function1[(A, B), C]. Your list contains functions of type Function2[A, B, C]. So you need to convert the function to tupled form before you can apply it.
The following works:
def call[F](funcList: List[funcOb[K, V, F]]): Either[F, Seq[(K, Option[V])]] = {
type t[a] = Either[F, a]
funcList.
map(v => {
v.funcs.
foldLeft((v.name, dataMap.get(v.name)).right[F])(_ >>= _.tupled)
}
).sequence[t, (K, Option[V])]
}
Related
I'm having trouble getting this implicit conversion to work properly.
I keep getting these errors:
[error]
found: (scala.collection.immutable.Map[O,scala.collection.immutable.Seq[D]], O) => scala.collection.immutable.Map[O,scala.collection.immutable.Seq[D]]
required:
(Object, Object) => Object
at (operToDocsMap: Map[O, Seq[D]], operator: O) =>
[error] type mismatch;
found : Object
required: scala.collection.immutable.Map[O,scala.collection.immutable.Seq[D]]
at .fold(operatorToDocsMap){
My code:
object ModelTypes {
trait Document
trait DocumentOperator {
def operatesOn[D <: Document](document: D): Boolean
}
class Documents[D <: Document](docs: Seq[D]) {
def groupByOperator[O <: DocumentOperator](operators: Seq[O])
: Map[O, Seq[D]] = {
docs.foldLeft(Map[O, Seq[D]]()) {
(operatorToDocsMap: Map[O, Seq[D]], document: D) =>
operators
.filter(_.operatesOn(document))
.fold(operatorToDocsMap){
(operToDocsMap: Map[O, Seq[D]], operator: O) =>
{operToDocsMap + (operator -> (document +: operToDocsMap.getOrElse(operator, Seq())))}
}
}
}
}
implicit def documentsConverter[D <: Document](docs: Seq[D]) =
new Documents(docs)
}
Is it something wrong with the type bounds?
Any help is greatly appreciated.
Below is more idiomatic way to achieve your requirement. This logic should give you the grouping between operators and documents without the use of convoluted nested foldJoins.
class Documents[D <: Document](docs: Seq[D]) {
def groupByOperator[O <: DocumentOperator](operators: Seq[O]): Map[O, Seq[D]] = {
val operatorDoc =
for {
doc <- docs
operator <- operators if operator.operatesOn(doc)
} yield (operator -> doc)
operatorDoc
.groupBy({ case (x, _) => x })
.mapValues(_.map({ case (_, x) => x }))
}
}
I'm in the process of learning a bit about Scala in order to see how it compares to F#, which is what I spend most of my time with. I'm attempting a pretty straightforward memoization technique for functions. In F# I would use something like this:
open System.Collections.Generic
let memoize (f : 'a -> 'b) =
// A dictionary in which to cache results of previous
// calls of the function
let dict = new Dictionary<'a, 'b>()
let memoizedFunction input =
match dict.TryGetValue(input) with
| true, x -> x
| false, _ ->
let answer = f input
dict.Add(input, answer)
answer
memoizedFunction
In attempting to produce an equivalent version of this in Scala I've come up with the following:
def memoize[A, B](f: A => B): A => B = {
val dict = collection.mutable.WeakHashMap[A, B]()
def memoizedFunction[A, B](input: A): B =
dict.get(input) match {
case x: Some[B] => x
case _ =>
val answer = f(input)
dict += ((input, answer))
answer
}
memoizedFunction _
}
I'm receiving a few errors in the REPL when I attempt to define this function:
<console>:11: error: type mismatch;
found : input.type (with underlying type A)
required: A
dict.get(input) match {
^
<console>:14: error: type mismatch;
found : input.type (with underlying type A)
required: A
val answer = f(input)
^
<console>:15: error: type mismatch;
found : input.type (with underlying type A)
required: A
dict += ((input, answer))
^
Can anyone point out where I'm going wrong here?
The type parameters on memoizedFunction shadow the outer type parameters. The nitty-gritty of Scala generics escapes me, but that's why input's type of A isn't the A that Scala is looking for.
Also, x: Some[B] conflicts with the return type of memoizedFunction, which is B. The idiomatic way to match Option is Some(x) => // do something with x.
So here's what I've got with those 2 things corrected:
def memoize[A, B](f: A => B): A => B = {
val dict = collection.mutable.WeakHashMap[A, B]()
def memoizedFunction(input: A): B =
dict.get(input) match {
case Some(x) => x
case _ =>
val answer = f(input)
dict += ((input, answer))
answer
}
memoizedFunction _
}
I am trying to implement an implicit function mapMetered that wraps map and functions exactly like it in terms of returning the correct type. I tried this:
implicit class MeteredGenTraversablePimp[T, C[T] <: GenTraversable[T]](trav: C[T]) {
def foreachMetered(m: Meter)(f: T => Unit) =
m.foreach(trav)(f)
def mapMetered[B, That](m: Meter)(f: (T) => B)(
implicit bf: CanBuildFrom[C[T], B, That]
): That = {
m.start()
try {
trav.map { x =>
val z = f(x)
m.item_processed()
z
} (bf)
} finally { m.finish() }
}
}
But when I try this I get an error:
[info] Compiling 1 Scala source to /Users/benwing/devel/textgrounder/target/classes...
[error] /Users/benwing/devel/textgrounder/src/main/scala/opennlp/textgrounder/util/metering.scala:223: type mismatch;
[error] found : scala.collection.generic.CanBuildFrom[C[T],B,That]
[error] required: scala.collection.generic.CanBuildFrom[scala.collection.GenTraversable[T],B,That]
[error] } (bf)
[error] ^
[error] one error found
There are similar Stack Overflow questions, including one from Daniel Sobral who suggests writing (trav: C[T] with GenTraversableLike[T]) but this doesn't fix the problem.
The Repr parameter in CanBuildFrom and in the *Like collection types is already there to represent the most precise type of the collection.
The solution to your problem is to wrap a GenTraversableLike[A,Repr] instead of a C[T].
The compiler will infer the exact type as Repr, and everything will work flawlessly:
implicit class MeteredGenTraversablePimp[A, Repr](trav: GenTraversableLike[A,Repr]) {
def foreachMetered(m: Meter)(f: A => Unit) = {
m.start()
try {
trav.foreach{ e => f( e ); m.item_processed() }
} finally {
m.finish()
}
}
def mapMetered[B, That](m: Meter)(f: A => B)(
implicit bf: CanBuildFrom[Repr, B, That]
): That = {
m.start()
trav.map { x: A =>
try {
val z: B = f(x)
m.item_processed()
z
} finally { m.finish() }
}(bf)
}
}
I am having trouble getting my code with parameterized types to pass the scala compiler. My goal is to be able to express (Predicate, Action) pairs as shown in the MyProg object.
trait ProgBase {
type Predicate[T] = T => Boolean
type Action[T] = T => Unit
private var prog = List[(Predicate[Any], Action[Any])]()
final def on[T <: Any](pred: Predicate[T])(action: Action[T]) = {
prog = (pred, action) :: prog // gives type mismatch
}
// remainder of trait elided
}
object MyProg extends ProgBase {
on[String](s => !s.isEmpty) { s =>
println(s + " is not empty")
}
on[Int](i => i.isValidByte) { i =>
println(i + " can fit in a byte")
}
}
By specifying that T has an upper bound of Any, I hoped this would appease the compiler, but clearly I am missing something:
[error] ......ProgBase.scala:8 type mismatch;
[error] found : (T => Boolean, T => Unit)
[error] required: (Any => Boolean, Any => Unit)
[error] prog = (pred, action) :: prog
[error] ^
First of all, answer to your question, if you write:
private var prog = List[(Predicate[_ <: Any], Action[_ <: Any])]()
It all compiles OK. We should use wildcards, 'cause the type of elements are unknown.
Second, maybe you mistyped, you can't use your on function as you used it, use it something like:
on[String](s => !s.isEmpty)(s => !s.isEmpty)
It caused by type mismatch: type Action[T] = T => Unit but println has type Unit,
so as a variant u can simply write: type Action = Unit. Obviously, u can avoid using this type alias at all.
Third, maybe you already know, and I shoudn't tell you, that in fact, you lose all information about predicate types - let's check it using Scala reflection:
import scala.reflect.runtime.{universe => ru}
def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
val s: String = "123"
val i: Int = 123
on[String](s => !s.isEmpty)(s => !s.isEmpty)
on[Int](i => i.isValidByte)(i => i.isValidByte)
getTypeTag((MyProg.prog.head._1)).tpe =:= ru.typeOf[(String) => Boolean] //>false!
So you see the problem.
To deal with it you can use heterogeneous lists. Lists and other various powerful structures you can find in shapeless: https://github.com/milessabin/shapeless
Suppose I have a list of functions as so:
val funcList = List(func1: A => T, func2: B => T, func2: C => T)
(where func1, et al. are defined elsewhere)
I want to write a method that will take a value and match it to the right function based on exact type (match a: A with func1: A => T) or throw an exception if there is no matching function.
Is there a simple way to do this?
This is similar to what a PartialFunction does, but I am not able to change the list of functions in funcList to PartialFunctions. I am thinking I have to do some kind of implicit conversion of the functions to a special class that knows the types it can handle and is able to pattern match against it (basically promoting those functions to a specialized PartialFunction). However, I can't figure out how to identify the "domain" of each function.
Thank you.
You cannot identify the domain of each function, because they are erased at runtime. Look up erasure if you want more information, but the short of it is that the information you want does not exist.
There are ways around type erasure, and you'll find plenty discussions on Stack Overflow itself. Some of them come down to storing the type information somewhere as a value, so that you can match on that.
Another possible solution is to simply forsake the use of parameterized types (generics in Java parlance) for your own customized types. That is, doing something like:
abstract class F1 extends (A => T)
object F1 {
def apply(f: A => T): F1 = new F1 {
def apply(n: A): T = f(n)
}
}
And so on. Since F1 doesn't have type parameters, you can match on it, and you can create functions of this type easily. Say both A and T are Int, then you could do this, for example:
F1(_ * 2)
The usual answer to work around type erasure is to use the help of manifests. In your case, you can do the following:
abstract class TypedFunc[-A:Manifest,+R:Manifest] extends (A => R) {
val retType: Manifest[_] = manifest[R]
val argType: Manifest[_] = manifest[A]
}
object TypedFunc {
implicit def apply[A:Manifest, R:Manifest]( f: A => R ): TypedFunc[A, R] = {
f match {
case tf: TypedFunc[A, R] => tf
case _ => new TypedFunc[A, R] { final def apply( arg: A ): R = f( arg ) }
}
}
}
def applyFunc[A, R, T >: A : Manifest]( funcs: Traversable[TypedFunc[A,R]] )( arg: T ): R = {
funcs.find{ f => f.argType <:< manifest[T] } match {
case Some( f ) => f( arg.asInstanceOf[A] )
case _ => sys.error("Could not find function with argument matching type " + manifest[T])
}
}
val func1 = { s: String => s.length }
val func2 = { l: Long => l.toInt }
val func3 = { s: Symbol => s.name.length }
val funcList = List(func1: TypedFunc[String,Int], func2: TypedFunc[Long, Int], func3: TypedFunc[Symbol, Int])
Testing in the REPL:
scala> applyFunc( funcList )( 'hello )
res22: Int = 5
scala> applyFunc( funcList )( "azerty" )
res23: Int = 6
scala> applyFunc( funcList )( 123L )
res24: Int = 123
scala> applyFunc( funcList )( 123 )
java.lang.RuntimeException: Could not find function with argument matching type Int
at scala.sys.package$.error(package.scala:27)
at .applyFunc(<console>:27)
at .<init>(<console>:14)
...
I think you're misunderstanding how a List is typed. List takes a single type parameter, which is the type of all the elements of the list. When you write
val funcList = List(func1: A => T, func2: B => T, func2: C => T)
the compiler will infer a type like funcList : List[A with B with C => T].
This means that each function in funcList takes a parameter that is a member of all of A, B, and C.
Apart from this, you can't (directly) match on function types due to type erasure.
What you could instead do is match on a itself, and call the appropriate function for the type:
a match {
case x : A => func1(x)
case x : B => func2(x)
case x : C => func3(x)
case _ => throw new Exception
}
(Of course, A, B, and C must remain distinct after type-erasure.)
If you need it to be dynamic, you're basically using reflection. Unfortunately Scala's reflection facilities are in flux, with version 2.10 released a few weeks ago, so there's less documentation for the current way of doing it; see How do the new Scala TypeTags improve the (deprecated) Manifests?.