I have case class State and want to extend Variable class from it; but in Variable class only need value in constructor. Where can I put run function?
case class State[S, +A](run: S => (A, S)) {
//.....has `map` function
def map[B, X >: State[S, B]](f: A => B): X =
State(state => {
val (a, s2) = run(state)
(f(a), s2)
})
}
class Variable[+A](value: A) extends State[A, A] { // ERROR
def get: Variable[A] =
map(x => x)
def set(newValue: A): Variable[A] =
map(_ => newValue)
}
UPDATE
I've changed to something like this:
class Variable[+A](value: A, run: A => (A, A)) extends State[A, A](run) {
def get: Variable[A] =
map(x => x) // ERROR HERE
def set(newValue: A): State[A, A] =
map(_ => newValue)
}
object Variable {
def create[A](value: A): Variable[A] = new Variable[A](value, x => (x, x))
}
But I've gotten error:
type mismatch; found : com.libs.State[A,A] required: com.libs.Variable[A] Variable.scala /scala/src/com/libs line 4 Scala Problem
The problem is that you cannot define a Variable using map, since map defines a State which is only a super-type of Variable. How can your program know how to set the additional information of your subclass, using only map?
However, if you define type Variable[+A] = State[A, A], so that it is not a subclass but an alias for the same class, you will have some variance errors, since State is invariant in its type parameter S, so Variable must be too.
Related
As a part of learning Scala I try to implement Haskell's flip function (a function with signature (A => B => C) => (B => A => C)) in Scala - and implement it as a function (using val) and not as a method (using def).
I can implement it as a method, for instance this way:
def flip[A, B, C](f: (A, B) => C):((B, A) => C) = (b: B, a: A) => f(a, b)
val minus = (a: Int, b: Int) => a - b
val f = flip(minus)
println(f(3, 5))
However, when I try to implement it as a function, it does not work:
val flip = (f: ((Any, Any) => Any)) => ((a: Any, b: Any) => f(b, a))
val minus = (a: Int, b: Int) => a - b
val f = flip(minus)
println(f(3, 5))
When I try to compile this code, it fails with this message:
Error:(8, 18) type mismatch;
found : (Int, Int) => Int
required: (Any, Any) => Any
val f = flip(minus)
I understand why it fails: I try to pass (Int, Int) => Int where (Any, Any) => Any is expected. However, I don't know how to fix this problem. Is it possible at all?
Scala doesn't support polymorphic functions, unlike methods which are. This is due to the first class value nature of functions, which are simply instances of the FunctioN traits. These functions are classes, and they need the types to be bound at declaration site.
If we took the flip method and tried to eta expand it to a function, we'd see:
val flipFn = flip _
We'd get back in return a value of type:
((Nothing, Nothing) => Nothing) => (Nothing, Nothing) => Nothing
Due to the fact that none of the types were bound, hence the compiler resorts to the buttom type Nothing.
However, not all hope is lost. There is a library called shapeless which does allow us to define polymorphic functions via PolyN.
We can implement flip like this:
import shapeless.Poly1
object flip extends Poly1 {
implicit def genericCase[A, B, C] = at[(A, B) => C](f => (b: B, a: A) => f(a, b))
}
flip is no different from the FunctionN trait, it defines an apply method which will be called.
We use it like this:
def main(args: Array[String]): Unit = {
val minus = (a: Int, b: Int) => a - b
val f = flip(minus)
println(f(3, 5))
}
Yielding:
2
This would also work for String:
def main(args: Array[String]): Unit = {
val stringConcat = (a: String, b: String) => a + b
val f = flip(stringConcat)
println(f("hello", "world"))
}
Yielding:
worldhello
I have and ADT which is basically a wrapper over Function1:
case class Abstract[M[_], A, B](f:M[A] => M[B]) {
def fn: M[A] => M[B] = { case x: M[A] => f(x) }
}
I want to map over these, so I defined a Functor like so:
trait AbstractAPI[E] {
type AbsO[T] = Abstract[List, E, T]
// type AbsO[T] = Abstract[List, _, T] => does not work (?)
implicit val abstractO: Functor[AbsO] = new Functor[AbsO] {
def map[A, B](fa: AbsO[A])(f: A => B): AbsO[B] = {
new Abstract(fa.fn andThen { x: List[A] => x.map{ y => f(y) } })
}
}
}
Now, to actually map over an Abstract, I'd need AbstractAPI[Int], like
case object IntAbstractAPI extends AbstractAPI[Int]
object A {
import IntAbstractAPI._
val f:List[Int] => List[String] = { case x: List[Int] => x.map{ _.toString.toLowerCase } }
val hey = (new Abstract(f)).map{ x => x.toInt }
}
or
object A extends AbstractAPI[Int] {
val f:List[Int] => List[String] = { case x: List[Int] => x.map{ _.toString.toLowerCase } }
// FINALLY!
val res = (new Abstract(f)).map{ x => x.toInt }.map{ _.toFloat + 10f }
// Abstract[List, Int, Float] = Abstract(<function1>)
}
However, in this pattern, I'd have to define case objects for every possible E. Here are my questions:
Is this the correct way to use Functors?
How can I automate the creation of the case objects for every possible E (or make the compiler infer it?)
Edit 1:
Further clarification: The above implementation works, but this one does not:
object A extends AbstractAPI {
val f:List[Int] => List[String] = { case x: List[Int] => x.map{ _.toString.toLowerCase } }
val res = (new Abstract(f)).map{ x => x.toInt }.map{ _.toFloat + 10f }
// Abstract[List, Int, Float] = Abstract(<function1>)
}
gives compilation error:
value map is not a member of Abstract[List,Int,String]
I assume this is because the compiler is not able to derive a functor for Abstract[List,Int,String]?
You can derive a functor for type parameters that you don't care about.
import cats.Functor
import cats.syntax.functor._
And I'll rename second type parameter on Abstract to X, it'll help
case class Abstract[M[_], X, A](f: M[X] => M[A]) // forget the fn bit for now
You can create typeclass instances not only with a val, but also with a def. It is allowed to have type parameters and also take other implicit (but only implicit) parameters.
type Abs1[X] = ({ type L[A] = Abstract[List, X, A] })
/*implicit*/ def abstract1[X]: Functor[Abs1[X]#L] = new Functor[Abs1[X]#L] {
override def map[A, B](fa: Abstract[List, X, A])(f: A => B): Abstract[List, X, B] =
Abstract(mx => fa.f(mx).map(f))
}
If map is all you need from a List, you can generalize further for any M[_] that has a Functor instance. Also placing it into a companion object of Abstract enables it to be found without additional imports / inheritance / etc.
object Abstract {
// Abstract.MX[M, X]#L can be replaced with Abstract[M, X, ?] if you use kind-projector
type MX[M[_], X] = ({ type L[A] = Abstract[M, X, A] })
implicit def genericFunctor[M[_]: Functor, X] = new Functor[MX[M, X]#L] {
override def map[A, B](fa: Abstract[M, X, A])(f: A => B): Abstract[M, X, B] =
Abstract(mx => fa.f(mx).map(f)) // the implementation is the same
}
}
And it works, if you import instances for whatever your M[_] is
assert {
import cats.instances.list._ // get Functor[List]
// map is automatically picked up from Functor[Abstract[List, Int, ?]]
Abstract(identity[List[Int]])
.map(Vector.range(0, _))
.map(_.mkString(""))
.f(List(1, 2, 3)) == List("0", "01", "012")
}
assert {
import cats.instances.option._
Abstract(identity[Option[Int]])
.map(_ min 42)
.map(i => Range(i, i + 3))
.f(Some(11)) == Some(Range(11, 14))
}
You can try the code there
Answering your second question, you could try this implicit AbstractAPI[T] factory:
implicit def abstractAPI[T]: AbstractAPI[T] = new AbstractAPI[T] {}
Any required implicit evidence for AbstractAPI[T] should work, e.g:
def f[T : AbstractAPI]: Unit = ()
f
I would like to have groupByIndex function that groups values based on their index (and not the value).
A concrete method definition for Vector[A] could look like the following:
def groupByIndex[A, K](vector: Vector[A], f: Int => K): immutable.Map[K, Vector[(A, Int)]] = {
vector.zipWithIndex.groupBy { case (elem, index) => f(index) }
}
Testing this function in the REPL gives indeed the correct result:
scala> val vec = Vector.tabulate(4)(i => s"string ${i+1}")
vec: scala.collection.immutable.Vector[String] = Vector(string 1, string 2, string 3, string 4)
scala> groupByIndex(vec, i => i%2)
res2: scala.collection.immutable.Map[Int,Vector[(String, Int)]] = Map(1 -> Vector((string 2,1), (string 4,3)), 0 -> Vector((string 1,0), (string 3,2)))
Now, I would like to apply the "enrich-my-library" pattern to give this method to all the classes that should support it, i.e. classes that implement zipWithIndex and groupBy. Those two methods are defined in GenIterableLike (zipWithIndex) and GenTraversableLike/TraversableLike (groupBy).
With all this in mind, I tried to mimic the method definitions of zipWithIndex (this is the problematic) and groupBy to build my own groupByIndex:
implicit class GenIterableLikeOps[A, Repr](val iterable: GenIterableLike[A, Repr] with TraversableLike[A, Repr]) extends AnyVal {
def groupByIndex[K, A1 >: A, That <: TraversableLike[(A1, Int), OtherRepr], OtherRepr](f: Int => K)(implicit bf: CanBuildFrom[Repr, (A1, Int), That]): immutable.Map[K, OtherRepr] = {
val zipped = iterable.zipWithIndex
zipped.groupBy{ case (elem, index) => f(index) }
}
}
First, this seems way too complicated to me - is there a way to simplify this? For example, can we somehow drop the second OtherRepr? (I was not able to.)
Second, I am not able to call this function without explicitly specifying the generic parameters. Using the example from above I get the following error:
scala> vec.groupByIndex(i => i%2)
<console>:21: error: Cannot construct a collection of type scala.collection.TraversableLike[(String, Int),Nothing] with elements of type (String, Int) based on a collection of type scala.collection.immutable.Vector[String].
vec.groupByIndex(i => i%2)
^
scala> vec.groupByIndex[Int, String, Vector[(String, Int)], Vector[(String, Int)]](i => i%2)
res4: scala.collection.immutable.Map[Int,Vector[(String, Int)]] = Map(1 -> Vector((string 2,1), (string 4,3)), 0 -> Vector((string 1,0), (string 3,2)))
How do I a) simplify this method and b) make it work without having to specify the generic parameters?
You can substitute the OtherThat type parameter by That. That way you get rid of OtherThat and solve the problem of having to specify the generic type parameters. The compiler is then able to resolve That by looking at the implicit value for CanBuildFrom[Repr, (A1, Int), That].
implicit class GenIterableLikeOps[A, Repr]
(val iterable: GenIterableLike[A, Repr] with TraversableLike[A, Repr])
extends AnyVal {
def groupByIndex
[K, A1 >: A, That <: TraversableLike[(A1, Int), That]]
(f: Int => K)(implicit bf: CanBuildFrom[Repr, (A1, Int), That])
: Map[K, That] = {
val zipped = iterable.zipWithIndex
zipped.groupBy{ case (elem, index) => f(index) }
}
}
This isn't as good as the other answer, but if you don't care about what you're building, one way to simplify and avoid building the zipped collection:
implicit class gbi[A](val as: Traversable[A]) extends AnyVal {
def groupByIndex[K](f: Int => K) = (as, (0 until Int.MaxValue)).zipped.groupBy { case (x, i) => f(i) }
}
The range is a benign way to avoid taking the size of the traversable.
When I learn State Monad, I'm not sure how to compose two functions with different State return types.
State Monad definition:
case class State[S, A](runState: S => (S, A)) {
def flatMap[B](f: A => State[S, B]): State[S, B] = {
State(s => {
val (s1, a) = runState(s)
val (s2, b) = f(a).runState(s1)
(s2, b)
})
}
def map[B](f: A => B): State[S, B] = {
flatMap(a => {
State(s => (s, f(a)))
})
}
}
Two different State types:
type AppendBang[A] = State[Int, A]
type AddOne[A] = State[String, A]
Two methods with differnt State return types:
def addOne(n: Int): AddOne[Int] = State(s => (s + ".", n + 1))
def appendBang(str: String): AppendBang[String] = State(s => (s + 1, str + " !!!"))
Define a function to use the two functions above:
def myAction(n: Int) = for {
a <- addOne(n)
b <- appendBang(a.toString)
} yield (a, b)
And I hope to use it like this:
println(myAction(1))
The problem is myAction is not compilable, it reports some error like this:
Error:(14, 7) type mismatch;
found : state_monad.State[Int,(Int, String)]
required: state_monad.State[String,?]
b <- appendBang(a.toString)
^
How can I fix it? Do I have to define some Monad transformers?
Update: The question may be not clear, let me give an example
Say I want to define another function, which uses addOne and appendBang internally. Since they all need existing states, I have to pass some to it:
def myAction(n: Int)(addOneState: String, appendBangState: Int): ((String, Int), String) = {
val (addOneState2, n2) = addOne(n).runState(addOneState)
val (appendBangState2, n3) = appendBang(n2.toString).runState(appendBangState)
((addOneState2, appendBangState2), n3)
}
I have to run addOne and appendBang one by one, passing and getting the states and result manually.
Although I found it can return another State, the code is not improved much:
def myAction(n: Int): State[(String, Int), String] = State {
case (addOneState: String, appendBangState: Int) =>
val (addOneState2, n2) = addOne(n).runState(addOneState)
val (appendBangState2, n3) = appendBang(n2.toString).runState( appendBangState)
((addOneState2, appendBangState2), n3)
}
Since I'm not quite familiar with them, just wondering is there any way to improve it. The best hope is that I can use for comprehension, but not sure if that's possible
Like I mentioned in my first comment, it will be impossible to use a for comprehension to do what you want, because it can not change the type of the state (S).
Remember that a for comprehension can be translated to a combination of flatMaps, withFilter and one map. If we look at your State.flatMap, it takes a function f to change a State[S,A] into State[S, B]. We can use flatMap and map (and thus a for comprehension) to chain together operations on the same state, but we can't change the type of the state in this chain.
We could generalize your last definition of myAction to combine, compose, ... two functions using state of a different type. We can try to implement this generalized compose method directly in our State class (although this is probably so specific, it probably doesn't belong in State). If we look at State.flatMap and myAction we can see some similarities:
We first call runState on our existing State instance.
We then call runState again
In myAction we first use the result n2 to create a State[Int, String] (AppendBang[String] or State[S2, B]) using the second function (appendBang or f) on which we then call runState. But our result n2 is of type String (A) and our function appendBang needs an Int (B) so we need a function to convert A into B.
case class State[S, A](runState: S => (S, A)) {
// flatMap and map
def compose[B, S2](f: B => State[S2, B], convert: A => B) : State[(S, S2), B] =
State( ((s: S, s2: S2) => {
val (sNext, a) = runState(s)
val (s2Next, b) = f(convert(a)).runState(s2)
((sNext, s2Next), b)
}).tupled)
}
You then could define myAction as :
def myAction(i: Int) = addOne(i).compose(appendBang, _.toString)
val twoStates = myAction(1)
// State[(String, Int),String] = State(<function1>)
twoStates.runState(("", 1))
// ((String, Int), String) = ((.,2),2 !!!)
If you don't want this function in your State class you can create it as an external function :
def combineStateFunctions[S1, S2, A, B](
a: A => State[S1, A],
b: B => State[S2, B],
convert: A => B
)(input: A): State[(S1, S2), B] = State(
((s1: S1, s2: S2) => {
val (s1Next, temp) = a(input).runState(s1)
val (s2Next, result) = b(convert(temp)).runState(s2)
((s1Next, s2Next), result)
}).tupled
)
def myAction(i: Int) =
combineStateFunctions(addOne, appendBang, (_: Int).toString)(i)
Edit : Bergi's idea to create two functions to lift a State[A, X] or a State[B, X] into a State[(A, B), X].
object State {
def onFirst[A, B, X](s: State[A, X]): State[(A, B), X] = {
val runState = (a: A, b: B) => {
val (nextA, x) = s.runState(a)
((nextA, b), x)
}
State(runState.tupled)
}
def onSecond[A, B, X](s: State[B, X]): State[(A, B), X] = {
val runState = (a: A, b: B) => {
val (nextB, x) = s.runState(b)
((a, nextB), x)
}
State(runState.tupled)
}
}
This way you can use a for comprehension, since the type of the state stays the same ((A, B)).
def myAction(i: Int) = for {
x <- State.onFirst(addOne(i))
y <- State.onSecond(appendBang(x.toString))
} yield y
myAction(1).runState(("", 1))
// ((String, Int), String) = ((.,2),2 !!!)
The trait below compiles fine without the #specialized annotations, or without the map method. Otherwise, it will fail with a compilation error, which doesn't make a lot of sense (at least to me):
[error] (compile:compile) scala.tools.nsc.symtab.Types$TypeError: type mismatch;
[error] found : U(in method foreach)(in method foreach)
[error] required: U(in method foreach)(in method foreach)
This is the trait that I'm talking about:
trait Tuple2Traversable[#specialized(Int, Byte) +A, #specialized(Int, Byte) +B] {
def foreach[T](fn: (A, B) => T)
def map[T](fn: (A, B) => T): Traversable[T] = new Traversable[T] {
def foreach[U](f: T => U) {
def composed(a: A, b: B) = f(fn(a, b))
Tuple2Traversable.this.foreach(composed)
}
}
def flatMap[T](fn: (A, B) => Traversable[T]): Traversable[T] = new Traversable[T] {
def foreach[U](f: (T) => U) {
def composed(a: A, b: B) = fn(a, b).foreach(f)
Tuple2Traversable.this.foreach(composed)
}
}
def filter(included: (A, B) => Boolean): Tuple2Traversable[A, B] = new Tuple2Traversable[A, B] {
def foreach[T](fn: (A, B) => T) {
def composed(a: A, b: B) = if (included(a, b)) fn(a, b)
Tuple2Traversable.this.foreach(composed)
}
}
def foldLeft[T](z: T)(fn: (T, A, B) => T): T = {
var current = z
def op(a: A, b: B) {
current = fn(current, a, b)
}
foreach(op)
current
}
def asTraversable = new Traversable[(A, B)] {
def foreach[U](f: ((A, B)) => U) {
def tupled(a: A, b: B) = f((a, b))
Tuple2Traversable.this.foreach(tupled)
}
}
}
I've been staring at this for a while now. Any suggestions on how to solve this would be highly appreciated.
Perhaps I should add that the purpose of this class is to have a Traversable of tuples, without forcing those tuples to ever be created. A Traversable[(A,B)] would accept a Tuple2[A,B] => T as the parameter of foreach. I want my 'traversable' to accept a function (A, B) => T. (Like def fn(a: Int, b: Int) = a + b.)
Looks like some internal compiler bug. I get the same error in scala 2.9.2, but it compiles fine in scala 2.10-RC2