Object orientation in Scala - scala

From Martin Odersky's Scala course I have the following Exercise (this a video exercise in which answer is given):
"
Provide an implementation of the abstract class Nat that represents
non-negative integers
Do not use standard numerical classes in this implementation.
Rather, implement a sub-object and a sub-class.
One for the number zero, the other for strictly prositive numbers.
"
Here is the code :
abstract class Nat {
def isZero : scala.Boolean
def predecessor : Nat
def successor = new Succ(this)
def + (that : Nat) : Nat
def - (that : Nat) : Nat
}
object Zero extends Nat {
def isZero = true
def predecessor = throw new Error("0.predecessor")
def + (that: Nat) = that
def - (that: Nat) = if(that.isZero) this else throw new Error("negative number")
}
class Succ(n : Nat) extends Nat {
def isZero = false
def predecessor = n
def +(that : Nat) = new Succ(n + that)
def -(that: Nat) = n - that.predecessor
}
Within a Scala worksheet I have :
object NatTests {
new Successor(Zero).+(new Successor(Zero))
}
Which returns a new Sucessor. I don't think I'm understanding this code fully as I should be able to add non zero objects without extending the code ? If so, how is this accomplished ?

You are able to add non zero numbers / objects without extending any of the classes Nat, Zero, or Succ. When you use an object natObj of type Nat and construct a new object new Succ(natObject) that new object represents a number that is one higher than the number that natObj represents.
Maybe being able to view the objects, makes this a bit clearer:
abstract class Nat {
def isZero : Boolean
def predecessor : Nat
def successor = new Succ(this)
def + (that : Nat) : Nat
def - (that : Nat) : Nat
}
object Zero extends Nat {
def isZero = true
def predecessor = throw new Error("0.predecessor")
def + (that: Nat) = that
def - (that: Nat) = if(that.isZero) this else throw new Error("negative number")
override def toString = "0 => Zero"
}
class Succ(n : Nat) extends Nat {
def isZero = false
def predecessor = n
def + (that : Nat) = new Succ(n + that)
def - (that: Nat) = if (that.isZero) this else n - that.predecessor
override def toString = {
def findNumber(nat: Nat): Int =
if (nat.isZero) 0
else 1 + findNumber(nat.predecessor)
val number = findNumber(this)
String.valueOf(number) + " => " +
((1 to number) fold ("Zero")) ( (s,_) => "Succ(" + s + ")")
}
}
Now your Scala worksheet will show you the number an object represents and its internal structure:
object NatTests extends App {
val nat0 = Zero
val nat1 = new Succ(Zero)
val nat2 = new Succ(nat1) // or new Succ(new Succ(Zero))
val nat3 = new Succ(nat2) // or new Succ(new Succ(new Succ(Zero)))
println(nat0) //> 0 => Zero
println(nat1) //> 1 => Succ(Zero)
println(nat2) //> 2 => Succ(Succ(Zero))
println(nat3) //> 3 => Succ(Succ(Succ(Zero)))
println(nat2 + nat2) //> 4 => Succ(Succ(Succ(Succ(Zero))))
println(nat3 + nat2) //> 5 => Succ(Succ(Succ(Succ(Succ(Zero)))))
}

You're most likely expected to implement them recursively
I'm not sure of the exact syntax, but it'd be something like this
def +(that : Nat) = (this.predecessor + that.successor)
def -(that: Nat) = if (that.isZero) this else (this.predecessor - that.predecessor)
Also since your objects are immutable, there's no real reason to create a new one each time.

That's how I would write it:
sealed trait Nat {
def isZero : scala.Boolean
def predecessor : Nat
def successor = Succ(this)
def + (that : Nat) : Nat
def - (that : Nat) : Nat =
if (that.isZero) this else this.predecessor - that.predecessor
}
case object Zero extends Nat {
def isZero = true
def predecessor = sys.error("predecessor of zero")
def + (that: Nat) = that
}
case class Succ(predecessor : Nat) extends Nat {
def isZero = false
def +(that : Nat) = this.predecessor + that.successor
}

Related

Type mismatch error when type is not defined in abstract class

I am new to Scala and got stuck with a compiler error from below code. I am trying to implement a Natural number class which represents +ve integers. I am facing problem while defining the + operator which should follow, def + (that: Nat): Nat but I don't define this in abstract class I get below error. But it goes away once it is defined in the abstract class.
[error] D:\Scala\NatuarlNum\src\main\scala\NatuarlNum.scala:31:46: type mismatch;
[error] found : Nat
[error] required: String
[error] def + (that: Nat): Nat = new Succ(previous.+(that))
I am not able to understand why it says required is "String" instead of "Nat". even when the function declaration is present just before the definition.
Here is the code:
abstract class Nat {
def isZero: Boolean
def predecessor: Nat
def successor: Nat
//def + (that: Nat): Nat // By uncommentng this line the error will go away
//def - (that: Nat): Nat
override def toString: String = {
if (this.isZero) {
"0"
} else {
"{" + this.predecessor.toString + "}"
}
}
}
object Zero extends Nat {
def isZero = true
def predecessor = throw new Error("0.predecessor")
def successor: Nat = new Succ(this)
def + (that: Nat): Nat = that
}
class Succ(previous: Nat) extends Nat {
def isZero = false
def predecessor = previous
def successor: Nat = new Succ(this)
def + (that: Nat): Nat = new Succ(previous.+(that)) // The error is from this line
}
object NatuarlNum {
def main(args: Array[String]): Unit = {
val zero = Zero
val one = new Succ(zero)
val two = new Succ(one)
val three = new Succ(new Succ(new Succ(Zero)))
println("0 = " + zero)
println("1 = " + one)
println("2 = " + two)
println("3 = " + three)
println("0 + 2 = " + (zero + two))
println("2 + 2 = " + (two + two))
}
}
Without the + operator my code compiles and gives result like this:
0 = 0
1 = {0}
2 = {{0}}
3 = {{{0}}}
0 + 2 = {{0}}
Well, you gave an answer to your question in your code.
//def + (that: Nat): Nat // By uncommentng this line the error will go away
//def - (that: Nat): Nat
The problem is,
def + (that: Nat): Nat = new Succ(previous.+(that))
previous is of type Nat, which doesn't have + operator override.
If you uncomment the definition for operators in Nat - it will work.
The default implementation of + operator takes String as a parameter, which explains the error message you get, see any2stringadd for more info and there is a ticket to remove implicit + operator definition.
From compiler warning:
Predef is deprecated (since 2.13.0): Implicit injection of + is deprecated. Convert to String to call +

what's wrong with this code...."compose"

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.

Accessing a Scala Trait method inside another method

I am writing a trait that contains a function:
trait MyTrait[X,Y] {
def f(x : X) : Y
}
I'm trying to add a map function:
trait MyTrait[X,Y] {
def f(x : X) : Y // the outer f
def map[Z](g : Y => Z) : MyTrait[X,Y] = MyTrait[X,Z] {
//namespace conflict : I need to access the outer f within this f
override def f(x : X) : Z = outerF andThen g
}
}
My question is: how do I reference the outer f? I've tried super.f and this.f to no avail. I'm sure this is a basic question that has been asked before but it's not very "google-able", e.g. easy to search for.
thank you in advance for your consideration and response.
You can use self type
trait MyTrait[X,Y] {
self =>
def f(x : X) : Y // the outer f
def map[Z](g : Y => Z) : MyTrait[X,Y] = MyTrait[X,Z] {
override def f(x : X) : Z = self.f andThen g
}
}
You can also use override def f(x : X) : Z = MyTrait.this.f andThen g.

overloading a function for a bunch of types

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)
}
}

Playing with Nat without case classes

I just create a definition in scala for Naturals, and also a PLUS operation:
abstract class Nat {
def +(other:Nat):Nat = this match {
case Zero => other
case Succ(x) => x + Succ(other)
}
}
object Zero extends Nat {
override def toString = "Zero"
}
And for the definition of Succ, i tryit not to use a Case class, for learning purposes. My first approach was:
class Succ(x: Nat) extends Nat {
override def toString = "Succ(" + x.toString + ")"
}
object Succ {
def apply(x: Nat) = new Succ(x)
def unapply(s: Succ) = Some(s.x)
}
But the compiler throws me an error
Error:( , ) value x is not a member of Succ
def unapply(s: Succ) = Some(s.x)
^
I make an explicit method for get X, and it works
class Succ(x: Nat) extends Nat {
def getX = x
override def toString = "Succ(" + x.toString + ")"
}
object Succ {
def apply(x: Nat) = new Succ(x)
def unapply(s: Succ) = Some(s.getX)
}
Why?
Constructor arguments are only visible inside the class. If you want to make it a field, you'll have to say so:
class Succ(val x: Nat) extends Nat { … }
// ^^^