I am struggling on how to create an instance of Functor[Dataset]... the problem is that when you map from A to B the Encoder[B] must be in the implicit scope but I am not sure how to do it.
implicit val datasetFunctor: Functor[Dataset] = new Functor[Dataset] {
override def map[A, B](fa: Dataset[A])(f: A => B): Dataset[B] = fa.map(f)
}
Of course this code is throwing a compilation error since Encoder[B] is not available but I can't add Encoder[B] as an implicit parameter because it would change the map method signature, how can I solve this?
You cannot apply f right away, because you are missing the Encoder. The only obvious direct solution would be: take cats and re-implement all the interfaces, adding an implict Encoder argument. I don't see any way to implement a Functor for Dataset directly.
However maybe the following substitute solution is good enough.
What you could do is to create a wrapper for the dataset, which has a map method without the implicit Encoder, but additionally has a method toDataset, which needs the Encoder in the very end.
For this wrapper, you could apply a construction which is very similar to the so-called Coyoneda-construction (or Coyo? What do they call it today? I don't know...). It essentially is a way to implement a "free functor" for an arbitrary type constructor.
Here is a sketch (it compiles with cats 1.0.1, replaced Spark traits by dummies):
import scala.language.higherKinds
import cats.Functor
/** Dummy for spark-Encoder */
trait Encoder[X]
/** Dummy for spark-Dataset */
trait Dataset[X] {
def map[Y](f: X => Y)(implicit enc: Encoder[Y]): Dataset[Y]
}
/** Coyoneda-esque wrapper for `Dataset`
* that simply stashes all arguments to `map` away
* until a concrete `Encoder` is supplied during the
* application of `toDataset`.
*
* Essentially: the wrapped original dataset + concatenated
* list of functions which have been passed to `map`.
*/
abstract class MappedDataset[X] private () { self =>
type B
val base: Dataset[B]
val path: B => X
def toDataset(implicit enc: Encoder[X]): Dataset[X] = base map path
def map[Y](f: X => Y): MappedDataset[Y] = new MappedDataset[Y] {
type B = self.B
val base = self.base
val path: B => Y = f compose self.path
}
}
object MappedDataset {
/** Constructor for MappedDatasets.
*
* Wraps a `Dataset` into a `MappedDataset`
*/
def apply[X](ds: Dataset[X]): MappedDataset[X] = new MappedDataset[X] {
type B = X
val base = ds
val path = identity
}
}
object MappedDatasetFunctor extends Functor[MappedDataset] {
/** Functorial `map` */
def map[A, B](da: MappedDataset[A])(f: A => B): MappedDataset[B] = da map f
}
Now you can wrap a dataset ds into a MappedDataset(ds), then map it using the implicit MappedDatasetFunctor as long as you want, and then call toDataset in the very end, there you can supply a concrete Encoder for the final result.
Note that this will combine all functions inside map into a single spark stage: it won't be able to save the intermediate results, because the Encoders for all intermediate steps are missing.
I'm not quite there yet with studying cats, I cannot guarantee that this is the most idiomatic solution. Probably there is something Coyoneda-esque already in the library.
EDIT: There is Coyoneda in the cats library, but it requires a natural transformation F ~> G to a functor G. Unfortunately, we don't have a Functor for Dataset (that was the problem in the first place). What my implementation above does is: instead of a Functor[G], it requires a single morphism of the (non-existent) natural transformation at a fixed X (this is what the Encoder[X] is).
Related
Continuing What is "prolog style" in Scala?
I want to combine logical inference and procedural code, in Scala-3. Something like this:
// This is a mix of Prolog and Scala, and is not a real code.
// The idea is not only to find out that the goal is reachable,
// but to use the found solution
print_file(X:Filename) :- read(X,Representation), print(Representation).
read(X:Filename, CollectionOfLines[X]) :- { read_lines(X) }.
read(X:Filename, String[X]) :- { slurp_file(X) }.
print(X:String) :- { print(X) }.
print(X:CollectionOfLines) :- { X.foreach(println)}.
given Filename("foo.txt")
val howto = summon[print_file]
howto()
I expect such kind of program to print the specified file. But so far I do not know how to specify the procedural part, in Scala.
(This post contains code that is supposed to demonstrate some properties of the type system; it has no direct practical applications, please don't use it for anything; "It can be done" does not imply "you should do it")
In your question, it's not entirely clear what the formulas such as "CollectionOfLines[X]" and "String[X]" are supposed to mean. I took the liberty to warp it into something implementable:
/**
* Claims that an `X` can be printed.
*/
trait Print[X]:
def apply(x: X): Unit
/**
* Claims that an instance of type `X` can
* be read from a file with a statically
* known `Name`.
*/
trait Read[Name <: String & Singleton, X]:
def apply(): X
/**
* Claims that an instance of type `Repr` can
* be read from a statically known file with a given `Name`,
* and then printed in `Repr`-specific way.
*/
trait PrintFile[Name, Repr]:
def apply(): Unit
given splitLines: Conversion[String, List[String]] with
def apply(s: String) = s.split("\n").toList
given printFile[Name <: String & Singleton, Repr]
(using n: ValueOf[Name], rd: Read[Name, Repr], prnt: Print[Repr])
: PrintFile[Name, Repr] with
def apply(): Unit =
val content = rd()
prnt(content)
given readThenConvert[Name <: String & Singleton, A, B]
(using name: ValueOf[Name], readA: Read[Name, A], conv: Conversion[A, B])
: Read[Name, B] with
def apply() = conv(readA())
inline given slurp[Name <: String & Singleton]
(using n: ValueOf[Name])
: Read[Name, String] with
def apply() = io.Source.fromFile(n.value).getLines.mkString("\n")
given printString: Print[String] with
def apply(s: String) = println(s)
given printList[X](using printOne: Print[X]): Print[List[X]] with
def apply(x: List[X]) = x.zipWithIndex.foreach((line, idx) => {
print(s"${"%3d".format(idx)}| ")
printOne(line)
})
#main def printItself(): Unit =
println("Print as monolithic string")
summon[PrintFile["example.scala", String]]()
println("=" * 80)
println("Print as separate lines")
summon[PrintFile["example.scala", List[String]]]()
When saved as example.scala, it will print its own code twice, once as one long multiline-string, and once as a list of numbered lines.
As already mentioned elsewhere, this particular use case seems highly atypical, and the code looks quite unidiomatic.
You should try to reserve this mechanism for making true and precise statements about types and type constructors, not for enforcing an order between a bunch of imperative statements.
In this example, instead of carefully making universally true statements, we're making a bunch of half-baked not well thought-out statements, giving them semi-random names, and then trying to abuse the nominal type system and to coerce the reality to the artificial constraints that we have imposed by naming things this or that. This is usually a sign of a bad design: everything feels loose and kind-of "flabby". The apply(): Unit in particular is clearly a red flag: there is not much that can be said about Unit that could also be encoded as types, so instead of relying on the type system, one has to revert to "stringly-typed" naming-discipline, and then hope that one has interpreted the names correctly.
We are using Spark 2.x with Scala for a system that has 13 different ETL operations. 7 of them are relatively simple and each driven by a single domain class, and differ primarily by this class and some nuances in how the load is handled.
A simplified version of the load class is as follows, for the purposes of this example say that there are 7 pizza toppings being loaded, here's Pepperoni:
object LoadPepperoni {
def apply(inputFile: Dataset[Row],
historicalData: Dataset[Pepperoni],
mergeFun: (Pepperoni, PepperoniRaw) => Pepperoni): Dataset[Pepperoni] = {
val sparkSession = SparkSession.builder().getOrCreate()
import sparkSession.implicits._
val rawData: Dataset[PepperoniRaw] = inputFile.rdd.map{ case row : Row =>
PepperoniRaw(
weight = row.getAs[String]("weight"),
cost = row.getAs[String]("cost")
)
}.toDS()
val validatedData: Dataset[PepperoniRaw] = ??? // validate the data
val dedupedRawData: Dataset[PepperoniRaw] = ??? // deduplicate the data
val dedupedData: Dataset[Pepperoni] = dedupedRawData.rdd.map{ case datum : PepperoniRaw =>
Pepperoni( value = ???, key1 = ???, key2 = ??? )
}.toDS()
val joinedData = dedupedData.joinWith(historicalData,
historicalData.col("key1") === dedupedData.col("key1") &&
historicalData.col("key2") === dedupedData.col("key2"),
"right_outer"
)
joinedData.map { case (hist, delta) =>
if( /* some condition */) {
hist.copy(value = /* some transformation */)
}
}.flatMap(list => list).toDS()
}
}
In other words the class performs a series of operations on the data, the operations are mostly the same and always in the same order, but can vary slightly per topping, as would the mapping from "raw" to "domain" and the merge function.
To do this for 7 toppings (i.e. Mushroom, Cheese, etc), I would rather not simply copy/paste the class and change all of the names, because the structure and logic is common to all loads. Instead I'd rather define a generic "Load" class with generic types, like this:
object Load {
def apply[R,D](inputFile: Dataset[Row],
historicalData: Dataset[D],
mergeFun: (D, R) => D): Dataset[D] = {
val sparkSession = SparkSession.builder().getOrCreate()
import sparkSession.implicits._
val rawData: Dataset[R] = inputFile.rdd.map{ case row : Row =>
...
And for each class-specific operation such as mapping from "raw" to "domain", or merging, have a trait or abstract class that implements the specifics. This would be a typical dependency injection / polymorphism pattern.
But I'm running into a few problems. As of Spark 2.x, encoders are only provided for native types and case classes, and there is no way to generically identify a class as a case class. So the inferred toDS() and other implicit functionality is not available when using generic types.
Also as mentioned in this related question of mine, the case class copy method is not available when using generics either.
I have looked into other design patterns common with Scala and Haskell such as type classes or ad-hoc polymorphism, but the obstacle is the Spark Dataset basically only working on case classes, which can't be abstractly defined.
It seems that this would be a common problem in Spark systems but I'm unable to find a solution. Any help appreciated.
The implicit conversion that enables .toDS is:
implicit def rddToDatasetHolder[T](rdd: RDD[T])(implicit arg0: Encoder[T]): DatasetHolder[T]
(from https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.sql.SQLImplicits)
You are exactly correct in that there's no implicit value in scope for Encoder[T] now that you've made your apply method generic, so this conversion can't happen. But you can simply accept one as an implicit parameter!
object Load {
def apply[R,D](inputFile: Dataset[Row],
historicalData: Dataset[D],
mergeFun: (D, R) => D)(implicit enc: Encoder[D]): Dataset[D] = {
...
Then at the time you call the load, with a specific type, it should be able to find an Encoder for that type. Note that you will have to import sparkSession.implicits._ in the calling context as well.
Edit: a similar approach would be to enable the implicit newProductEncoder[T <: Product](implicit arg0: scala.reflect.api.JavaUniverse.TypeTag[T]): Encoder[T] to work by bounding your type (apply[R, D <: Product]) and accepting an implicit JavaUniverse.TypeTag[D] as a parameter.
Issue
First approach
If would like to have
trait Distance extends ((SpacePoint, SpacePoint) => Double)
object EuclideanDistance extends Distance {
override def apply(sp1: SpacePoint, sp2: SpacePoint): Double = ???
}
trait Kernel extends (((Distance)(SpacePoint, SpacePoint)) => Double)
object GaussianKernel extends Kernel {
override def apply(distance: Distance)(sp1: SpacePoint, sp2: SpacePoint): Double = ???
}
However the apply of object GaussianKernel extends Kernel is not an excepted override to the apply of trait Kernel.
Second approach - EDIT: turns out this works afterall...
Alternatively I could write
trait Kernel extends ((Distance) => ( (SpacePoint, SpacePoint) => Double))
object GaussianKernel extends Kernel {
override def apply(distance: Distance): (SpacePoint, SpacePoint) => Double =
(sp1: SpacePoint, sp2: SpacePoint) =>
math.exp(-math.pow(distance(sp1, sp2), 2) / (2))
}
but am not sure this is currying...
EDIT: Turns out that I can use this second approach in a currying fashion. I think it is exactly what the typical currying is, only without the syntactic sugar.
Explanation of the idea
The idea is this: For my algorithm I need a Kernel. This kernel calculates a metric for two vectors in space - here SpacePoints. For that the Kernel requires a way to calculate the distance between the two SpacePoints. Both distance and kernel should be exchangeable (open-closed principle), thus I declare them as traits (in Java I had them declared as interfaces). Here I use the Euclidean Distance (not shown) and the Gaussian Kernel. Why the currying? Later when using those things, the distance is going to be more or less the same for all measurements, while the SpacePoints will change all the time. Again, trying to stay true to the open-closed principle. Thus, in a first step I would like the GaussianKernel to be pre-configured (if you will) with a distance and return a Function that can be feed later in the program with the SpacePoints (I am sure the code is wrong, just to give you an idea what I am aiming at):
val myFirstKernel = GaussianKernel(EuclideanDistance)
val mySecondKernel = GaussianKernel(FancyDistance)
val myThirdKernel = EpanechnikovKernel(EuclideanDistance)
// ... lots lof code ...
val firstOtherClass = new OtherClass(myFirstKernel)
val secondOtherClass = new OtherClass(mySecondKernel)
val thirdOtherClass = new OtherClass(myThirdKernel)
// ... meanwhile in "OtherClass" ...
class OtherClass(kernel: Kernel) {
val thisSpacePoint = ??? // ... fancy stuff going on ...
val thisSpacePoint = ??? // ... fancy stuff going on ...
val calculatedKernel = kernel(thisSpacePoint, thatSpacePoint)
}
Questions
How do I build my trait?
Since distance can be different for different GaussianKernels - should GaussianKernel be a class instead of an object?
Should I partially apply GaussianKernel instead of currying?
Is my approach bad and GaussianKernel should be a class that stores the distance in a field?
I would just use functions. All this extra stuff is just complexity and making things traits doesn't seem to add anything.
def euclideanDistance(p1: SpacePoint1, p1: SpacePoint1): Double = ???
class MyClass(kernel: (SpacePoint, SpacePoint) => Double) { ??? }
val myClass = new MyClass(euclideanDistance)
So just pass the kernel as a function that will computer your distance given two points.
I'm on my phone, so can't fully check, but this will give you an idea.
This will allow you to partially apply the functions if you have the need. Imagine you have a base calculate method...
def calc(settings: Settings)(p1: SpacePoint1, p1: SpacePoint1): Double = ???
val standardCalc = calc(defaultSettings)
val customCalc = calc(customSettings)
I would start with modeling everything as functions first, then roll up commonality into traits only if needed.
Answers
1. How do I build my trait?
The second approach is the way to go. You just can't use the syntactic sugar of currying as usual, but this is the same as currying:
GaussianKernel(ContinuousEuclideanDistance)(2, sp1, sp2)
GaussianKernel(ContinuousManhattanDistance)(2, sp1, sp2)
val eKern = GaussianKernel(ContinuousEuclideanDistance)
eKern(2, sp1, sp2)
eKern(2, sp1, sp3)
val mKern = GaussianKernel(ContinuousManhattanDistance)
mKern(2, sp1, sp2)
mKern(2, sp1, sp3)
Why the first approach does not work
Because currying is only possible for methods (duh...). The issue starts with the notion that a Function is very much like a method, only that the actual method is the apply method, which is invoked by calling the Function's "constructor".
First of all: If an object has an apply method, it already has this ability - no need to extend a Function. Extending a Function only forces the object to have an apply method. When I say "object" here I mean both, a singleton Scala object (with the identifier object) and a instantiated class. If the object is a instantiated class MyClass, then the call MyClass(...) refers to the constructor (thus a new before that is required) and the apply is masked. However, after the instantiation, I can use the resulting object in the way mentioned: val myClass = new MyClass(...), where myClass is an object (a class instance). Now I can write myClass(...), calling the apply method. If the object is a singleton object, then I already have an object and can directly write MyObject(...) to call the apply method. Of course an object (in both senses) does not have a constructor and thus the apply is not masked and can be used. When this is done, it just looks the same way as a constructor, but it isn't (that's Scala syntax for you - just because it looks similar, doesn't mean it's the same thing).
Second of all: Currying is syntactic sugar:
def mymethod(a: Int)(b: Double): String = ???
is syntactic sugar for
def mymethod(a: Int): ((Double) => String) = ???
which is syntactic sugar for
def mymethod(a: Int): Function1[Double, String] = ???
thus
def mymethod(a: Int): Function1[Double, String] = {
new Function1[Double, String] {
def apply(Double): String = ???
}
}
(If we extend a FunctionN[T1, T2, ..., Tn+1] it works like this: The last type Tn+1 is the output type of the apply method, the first N types are the input types.)
Now, we want the apply method here is supposed to be currying:
object GaussianKernel extends Kernel {
override def apply(distance: Distance)(sp1: SpacePoint, sp2: SpacePoint): Double = ???
}
which translates to
object GaussianKernel extends Kernel {
def apply(distance: Distance): Function2[SpacePoint, SpacePoint, Double] = {
new Function2[SpacePoint, SpacePoint, Double] {
def apply(SpacePoint, SpacePoint): Double
}
}
}
Now, so what should GaussianKernel extend (or what is GaussianKernel)? It should extend
Function1[Distance, Function2[SpacePoint, SpacePoint, Double]]
(which is the same as Distance => ((SpacePoint, SpacePoint) => Double)), the second approach).
Now the issue here is, that this cannot be written as currying, because it is a type description and not a method's signature. After discussing all this, this seems obvious, but before discussion all this, it might not have. The thing is, that the type description seemed to have a direct translation into the apply method's (the first, or only one, depending on how one takes the syntactic sugar apart) signature, but it doesn't. To be fair though, it is something that could have been implemented in the compiler: That the type description and the apply method's signature are recognized to be equal.
2. Since distance can be different for different GaussianKernels - should GaussianKernel be a class instead of an object?
Both are valid implementation. Using those later only differenciates only in the presence or absence of new.
If one does not like the new one can consider a companion object as a Factory pattern.
3. Should I partially apply GaussianKernel instead of currying?
In general this is preferred according to http://www.vasinov.com/blog/on-currying-and-partial-function-application/#toc-use-cases
An advantage of currying would be the nicer code without _: ??? for the missing parameters.
4. Is my approach bad and GaussianKernel should be a class that stores the distance in a field?
see 2.
tl;dr: How do I do something like the made up code below:
def notFunctor[M[_] : Not[Functor]](m: M[_]) = s"$m is not a functor"
The 'Not[Functor]', being the made up part here.
I want it to succeed when the 'm' provided is not a Functor, and fail the compiler otherwise.
Solved: skip the rest of the question and go right ahead to the answer below.
What I'm trying to accomplish is, roughly speaking, "negative evidence".
Pseudo code would look something like so:
// type class for obtaining serialization size in bytes.
trait SizeOf[A] { def sizeOf(a: A): Long }
// type class specialized for types whose size may vary between instances
trait VarSizeOf[A] extends SizeOf[A]
// type class specialized for types whose elements share the same size (e.g. Int)
trait FixedSizeOf[A] extends SizeOf[A] {
def fixedSize: Long
def sizeOf(a: A) = fixedSize
}
// SizeOf for container with fixed-sized elements and Length (using scalaz.Length)
implicit def fixedSizeOf[T[_] : Length, A : FixedSizeOf] = new VarSizeOf[T[A]] {
def sizeOf(as: T[A]) = ... // length(as) * sizeOf[A]
}
// SizeOf for container with scalaz.Foldable, and elements with VarSizeOf
implicit def foldSizeOf[T[_] : Foldable, A : SizeOf] = new VarSizeOf[T[A]] {
def sizeOf(as: T[A]) = ... // foldMap(a => sizeOf(a))
}
Keep in mind that fixedSizeOf() is preferable where relevant, since it saves us the traversal over the collection.
This way, for container types where only Length is defined (but not Foldable), and for elements where a FixedSizeOf is defined, we get improved performance.
For the rest of the cases, we go over the collection and sum individual sizes.
My problem is in the cases where both Length and Foldable are defined for the container, and FixedSizeOf is defined for the elements. This is a very common case here (e.g.,: List[Int] has both defined).
Example:
scala> implicitly[SizeOf[List[Int]]].sizeOf(List(1,2,3))
<console>:24: error: ambiguous implicit values:
both method foldSizeOf of type [T[_], A](implicit evidence$1: scalaz.Foldable[T], implicit evidence$2: SizeOf[A])VarSizeOf[T[A]]
and method fixedSizeOf of type [T[_], A](implicit evidence$1: scalaz.Length[T], implicit evidence$2: FixedSizeOf[A])VarSizeOf[T[A]]
match expected type SizeOf[List[Int]]
implicitly[SizeOf[List[Int]]].sizeOf(List(1,2,3))
What I would like is to be able to rely on the Foldable type class only when the Length+FixedSizeOf combination does not apply.
For that purpose, I can change the definition of foldSizeOf() to accept VarSizeOf elements:
implicit def foldSizeOfVar[T[_] : Foldable, A : VarSizeOf] = // ...
And now we have to fill in the problematic part that covers Foldable containers with FixedSizeOf elements and no Length defined. I'm not sure how to approach this, but pseudo-code would look something like:
implicit def foldSizeOfFixed[T[_] : Foldable : Not[Length], A : FixedSizeOf] = // ...
The 'Not[Length]', obviously, being the made up part here.
Partial solutions I am aware of
1) Define a class for low priority implicits and extend it, as seen in 'object Predef extends LowPriorityImplicits'.
The last implicit (foldSizeOfFixed()) can be defined in the parent class, and will be overridden by alternative from the descendant class.
I am not interested in this option because I'd like to eventually be able to support recursive usage of SizeOf, and this will prevent the implicit in the low priority base class from relying on those in the sub class (is my understanding here correct? EDIT: wrong! implicit lookup works from the context of the sub class, this is a viable solution!)
2) A rougher approach is relying on Option[TypeClass] (e.g.,: Option[Length[List]]. A few of those and I can just write one big ol' implicit that picks Foldable and SizeOf as mandatory and Length and FixedSizeOf as optional, and relies on the latter if they are available. (source: here)
The two problems here are lack of modularity and falling back to runtime exceptions when no relevant type class instances can be located (this example can probably be made to work with this solution, but that's not always possible)
EDIT: This is the best I was able to get with optional implicits. It's not there yet:
implicit def optionalTypeClass[TC](implicit tc: TC = null) = Option(tc)
type OptionalLength[T[_]] = Option[Length[T]]
type OptionalFixedSizeOf[T[_]] = Option[FixedSizeOf[T]]
implicit def sizeOfContainer[
T[_] : Foldable : OptionalLength,
A : SizeOf : OptionalFixedSizeOf]: SizeOf[T[A]] = new SizeOf[T[A]] {
def sizeOf(as: T[A]) = {
// optionally calculate using Length + FixedSizeOf is possible
val fixedLength = for {
lengthOf <- implicitly[OptionalLength[T]]
sizeOf <- implicitly[OptionalFixedSizeOf[A]]
} yield lengthOf.length(as) * sizeOf.fixedSize
// otherwise fall back to Foldable
fixedLength.getOrElse {
val foldable = implicitly[Foldable[T]]
val sizeOf = implicitly[SizeOf[A]]
foldable.foldMap(as)(a => sizeOf.sizeOf(a))
}
}
}
Except this collides with fixedSizeOf() from earlier, which is still necessary.
Thanks for any help or perspective :-)
I eventually solved this using an ambiguity-based solution that doesn't require prioritizing using inheritance.
Here is my attempt at generalizing this.
We use the type Not[A] to construct negative type classes:
import scala.language.higherKinds
trait Not[A]
trait Monoid[_] // or import scalaz._, Scalaz._
type NotMonoid[A] = Not[Monoid[A]]
trait Functor[_[_]] // or import scalaz._, Scalaz._
type NotFunctor[M[_]] = Not[Functor[M]]
...which can then be used as context bounds:
def foo[T: NotMonoid] = ...
We proceed by ensuring that every valid expression of Not[A] will gain at least one implicit instance.
implicit def notA[A, TC[_]] = new Not[TC[A]] {}
The instance is called 'notA' -- 'not' because if it is the only instance found for 'Not[TC[A]]' then the negative type class is found to apply; the 'A' is commonly appended for methods that deal with flat-shaped types (e.g. Int).
We now introduce an ambiguity to turn away cases where the undesired type class is applied:
implicit def notNotA[A : TC, TC[_]] = new Not[TC[A]] {}
This is almost exactly the same as 'NotA', except here we are only interested in types for which an instance of the type class specified by 'TC' exists in implicit scope. The instance is named 'notNotA', since by merely matching the implicit being looked up, it will create an ambiguity with 'notA', failing the implicit search (which is our goal).
Let's go over a usage example. We'll use the 'NotMonoid' negative type class from above:
implicitly[NotMonoid[java.io.File]] // succeeds
implicitly[NotMonoid[Int]] // fails
def showIfNotMonoid[A: NotMonoid](a: A) = a.toString
showIfNotMonoid(3) // fails, good!
showIfNotMonoid(scala.Console) // succeeds for anything that isn't a Monoid
So far so good! However, types shaped M[_] and type classes shaped TC[_[_]] aren't supported yet by the scheme above. Let's add implicits for them as well:
implicit def notM[M[_], TC[_[_]]] = new Not[TC[M]] {}
implicit def notNotM[M[_] : TC, TC[_[_]]] = new Not[TC[M]] {}
implicitly[NotFunctor[List]] // fails
implicitly[NotFunctor[Class]] // succeeds
Simple enough. Note that Scalaz has a workaround for the boilerplate resulting from dealing with several type shapes -- look for 'Unapply'. I haven't been able to make use of it for the basic case (type class of shape TC[_], such as Monoid), even though it worked on TC[_[_]] (e.g. Functor) like a charm, so this answer doesn't cover that.
If anybody's interested, here's everything needed in a single snippet:
import scala.language.higherKinds
trait Not[A]
object Not {
implicit def notA[A, TC[_]] = new Not[TC[A]] {}
implicit def notNotA[A : TC, TC[_]] = new Not[TC[A]] {}
implicit def notM[M[_], TC[_[_]]] = new Not[TC[M]] {}
implicit def notNotM[M[_] : TC, TC[_[_]]] = new Not[TC[M]] {}
}
import Not._
type NotNumeric[A] = Not[Numeric[A]]
implicitly[NotNumeric[String]] // succeeds
implicitly[NotNumeric[Int]] // fails
and the pseudo code I asked for in the question would look like so (actual code):
// NotFunctor[M[_]] declared above
def notFunctor[M[_] : NotFunctor](m: M[_]) = s"$m is not a functor"
Update: Similar technique applied to implicit conversions:
import scala.language.higherKinds
trait Not[A]
object Not {
implicit def not[V[_], A](a: A) = new Not[V[A]] {}
implicit def notNot[V[_], A <% V[A]](a: A) = new Not[V[A]] {}
}
We can now (e.g.) define a function that will only admit values if their types aren't viewable as Ordered:
def unordered[A <% Not[Ordered[A]]](a: A) = a
In Scala 3 (aka Dotty), the aforementioned tricks no longer work.
The negation of givens is built-in with NotGiven:
def f[T](value: T)(using ev: NotGiven[MyTypeclass[T]])
Examples:
f("ok") // no given instance of MyTypeclass[T] in scope
given MyTypeclass[String] = ... // provide the typeclass
f("bad") // compile error
I've tried this line of code
def **[A <% Numeric[A]](l:List[A],m:List[A])=l.zip(m).map({t=>t._1*t._2})
However on compilation, I get this error
error: value * is not a member of type parameter A
def **[A <% Numeric[A]](l:List[A],m:List[A])=l.zip(m).map({t=>t._1*t._2})
When I look at the source for the Numeric trait, I see a * op defined.
What am I doing wrong?
The instance of Numeric is not a number itself, but it is an object that offers operations to do the arithmetic. For example, an object num of type Numeric[Int] can add two integers like this: num.plus(3, 5) The result of this operation is the integer 7.
For integers, this is very trivial. However, for all basic numerical types, there is one implicit instance of Numeric available. And if you define your own numeric types, you can provide one.
Therefore, you should leave the bounds for A open and add an implicit parameter of type Numeric[A], with which you do the calculations. Like this:
def **[A](l:List[A],m:List[A])(implicit num:Numeric[A])=l.zip(m).map({t=>num.times(t._1, t._2)})
Of course, num.times(a,b) looks less elegant than a*b. In most of the cases, one can live with that. However, you can wrap the value a in an object of type Ops that supports operators, like this:
// given are: num:Numeric[A], a:A and b:A
val a_ops = num.mkNumericOps(a)
val product = a_ops * b
Since the method mkNumericOps is declared implicit, you can also import it and use it implicitly:
// given are: num:Numeric[A], a:A and b:A
import num._
val product = a * b
You can also solve this with a context bound. Using the context method from this answer, you can write:
def **[A : Numeric](l:List[A],m:List[A]) =
l zip m map { t => context[A]().times(t._1, t._2) }
or
def **[A : Numeric](l:List[A],m:List[A]) = {
val num = context[A]()
import num._
l zip m map { t => t._1 * t._2 }
}