I'm wondering if it is possible to mixin a Scala trait with an instance to make an anonymous instance.
basically I would to do something like that
trait Duck {
def walk : Unit
}
def learnToDuckWalk[A](a : A) : A with Duck = a with Duck {
def walk = print("flic flak floc")
}
The idea is to make a new type without having to define a all new class that extends 2 types.
Because define a new class for each type could lead to exponential number of class, growing each time we add a new Trait to mixin.
I saw few things that look like this in ZIO.Has but I'm wondering if it is doable with pure Scala 2 or even with Scala 3.
Do you really need a generic parameter A, or was that just for example sake? If you had a concrete type instead of A, then you could just create an instance that mixes in both traits:
trait Duck {
def walk: Unit
}
trait Goose {
def run: Unit
}
def learnToDuckWalk: Goose with Duck = new Goose with Duck {
def run = println("tip tap top")
def walk = println("flic flak floc")
}
learnToDuckWalk.walk
learnToDuckWalk.run
However, having a generic A and "bolting-on" some extra traits is not really a good design, even if you managed to implement it (e.g. using reflection).
A better approach would be, instead of saying "I have an A that is mixed in with Duck", to say "I have an A that has a Duck type class instance".
trait Duck [A]{
def walk : Unit
}
object Duck {
implicit val duckString = new Duck[String] {
def walk = print("Stringy flic flak floc")
}
implicit val duckInt = new Duck[Int] {
def walk = print("Inty flic flak floc")
}
...
implicit def duckA[A] = new Duck[A] {
def walk = print("Generic flic flak floc")
}
}
This way you can provide type class instances for any type you want, and you can have them behave differently depending on the actual type (see how walk prints a different message fo each type).
Then your use-site can look like this:
import Duck._
def learnToDuckWalk[A : Duck](a : A) = {
val aDuck = implicitly[Duck[A]]
aDuck.walk // prints Stringy flic flak floc
}
learnToDuckWalk("Some string")
Important part here is the [A : Duck] type, which means "any A for which a Duck type class instance exists".
Related
I am tinkling with Scala and would like to produce some generic code. I would like to have two classes, one "outer" class and one "inner" class. The outer class should be generic and accept any kind of inner class which follow a few constraints. Here is the kind of architecture I would want to have, in uncompilable code. Outer is a generic type, and Inner is an example of type that could be used in Outer, among others.
class Outer[InType](val in: InType) {
def update: Outer[InType] = new Outer[InType](in.update)
def export: String = in.export
}
object Outer {
def init[InType]: Outer[InType] = new Outer[InType](InType.empty)
}
class Inner(val n: Int) {
def update: Inner = new Inner(n + 1)
def export: String = n.toString
}
object Inner {
def empty: Inner = new Inner(0)
}
object Main {
def main(args: Array[String]): Unit = {
val outerIn: Outer[Inner] = Outer.empty[Inner]
println(outerIn.update.export) // expected to print 1
}
}
The important point is that, whatever InType is, in.update must return an "updated" InType object. I would also like the companion methods to be callable, like InType.empty. This way both Outer[InType] and InType are immutable types, and methods defined in companion objects are callable.
The previous code does not compile, as it is written like a C++ generic type (my background). What is the simplest way to correct this code according to the constraints I mentionned ? Am I completely wrong and should I use another approach ?
One approach I could think of would require us to use F-Bounded Polymorphism along with Type Classes.
First, we'd create a trait which requires an update method to be available:
trait AbstractInner[T <: AbstractInner[T]] {
def update: T
def export: String
}
Create a concrete implementation for Inner:
class Inner(val n: Int) extends AbstractInner[Inner] {
def update: Inner = new Inner(n + 1)
def export: String = n.toString
}
Require that Outer only take input types that extend AbstractInner[InType]:
class Outer[InType <: AbstractInner[InType]](val in: InType) {
def update: Outer[InType] = new Outer[InType](in.update)
}
We got the types working for creating an updated version of in and we need somehow to create a new instance with empty. The Typeclass Pattern is classic for that. We create a trait which builds an Inner type:
trait InnerBuilder[T <: AbstractInner[T]] {
def empty: T
}
We require Outer.empty to only take types which extend AbstractInner[InType] and have an implicit InnerBuilder[InType] in scope:
object Outer {
def empty[InType <: AbstractInner[InType] : InnerBuilder] =
new Outer(implicitly[InnerBuilder[InType]].empty)
}
And provide a concrete implementation for Inner:
object AbstractInnerImplicits {
implicit def innerBuilder: InnerBuilder[Inner] = new InnerBuilder[Inner] {
override def empty = new Inner(0)
}
}
Invoking inside main:
object Experiment {
import AbstractInnerImplicits._
def main(args: Array[String]): Unit = {
val outerIn: Outer[Inner] = Outer.empty[Inner]
println(outerIn.update.in.export)
}
}
Yields:
1
And there we have it. I know this may be a little overwhelming to grasp at first. Feel free to ask more questions as you read this.
I can think of 2 ways of doing it without referring to black magic:
with trait:
trait Updatable[T] { self: T =>
def update: T
}
class Outer[InType <: Updatable[InType]](val in: InType) {
def update = new Outer[InType](in.update)
}
class Inner(val n: Int) extends Updatable[Inner] {
def update = new Inner(n + 1)
}
first we use trait, to tell type system that update method is available, then we put restrains on the type to make sure that Updatable is used correctly (self: T => will make sure it is used as T extends Updatable[T] - as F-bounded type), then we also make sure that InType will implement it (InType <: Updatable[InType]).
with type class:
trait Updatable[F] {
def update(value: F): F
}
class Outer[InType](val in: InType)(implicit updatable: Updatable[InType]) {
def update: Outer[InType] = new Outer[InType](updatable.update(in))
}
class Inner(val n: Int) {
def update: Inner = new Inner(n + 1)
}
implicit val updatableInner = new Updatable[Inner] {
def update(value: Inner): Inner = value.update
}
First we define type class, then we are implicitly requiring its implementation for our type, and finally we are providing and using it. Putting whole theoretical stuff aside, the practical difference is that this interface is that you are not forcing InType to extend some Updatable[InType], but instead require presence of some Updatable[InType] implementation to be available in your scope - so you can provide the functionality not by modifying InType, but by providing some additional class which would fulfill your constrains or InType.
As such type classes are much more extensible, you just need to provide implicit for each supported type.
Among other methods available to you are e.g. reflection (however that might kind of break type safety and your abilities to refactor).
I am using a library which has a class that has a generic type that can be quite complicated. I need to write a method that takes a parameter with the generic type that a val of the library class has, and I would like to avoid having to write out the type in the method signature. I thought I might be able to create an implicit class which adds a type to the val that I could use in the method signature, kind of like:
// This comes from a library and can't be changed
case class LibraryClass[A](a: A)
//----------------------------------
object MyCode {
val thing = LibraryClass(3)
implicit class LibraryClassWithType[A](lc: LibraryClass[A]) {
type TheType = A
}
def doStuff(something: thing.TheType): Unit = {
println(something)
}
}
This does not compile (TheType is not a member of LibraryClass). But if I wrap it in the class myself, it works
val thingWithType = LibraryClassWithType(thing)
def doStuff(something: thingWithType.TheType): Unit = {
println(something)
}
Is there something I am missing that will make this work, or is this kind of implicit conversion not valid Scala?
I haven't been able to do this sort of thing with implicits, but I have had to do something similar where I just instantiated these sorts of type holders:
case class LibraryClass[A](a: A)
object MyCode {
val thing = LibraryClass(3)
class HigherTypeHolder[A,F[A]](a: F[A]) {
type AT = A
}
val th = new HigherTypeHolder(thing)
def doStuff(something: th.AT): Unit = {
println(something)
}
}
You can do what (I think) you want like this:
implicit val thing = LibraryClass(3)
def doStuff[A](something: A)(implicit lc: LibraryClass[A])
What I don't understand is why this needs to be so complicated. Why not for example stick with your second approach, without implicits, that works, or why not just do
def doStuff[A](something: A) to begin with?
I recently saw the talks Dead-Simple Dependency Injection and Dependency Injection Without the Gymnastics about DI with Monads and was impressed. I tried to apply it on a simple problem, but failed as soon as it got non-trivial. I really would like to see a running version of dependency injection where
a class that depends on more than one value that has to be injected
a class that depends on a class that depends on something to be injected
as in the following example
trait FlyBehaviour { def fly() }
trait QuackBehaviour { def quack() }
trait Animal { def makeSound() }
// needs two behaviours injected
class Duck(val flyBehaviour: FlyBehaviour, val quackBehaviour: QuackBehaviour) extends Animal
{
def quack() = quackBehaviour.quack()
def fly() = flyBehaviour.fly()
def makeSound() = quack()
}
// needs an Animal injected (e.g. a Duck)
class Zoo(val animal: Animal)
// Spring for example would be able to provide a Zoo instance
// assuming a Zoo in configured to get a Duck injected and
// a Duck is configured to get impl. of FlyBehaviour and QuackBehaviour injected
val zoo: Zoo = InjectionFramework.get("Zoo")
zoo.animal.makeSound()
It would be really helpful to see a sample implementation using the reader Monad since I just feel that I am missing a push in the right direction.
Thanks!
The "reader monad" is just Function1, so all you need to do is accept an argument containing all the things you need. For example:
trait Config {
def fly: FlyBehaviour
def quack: QuackBehaviour
}
type Env[A] = Config => A
Now if you want to construct a Duck based on this environment:
val a: Env[Animal] = c => new Duck(c.fly, c.quack)
And then constructing a Zoo based on that is easy:
val z: Env[Zoo] = a andThen (new Zoo(_))
Using Scalaz (or with a bit of work on your own) you can make use of some syntax niceties to "ask" for the config c:
val z: Env[Zoo] = for {
c <- ask
} yield new Zoo(Duck(c.fly, c.quack))
I think it would be easier to describe a problem with concrete example. Suppose I have have Fruit class hierarchy and Show type class:
trait Fruit
case class Apple extends Fruit
case class Orange extends Fruit
trait Show[T] {
def show(target: T): String
}
object Show {
implicit object AppleShow extends Show[Apple] {
def show(apple: Apple) = "Standard apple"
}
implicit object OrangeShow extends Show[Orange] {
def show(orange: Orange) = "Standard orange"
}
}
def getAsString[T](target: T)(implicit s: Show[T]) = s show target
I also have list of fruits that I would like to show to the user using Show (this is my main goal in this question):
val basket = List[Fruit](Apple(), Orange())
def printList[T](list: List[T])(implicit s: Show[T]) =
list foreach (f => println(s show f))
printList(basket)
This will not compile because List is parametrized with Fruit and I have not defined any Show[Fruit]. What is the best way to achieve my goal using type classes?
I tried to find solution for this problem, but unfortunately have not found any nice one yet. It's not enough to know s in printList function - somehow it needs to know Show[T] for each element of the list. This means, that in order to be able to make this, we need some run-time mechanism in addition to the compile-time one. This gave me an idea of some kind of run-time dictionary, that knows, how to find correspondent Show[T] at run-time.
Implementation of implicit Show[Fruit]can serve as such dictionary:
implicit object FruitShow extends Show[Fruit] {
def show(f: Fruit) = f match {
case a: Apple => getAsString(a)
case o: Orange => getAsString(o)
}
}
And actually very similar approach can be found in haskell. As an example, we can look at Eq implementation for Maybe:
instance (Eq m) => Eq (Maybe m) where
Just x == Just y = x == y
Nothing == Nothing = True
_ == _ = False
The big problem with this solution, is that if I will add new subclass of Fruit like this:
case class Banana extends Fruit
object Banana {
implicit object BananaShow extends Show[Banana] {
def show(banana: Banana) = "New banana"
}
}
and will try to print my basket:
val basket = List[Fruit](Apple(), Orange(), Banana())
printList(basket)
then scala.MatchError would be thrown because my dictionary does not know anything about bananas yet. Of course, I can provide updated dictionary in some context that knows about bananas:
implicit object NewFruitShow extends Show[Fruit] {
def show(f: Fruit) = f match {
case b: Banana => getAsString(b)
case otherFruit => Show.FruitShow.show(otherFruit)
}
}
But this solution is far from perfect. Just imagine that some other library provides another fruit with it's own version of dictionary. It will just conflict with NewFruitShow if I try to use them together.
Maybe I'm missing something obvious?
Update
As #Eric noticed, there is one more solution described here: forall in Scala . It's really looks very interesting. But I see one problem with this solution.
If I use ShowBox, then it will remember concrete type class during it's creation time. So I generally building list with objects and correspondent type classes (so dictionary in present in the list). From the other hand, scala has very nice feature: I can drop new implicits in the current scope and they will override defaults. So I can define alternative string representation for the classes like:
object CompactShow {
implicit object AppleCompactShow extends Show[Apple] {
def show(apple: Apple) = "SA"
}
implicit object OrangeCompactShow extends Show[Orange] {
def show(orange: Orange) = "SO"
}
}
and then just import it in current scope with import CompactShow._. In this case AppleCompactShow and OrangeCompactShow object would be implicitly used instead of defaults defined in the companion object of Show. And as you can guess, list creation and printing happens in different places. If I will use ShowBox, than most probably I will capture default instances of type class. I would like to capture them at the last possible moment - the moment when I call printList, because I even don't know, whether my List[Fruit] will ever be shown or how it would be shown, in the code that creates it.
The most obvious answer is to use a sealed trait Fruit and a Show[Fruit]. That way your pattern matches will complain at compile time when the match is not exhaustive. Of course, adding a new kind of Fruit in an external library will not be possible, but this is inherent in the nature of things. This is the "expression problem".
You could also stick the Show instance on the Fruit trait:
trait Fruit { self =>
def show: Show[self.type]
}
case class Apple() extends Fruit { self =>
def show: Show[self.type] = showA
}
Or, you know, stop subtyping and use type classes instead.
I have a set of classes of models, and a set of algorithms that can be run on the models. Not all classes of models can perform all algorithms. I want model classes to be able to declare what algorithms they can perform. The algorithms a model can perform may depend on its arguments.
Example: Say I have two algorithms, MCMC, and Importance, represented as traits:
trait MCMC extends Model {
def propose...
}
trait Importance extends Model {
def forward...
}
I have a model class Normal, which takes a mean argument, which is itself a Model. Now, if mean implements MCMC, I want Normal to implement MCMC, and if mean implements Importance, I want Normal to implement Importance.
I can write:
class Normal(mean: Model) extends Model {
// some common stuff goes here
}
class NormalMCMC(mean: MCMC) extends Normal(mean) with MCMC {
def propose...implementation goes here
}
class NormalImportance(mean: Importance) extends Normal(mean) with Importance {
def forward...implementation goes here
}
I can create factory methods that make sure the right kind of Normal gets created with a given mean. But the obvious question is, what if mean implements both MCMC and Importance? Then I want Normal to implement both of them too. But I don't want to create a new class that reimplements propose and forward. If NormalMCMC and NormalImportance didn't take arguments, I could make them traits and mix them in. But here I want the mixing in to depend on the type of the argument. Is there a good solution?
Using self types allows you to separate the Model-Algorithm implementations from the instantiations and mix them in:
trait Model
trait Result
trait MCMC extends Model {
def propose: Result
}
trait Importance extends Model {
def forward: Result
}
class Normal(val model: Model) extends Model
trait NormalMCMCImpl extends MCMC {
self: Normal =>
def propose: Result = { //... impl
val x = self.model // lookie here... I can use vals from Normal
}
}
trait NormalImportanceImpl extends Importance {
self: Normal =>
def forward: Result = { // ... impl
...
}
}
class NormalMCMC(mean: Model) extends Normal(mean)
with NormalMCMCImpl
class NormalImportance(mean: Model) extends Normal(mean)
with NormalImportanceImpl
class NormalImportanceMCMC(mean: Model) extends Normal(mean)
with NormalMCMCImpl
with NormalImportanceImpl
Thanks to Kevin, Mitch, and Naftoli Gugenheim and Daniel Sobral on the scale-users mailing list, I have a good answer. The two previous answers work, but lead to an exponential blowup in the number of traits, classes and constructors. However, using implicits and view bounds avoids this problem. The steps of the solution are:
1) Give Normal a type parameter representing the type of its argument.
2) Define implicits that take a Normal with the right type of argument to one that implements the appropriate algorithm. For example, makeImportance takes a Normal[Importance] and produces a NormalImportance.
3) The implicits need to be given a type bound. The reason is that without the type bound, if you try to pass a Normal[T] to makeImportance where T is a subtype of Importance, it will not work because Normal[T] is not a subtype of Normal[Importance] because Normal is not covariant.
4) These type bounds need to be view bounds to allow the implicits to chain.
Here's the full solution:
class Model
trait Importance extends Model {
def forward: Int
}
trait MCMC extends Model {
def propose: String
}
class Normal[T <% Model](val arg: T) extends Model
class NormalImportance(arg: Importance) extends Normal(arg) with Importance {
def forward = arg.forward + 1
}
class NormalMCMC(arg: MCMC) extends Normal(arg) with MCMC {
def propose = arg.propose + "N"
}
object Normal {
def apply[T <% Model](a: T) = new Normal[T](a)
}
object Importance {
implicit def makeImportance[T <% Importance](n: Normal[T]): Importance =
new NormalImportance(n.arg)
}
object MCMC {
implicit def makeMCMC[T <% MCMC](n: Normal[T]): MCMC = new NormalMCMC(n.arg)
}
object Uniform extends Model with Importance with MCMC {
def forward = 4
def propose = "Uniform"
}
def main(args: Array[String]) {
val n = Normal(Normal(Uniform))
println(n.forward)
println(n.propose)
}
Much of your problem seems to be that NormalMCMC and NormalImportance take arguments but, as you correctly imply, traits can't have constructors.
Instead, you can take the parameters that you'd want to supply via a trait constructor (if such a thing existed) and make them abstract members of the trait.
The members then get realised when the trait is constructed.
Given:
trait Foo {
val x : String //abstract
}
you can use it as either of the following:
new Bar with Foo { val x = "Hello World" }
new Bar { val x = "Hello World" } with Foo
Which gives you back the equivalent functionality of using Trait constructors.
Note that if the type Bar already has a non-abstract val x : String then you can simply use
new Bar with Foo
In some scenarios it can also help to make x lazy, which can gives you more flexibility if initialization order should become an issue.