I'm working my way through parts of
http://ropas.snu.ac.kr/~bruno/papers/FOPOA.pdf
Feature-Oriented Programming with Object Algebras
I'm not a scala programmer, I can do a bit of F# and Haskell, but the nuances of scala are not obvious to me....so I try to enter the code from the paper;
def fix[A](f: Open[A, A]): A = {
lazy val s: A = f(s); s
}
trait GExpAlg[In,Out] {
def Lit(x : Int) : Out
def Add(e1 : In, e2 : In) : Out
}
type ExpAlg[E] = GExpAlg[E,E]
type OExpAlg[S <: E, E] = GExpAlg[S, Open[S,E]]
type Open[S <: E, E] = (=> S) => E
trait IEval { def eval() : Int }
trait IPrint { def print() : String }
trait ExpPrint2[S <: IEval with IPrint] extends OExpAlg[S, IPrint] {
def Lit(x : Int) = self => new IPrint() { def print() = x.toString() }
def Add(e1 : S, e2 : S) = self => new IPrint() {
def print() = e1.print() + " + " + e2.print() + " = " + self.eval()
}
}
trait CloseAlg[E] extends ExpAlg[E] { val alg : OExpAlg[E,E]
def Lit(x : Int) : E = fix(alg.Lit(x))
def Add(e1 : E, e2 : E) : E = fix(alg.Add(e1,e2))
}
def closeAlg[E](a : OExpAlg[E,E]) : ExpAlg[E] = new CloseAlg[E] {
val alg = a
}
trait SelfAlg[Self <: Exp, Exp] {
val fself : ExpAlg[Self]
}
trait SelfExpAlg[Self <: Exp, Exp] extends GExpAlg[Self,Open[Self,Exp]] with SelfAlg[Self,Exp]
trait ExpPrint3[S <: IEval with IPrint] extends SelfExpAlg[S,IPrint]{
def Lit(x : Int) = self => new IPrint() {def print() = x.toString()}
def Add(e1 : S, e2 : S) = self => new IPrint() {
def print() = {
val plus54 = fself.Add(fself.Lit(5), fself.Lit(4));
e1.print() + " + " + e2.print() + " = " + self.eval() + " and " + "5 + 4 = " + plus54.eval();
}
}
}
def ExpPrint3[S <: IEval with IPrint] : OpenExpAlg[S,IPrint] = s => new ExpPrint3[S] {
lazy val fself = s
}
type OpenExpAlg[S <: E, E] = (=> ExpAlg[S]) => GExpAlg[S, Open[S,E]]
// this is where the error is....
def close[S](f : OpenExpAlg[S,S]) : ExpAlg[S] = fix(compose(closeAlg,f))
Error:(154, 55) not found: value compose
def close[S](f : OpenExpAlg[S,S]) : ExpAlg[S] = fix(compose(closeAlg,f))
Error:(154, 63) missing argument list for method closeAlg in object ScalaApp
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing closeAlg _ or closeAlg(_) instead of closeAlg.
I can force the second error to go away, but I'm confused by the inability to not find compose....(there is some odd about the function type, they are "by name" which I'm not too sure what that means, maybe it's that)
I really don't especially know what I'm doing in scala, and I don't especially know how the IDE works.
def close[S](f : OpenExpAlg[S,S]) : ExpAlg[S] = fix(compose(closeAlg,f))
EDIT
I've amended the code thanks to below answer to
Cyrille Corpet below
def close[S](f : OpenExpAlg[S,S]) : ExpAlg[S] = fix(f.compose(closeAlg _))
I now get;
Error:(160, 65) polymorphic expression cannot be instantiated to expected type;
found : [E]ScalaApp.OExpAlg[E,E] => ScalaApp.ExpAlg[E]
(which expands to) [E]ScalaApp.GExpAlg[E,(=> E) => E] => ScalaApp.GExpAlg[E,E]
required: ? => => ScalaApp.ExpAlg[S]
(which expands to) ? => => ScalaApp.GExpAlg[S,S]
def close[S](f : OpenExpAlg[S,S]) : ExpAlg[S] = fix(f.compose(closeAlg _))
What you should really know about scala, is that everything is an object.
In particular, functions are objects with a method named apply which can be called without naming it so
val f: Int => String = _.toString
f(5) == f.apply(5)
Functions also have a method compose with the given signature:
trait Function1[In, Out] { // A => B is actually syntactic sugar for Function1[A, B]
def compose[Before](that: Before => In): Before => Out
}
So to use it, you should do fun1.compose(fun2) (or using the infix notation fun1 compose fun2), where fun2 is actually the first function to be applied (this is the same weird ordering that you have in mathematics).
EDIT
To know in which order to compose the functions, let's resolve types (I'll use == for type equality, although it does not make sense in code):
f: OpenExpAlg[S, S] == (=> ExpAlg[S]) => GexpAlg[S, Open[S, S]]
closeAlg[S]: OExpAlg[S, S] => ExpAlg[S] == GExpAlg[S, Open[S,S]] => ExpAlg[S]
So (closeAlg[S] compose f): (=> ExpAlg[S]) => ExpAlg[S] == Open[ExpAlg[S]] has the right signature to be a parameter for fix.
However, you still get a problem because closeAlg is not a function, but a method of the enclosing structure. The compiler usually make a conversion between the two, but it might have some trouble sometimes. To help it, you should do
(closeAlg[S] _) compose f
This method _ notation is to force the method to be seen as a function.
Related
What is an idiomatic way of chaining function calls, passing results between each with parameters supplied on the way in Scala?
Here's an example:
def a(x : A, param : String) : A = x
def b(x : A, param : String) : A = x
def c(x : A, param : String) : A = x
def d(x : A, param : String, anotherParam : String) : A = x
val start = A()
d(c(b(a(start, "par1"), "par2"), "par3"), "par4", "anotherPar")
One approach that comes to my mind is Ruby's Kernel#yield_self which allows to do the following:
start
.yield_self {|x| a(x, "par1") }
.yield_self {|x| b(x, "par2") }
.yield_self {|x| c(x, "par3") }
.yield_self {|x| d(x, "par4", "anotherPar) }
You may combine chain of functions into one function:
val start = new A()
val func: (A => A) =
((x: A) => a(x, "par1"))
.andThen(b(_, "par2"))
.andThen(c(_, "par3"))
.andThen(d(_, "par4", "anotherPar"))
func(start)
But I'm not sure if it's a your goal.
I'd say that chaining functions using well... chaining isn't that bad already:
(
{ (x: A) => a(x, "par1") } andThen
{ x => b(x, "par2") } andThen
{ x => c(x, "par3") } andThen
{ x => d(x, "par4", "anotherPar") }
)(start)
However, if you insist on having a yieldSelf method, here you go:
import scala.language.implicitConversions
case class YieldSelf[X](x: X) {
def yieldSelf[Y](f: X => Y): Y = f(x)
}
implicit def everythingCanYieldSelf[X](x: X) = YieldSelf(x)
start.
yieldSelf{ a(_, "par1") }.
yieldSelf{ b(_, "par2") }.
yieldSelf{ c(_, "par3") }.
yieldSelf{ d(_, "par4", "anotherPar") }
As soon as the implicit definition is in the scope, it adds a yieldSelf method to every object, which has the same semantics as in Ruby.
I would ensure that a method should only accept instances of A or B or C. And I don't want to modify the code of A, B and C.
case class A
case class B
case class C
def method(aOrbOrc: Any) = ???
// method("toto") should not compile
You can use Type Class.
case class A(s: String)
case class B(i: Int)
case class C(i1: Int, i2: Int)
// Type Class
trait ABC[T] {
def bar(t: T): String
}
// Instances
implicit object ABC_A extends ABC[A] {
override def bar(t: A): String = "A : s = " + t.s
}
implicit object ABC_B extends ABC[B] {
override def bar(t: B): String = "B : i = " + t.i
}
implicit object ABC_C extends ABC[C] {
override def bar(t: C): String = "C : i1 = " + t.i1 + ", i2 = " + t.i2
}
def method[T](abc: T)(implicit instance: ABC[T]) = println(instance.bar(abc))
method(A("AAAAA")) // => A : s = AAAAA
method(B(123)) // => B : i = 123
method(C(9, 5)) // => C : i1 = 9, i2 = 5
method(1) // compilation error
You could use Miles Sabin's idea for implementing union types (code below is taken from Rex Kerr's variant):
trait Contra[-A] {}
type Union[A,B,C] = {
type Check[Z] = Contra[Contra[Z]] <:< Contra[Contra[A] with Contra[B] with Contra[C]]
}
then do:
def method[T: Union[A,B,C]#Check](t: T) = ???
for example:
def method[T: Union[Int,String,Boolean]#Check](t:T) = ???
method(1) // OK
method("foo") // OK
method(true) // OK
method(1.5) // does not compile
Read more about it here. And here is a link to Miles' post.
Suppose I would like to define arithmetic operators for functional types like () => Int, () => Double etc in the following manner
def + (a : () => Int, b : () => Int) =
new (() => Int) {
def apply() = a() + b()
}
Is there any way to avoid boiler plate code in defining similar functions for all possible argument type combinations?
These types can be built-in ones (Int, Long, Double), user-defined ones (like Currency, Quantity etc), and Option[T] where T can be any before mentioned types.
def + (a : () => Option[Int], b : () => Double) =
new (() => Option[Double])
{
// this specific code could be factored out
def apply() =
a() map { _ + b() }
}
You can create trait which instances define concrete implementation of your operations for particular type. Then require this trait as implicit parameter for your operations and invoke these concrete implementations.
For the example, check sources of scala.math.Numeric.
It seems to me that the problem can be solved by introducing
trait PlusDefined[A,B] {
type Ret
def plus(a : A, b : B) : Ret
}
and introducing implicit values for different types. My current solution couldn't avoid all boiler-plate code (like explicit overloads for Option[T]) but looks workable:
import language.implicitConversions
trait Conversion[From, To]
{
def convert(from : From) : To
}
object Conversions {
implicit def toOption[T, U](implicit ev : Conversion[T,U])
: Conversion[T, Option[U]] =
new Conversion[T, Option[U]]
{
def convert(x : T) = Some(ev.convert(x))
}
implicit def toOptionId[T]
: Conversion[T, Option[T]] =
new Conversion[T, Option[T]]
{
def convert(x : T) = Some(x)
}
implicit def betweenOptions[T, U](implicit ev : Conversion[T,U])
: Conversion[Option[T], Option[U]] =
new Conversion[Option[T], Option[U]]
{
def convert(x : Option[T]) = x map { y => ev.convert(y) }
}
implicit val int2double =
new Conversion[Int, Double]{ def convert(x : Int) = x }
implicit val int2long =
new Conversion[Int, Long] { def convert(x : Int) = x }
implicit val long2double =
new Conversion[Long, Double]{ def convert(x : Long) = x }
}
trait PlusDefined[A,B]
{
type Ret
def plus(a : A, b : B) : Ret
}
trait Addable_Level1 {
implicit def rightConversion[A,B](implicit c : Conversion[A,B],
ev : PlusDefined[B,B])
: PlusDefined[A,B] =
new PlusDefined[A,B]
{
type Ret = PlusDefined[B,B]#Ret
def plus(a : A, b : B) = ev.plus(c.convert(a), b)
}
implicit def leftConversion[A,B](implicit c : Conversion[B,A],
ev : PlusDefined[A,A])
: PlusDefined[A,B] =
new PlusDefined[A,B]
{
type Ret = PlusDefined[A,A]#Ret
def plus(a : A, b : B) = ev.plus(a, c.convert(b))
}
}
trait Addable_Level2 extends Addable_Level1
{
implicit def rightOpt[A,B](implicit ev : PlusDefined[A,B])
: PlusDefined[A,Option[B]] =
new PlusDefined[A,Option[B]]
{
type Ret = Option[PlusDefined[A,B]#Ret]
def plus(a : A, b : Option[B]) = b map { x => ev.plus(a,x) }
}
implicit def leftOpt[A,B](implicit ev : PlusDefined[A,B])
: PlusDefined[Option[A],B] =
new PlusDefined[Option[A],B]
{
type Ret = Option[PlusDefined[A,B]#Ret]
def plus(a : Option[A], b : B) = a map { x => ev.plus(x,b) }
}
implicit def bothOpt[A,B](implicit ev : PlusDefined[A,B])
: PlusDefined[Option[A],Option[B]] =
new PlusDefined[Option[A],Option[B]]
{
type Ret = Option[PlusDefined[A,B]#Ret]
def plus(a : Option[A], b : Option[B]) =
(a,b) match {
case (Some(x), Some(y)) => Some(ev.plus(x,y))
case _ => None
}
}
}
object Addable extends Addable_Level2 {
implicit def fromNumeric[T : Numeric]
: PlusDefined[T,T] = new PlusDefined[T,T]
{
type Ret = T
def plus(a : T, b : T) = implicitly[Numeric[T]].plus(a,b)
}
}
Recently I have come across a very useful groupBy function that Groovy has made available on Iterable:
public static Map groupBy(Iterable self, List<Closure> closures)
Which you can use to perform recursive groupBy on Lists and even Maps see example by mrhaki here
I would like to write a function that does the same in Scala. But having just started my Scala journey, I am kind of lost on how I should going about defining and implementing this method. Especially the generics side of the functions and return type on this method's signature are way beyond my level.
I would need more experienced Scala developers to help me out here.
Is this following signature totally wrong or am I in the ball park?
def groupBy[A, K[_]](src: List[A], fs: Seq[(A) ⇒ K[_]]): Map[K[_], List[A]]
Also, how would I implement the recursion with the correct types?
This is simple multigroup implementation:
implicit class GroupOps[A](coll: Seq[A]) {
def groupByKeys[B](fs: (A => B)*): Map[Seq[B], Seq[A]] =
coll.groupBy(elem => fs map (_(elem)))
}
val a = 1 to 20
a.groupByKeys(_ % 3, _ % 2) foreach println
If you really need some recursive type you'll need a wrapper:
sealed trait RecMap[K, V]
case class MapUnit[K, V](elem: V) extends RecMap[K, V] {
override def toString = elem.toString()
}
case class MapLayer[K, V](map: Map[K, RecMap[K, V]]) extends RecMap[K, V] {
override def toString = map.toString()
}
out definition changes to:
implicit class GroupOps[A](coll: Seq[A]) {
def groupByKeys[B](fs: (A => B)*): Map[Seq[B], Seq[A]] =
coll.groupBy(elem => fs map (_(elem)))
def groupRecursive[B](fs: (A => B)*): RecMap[B, Seq[A]] = fs match {
case Seq() => MapUnit(coll)
case f +: fs => MapLayer(coll groupBy f mapValues {_.groupRecursive(fs: _*)})
}
}
and a.groupRecursive(_ % 3, _ % 2) yield something more relevant to question
And finally i rebuild domain definition from referred article:
case class User(name: String, city: String, birthDate: Date) {
override def toString = name
}
implicit val date = new SimpleDateFormat("yyyy-MM-dd").parse(_: String)
val month = new SimpleDateFormat("MMM").format (_:Date)
val users = List(
User(name = "mrhaki", city = "Tilburg" , birthDate = "1973-9-7"),
User(name = "bob" , city = "New York" , birthDate = "1963-3-30"),
User(name = "britt" , city = "Amsterdam", birthDate = "1980-5-12"),
User(name = "kim" , city = "Amsterdam", birthDate = "1983-3-30"),
User(name = "liam" , city = "Tilburg" , birthDate = "2009-3-6")
)
now we can write
users.groupRecursive(_.city, u => month(u.birthDate))
and get
Map(Tilburg -> Map(Mar -> List(liam), Sep -> List(mrhaki)), New York
-> Map(Mar -> List(bob)), Amsterdam -> Map(Mar -> List(kim), May -> List(britt)))
I decided add another answer, due to fully different approach.
You could, actually get non-wrapped properly typed maps with huge workarounds. I not very good at this, so it by the chance could be simplified.
Trick - is to create Sequence of typed functions, which is lately producing multi-level map using type classes and type path approach.
So here is the solution
sealed trait KeySeq[-V] {
type values
}
case class KeyNil[V]() extends KeySeq[V] {
type values = Seq[V]
}
case class KeyCons[K, V, Next <: KeySeq[V]](f: V => K, next: Next)
(implicit ev: RecGroup[V, Next]) extends KeySeq[V] {
type values = Map[K, Next#values]
def #:[K1](f: V => K1) = new KeyCons[K1, V, KeyCons[K, V, Next]](f, this)
}
trait RecGroup[V, KS <: KeySeq[V]] {
def group(seq: Seq[V], ks: KS): KS#values
}
implicit def groupNil[V]: RecGroup[V, KeyNil[V]] = new RecGroup[V, KeyNil[V]] {
def group(seq: Seq[V], ks: KeyNil[V]) = seq
}
implicit def groupCons[K, V, Next <: KeySeq[V]](implicit ev: RecGroup[V, Next]): RecGroup[V, KeyCons[K, V, Next]] =
new RecGroup[V, KeyCons[K, V, Next]] {
def group(seq: Seq[V], ks: KeyCons[K, V, Next]) = seq.groupBy(ks.f) mapValues (_ groupRecursive ks.next)
}
implicit def funcAsKey[K, V](f: V => K): KeyCons[K, V, KeyNil[V]] =
new KeyCons[K, V, KeyNil[V]](f, KeyNil[V]())
implicit class GroupOps[V](coll: Seq[V]) {
def groupRecursive[KS <: KeySeq[V]](ks: KS)(implicit g: RecGroup[V, KS]) =
g.group(coll, ks)
}
key functions are composed via #: right-associative operator
so if we define
def mod(m:Int) = (x:Int) => x % m
def even(x:Int) = x % 2 == 0
then
1 to 30 groupRecursive (even _ #: mod(3) #: mod(5) )
would yield proper Map[Boolean,Map[Int,Map[Int,Int]]] !!!
and if from previous question we would like to
users.groupRecursive(((u:User)=> u.city(0)) #: ((u:User) => month(u.birthDate)))
We are building Map[Char,Map[String,User]] !
I have been searching the forum and Google for answers to type erasure issues for Scala. However, I cannot find anything that answers my question.
I struggling with pattern matching on objects that match the type parameter of ParamClass. I need to pattern match on the type of incoming objects to the bar method. I have seen solutions such as
bar[X](a : X)(implicit m : Manifest[X])
which would solve my problem, but I cannot use this as the bar method is an overridden method. (Actually is the receive partial function in the Akka actor framework). The code is given below and should be self explanatory:
class ParamClass[A : Manifest] {
def bar(x : Any) = x match {
case a: A => println("Found A: " + a)
case _ => println("No match: " + x)
}
}
object ErasureIssue {
def main(args: Array[String]) {
val clz = new ParamClass[Int]
clz.bar("faf")
clz.bar(2.3)
clz.bar(12) // this should match, but does not
}
}
ErasureIssue.main(null)
Any help on solving this issue is greatly appreciated. I'm using Scala 2.9.1, BTW.
-J
In theory you could check in bar like this: x.getClass == implicitly[Manifest[A]].erasure, but that fails for primitive types such as Int for which the manifest correctly erases to Int, but bar is called with boxed type java.lang.Integer ... :-(
You could require A to be an AnyRef in order to get the boxed manifest:
class ParamClass[A <: AnyRef : Manifest] {
def bar(x : Any) = x match {
case _ if x.getClass == implicitly[Manifest[A]].erasure =>
println("Found A: " + x.asInstanceOf[A])
case _ => println("No match: " + x)
}
}
object ErasureIssue {
def main(args: Array[String]) {
val clz = new ParamClass[Integer] // not pretty...
clz.bar("faf")
clz.bar(2.3)
clz.bar(12) // ok
}
}
ErasureIssue.main(null)
Given your requirement to construct primitive arrays, you could store directly the boxed class, independently of the unboxed manifest:
object ParamClass {
def apply[A](implicit mf: Manifest[A]) = {
val clazz = mf match {
case Manifest.Int => classOf[java.lang.Integer] // boxed!
case Manifest.Boolean => classOf[java.lang.Boolean]
case _ => mf.erasure
}
new ParamClass[A](clazz)
}
}
class ParamClass[A] private[ParamClass](clazz: Class[_])(implicit mf: Manifest[A]) {
def bar(x : Any) = x match {
case _ if x.getClass == clazz =>
println("Found A: " + x.asInstanceOf[A])
case _ => println("No match: " + x)
}
def newArray(size: Int) = new Array[A](size)
override def toString = "ParamClass[" + mf + "]"
}
val pi = ParamClass[Int]
pi.bar("faf")
pi.bar(12)
pi.newArray(4)
val ps = ParamClass[String]
ps.bar("faf")
ps.bar(12)
ps.newArray(4)
If you try to compile with -unchecked, you immediately get the warning.
test.scala:3: warning: abstract type A in type pattern A is unchecked
since it is eliminated by erasure
case a: A => println("Found A: " + a)
If you now want to go deeper, you can use scalac -print
[[syntax trees at end of cleanup]]// Scala source: test.scala
package <empty> {
class ParamClass extends java.lang.Object with ScalaObject {
def bar(x: java.lang.Object): Unit = {
<synthetic> val temp1: java.lang.Object = x;
if (temp1.$isInstanceOf[java.lang.Object]())
{
scala.this.Predef.println("Found A: ".+(temp1))
}
else
{
scala.this.Predef.println("No match: ".+(x))
}
};
def this(implicit evidence$1: scala.reflect.Manifest): ParamClass = {
ParamClass.super.this();
()
}
};
final object ErasureIssue extends java.lang.Object with ScalaObject {
def main(args: Array[java.lang.String]): Unit = {
val clz: ParamClass = new ParamClass(reflect.this.Manifest.Int());
clz.bar("faf");
clz.bar(scala.Double.box(2.3));
clz.bar(scala.Int.box(12))
};
def this(): object ErasureIssue = {
ErasureIssue.super.this();
()
}
}
}
Now seeing this code you can see that your A has turned into a java.lang.Object, which cause all the parameters to match the clause