Cannot create constructor with logic in Scala program? - scala

I have the following program:
class Rational(n: Int, d: Int) {
require(d != 0)
private val g = gcd(n.abs, d.abs)
val numer = n / g
val denom = d / g
def this(n: Int) = this(n, 1)
def this(s: String) = {
val regex: Regex = "^([+-]?(\\d+|\\d*\\.?\\d+)|\\d*\\/?\\d+)$".r
if (!regex.matches(s)) throw new NumberFormatException()
val input: Array[String] = s.split("\\.|\\/")
val num: Int = input(0).toInt
if (input.length equals 1)
this(num, 1) // problem here
else
this(num, input(1).toInt) // problem here
}
}
I tried to create the constructor with some logic. However, I cannot due to
'Rational' does not take parameters
What's the problem?

Try to introduce a helper method
import scala.util.matching.Regex
def gcd(i: Int, i1: Int): Int = BigInt(i).gcd(BigInt(i1)).toInt
class Rational(n: Int, d: Int) {
require(d != 0)
private val g = gcd(n.abs, d.abs)
val numer = n / g
val denom = d / g
def this(n: Int) = this(n, 1)
def this(s: String) = {
this(Rational.transformStr(s)._1, Rational.transformStr(s)._2)
}
}
object Rational {
// helper method
def transformStr(s: String): (Int, Int) = {
val regex: Regex = "^([+-]?(\\d+|\\d*\\.?\\d+)|\\d*\\/?\\d+)$".r
if (!regex.matches(s)) throw new NumberFormatException()
val input: Array[String] = s.split("\\.|\\/")
val num: Int = input(0).toInt
if (input.length equals 1)
(num, 1)
else
(num, input(1).toInt)
}
}
or better, factory methods (because constructors have many limitations)
class Rational(n: Int, d: Int) {
require(d != 0)
private val g = gcd(n.abs, d.abs)
val numer = n / g
val denom = d / g
}
object Rational {
// factory methods
def apply(n: Int) = new Rational(n, 1)
def apply(s: String): Rational = {
val regex: Regex = "^([+-]?(\\d+|\\d*\\.?\\d+)|\\d*\\/?\\d+)$".r
if (!regex.matches(s)) throw new NumberFormatException()
val input: Array[String] = s.split("\\.|\\/")
val num: Int = input(0).toInt
if (input.length equals 1)
new Rational(num, 1)
else
new Rational(num, input(1).toInt)
}
}
Executing code in overloaded constructor prior to calling this()
By the way, you can also use default values
class Rational(n: Int, d: Int = 1 /*default*/ ) {
// ...
}
object Rational {
def apply(s: String): Rational = ???
}

Related

How is the property assignment in scala swing implemented

In scala swing I can do something like the following:
val field = new TextField("", 4)
field.text = "Hello"
And the assignment is implemented thus:
def text_=(t: String): Unit = peer.setText(t)
But if I try my own implementation such as:
case class A(i: Int) {
def value_=(j: Int) = copy(i = j)
}
val a = A(3)
a.value = 3
This will not compile for me. What am I missing?
In Scala 2.13 (and 3) the setter def value_= (or def value_$eq) seems to work if you declare a field value
case class A(i: Int) {
val value: Int = 0
def value_=(j: Int) = copy(i = j)
}
or
case class A(i: Int, value: Int = 0) {
def value_=(j: Int) = copy(i = j)
}
By the way, it's a little confusing that a setter value_= returns A rather than Unit
println(a.value = 4) // A(4,0)
In Scala 2.12 the "setter" def value_= (or def value_$eq) works if you declare a "getter" too
case class A(i: Int) {
def value = "value"
def value_=(j: Int) = copy(i = j)
}

How to pass a scala class as an object into a function parameter?

How do I run the refint1 function? I've triedvar x = new RefInt(5) and then doing scala> argpass.refint1(x)but get a found: RefInt, required : argpass.RefInt => Unit error in the console.
object argpass{
class RefInt (initial : Int) {
private var n : Int = initial
def get () : Int = n
def set (m : Int) : Unit = { n = m}
}
def refint1 ( f: RefInt => Unit) : (Int, Int, Int) = {
var x = new RefInt(5)
val first = f(x)
val firstget = x.get
val sec = f(x)
val secget = x.get
val third = f(x)
val thirdget = x.get
(firstget, secget, thirdget)
}
//How do i run the refint1 function?
As Luis said in the comments, f returns Unit, which is basically void. This should solve your problem:
class RefInt(initial: Int) {
var n: Int = initial
def get(): Int = n
def set(m: Int): Unit = { n = m }
}
def refint1(f: RefInt => Unit): (Int, Int, Int) = {
var x = new RefInt(5)
f(x)
val firstget = x.get
f(x)
val secget = x.get
f(x)
val thirdget = x.get
(firstget, secget, thirdget)
}
That being said, I think you can improve your design a little bit. Here's a different approach to solve the same problem:
case class RefInt(initial: Int)
def refInt1(initial: RefInt, f: RefInt => RefInt) : (Int, Int, Int) = {
val x0 = f(initial)
val x1 = f(x0)
val x2 = f(x1)
(x0.initial, x1.initial, x2.initial)
}
println(refInt1(RefInt(5), ri => ri.copy(ri.initial * 2)))

scala trait members and derivated variables

Hi am trying to write a simple hill climbing algorithm in scala .
I have State and HillClimbing that are traits.
I define them as concrete classes when I apply them to the Graph problem.
In GraphHillClimbing I receive two errors. This is because I use GraphState instead of State (observe that GraphState is also a State).
How can I solve this?
trait State {
val loc = 0
def neighbours: List[State]
def get_loc():Int = return loc
}
class GraphState(loc:Int, g: Map[Int, List[Int]]) extends State {
def neighbours():List[GraphState] =
{
def neighboursAcc(l:List[Int], acc:List[GraphState], g:Map[Int, List[Int]]):List[GraphState] =
{
if(l.isEmpty) acc
else {
val new_neig = new GraphState(l.head, g)
neighboursAcc(l.tail, List(new_neig) ++ acc, g)
}
}
neighboursAcc(g(loc), List(), g)
}
}
trait HillClimbing {
val max_iteration = 4
val start:State
def cost(state:State):Double
private def argmin(costs:List[Double]):Int = {
val best = costs.min
costs.indexOf(best)
}
private def next_best(states:List[State]):State = {
val costs = states map(x => cost(x))
val pos = argmin(costs)
states(pos)
}
def minimize():State = {
def minimizeAcc(iteration:Int, state:State):State =
{
if(iteration > max_iteration) state
else {
val neigs = state.neighbours
val next_state = next_best(neigs)
minimizeAcc(iteration+1, next_state)
}
}
minimizeAcc(0, start)
}
}
class GraphHillClimbing(start:GraphState, goal:GraphState) extends HillClimbing {
// ERROR 1 = start was State and now it is GraphState
// ERROR 2 = cost should take a State
def cost(current_state:GraphState):Double = {
val distance = goal.get_loc() - current_state.get_loc()
if(distance > 0 ) distance
else -distance
}
}
object RunHillClimbing {
def main(args: Array[String]) {
val G = Map[Int, List[Int]](1->List(2, 4, 5), 2->List(1, 3, 4), 3->List(2, 6), 4->List(1, 2, 5), 5->List(1, 4), 6->List(3))
val start = new GraphState(1, G)
val goal = new GraphState(6, G)
val hc = new GraphHillClimbing(start, goal)
print(hc.minimize())
}
}
I think this can be solved using some type parameters with type bounds.
Also in your constructor for GraphHillClimbing you should use val to indicate that the parameter start is the concrete implementation of the abstract start.
trait State[+Self] {
Self =>
def loc:Int
def neighbours: List[Self]
def get_loc():Int = return loc
}
class GraphState(val loc:Int, g: Map[Int, List[Int]]) extends State[GraphState] {
def neighbours():List[GraphState] =
{
def neighboursAcc(l:List[Int], acc:List[GraphState], g:Map[Int, List[Int]]):List[GraphState] =
{
if(l.isEmpty) acc
else {
val new_neig = new GraphState(l.head, g)
neighboursAcc(l.tail, List(new_neig) ++ acc, g)
}
}
neighboursAcc(g(loc), List(), g)
}
}
trait HillClimbing[T<:State[T]] {
val max_iteration = 4
val start:T
def cost(state:T):Double
private def argmin(costs:List[Double]):Int = {
val best = costs.min
costs.indexOf(best)
}
private def next_best(states:List[T]):T = {
val costs = states map(x => cost(x))
val pos = argmin(costs)
states(pos)
}
def minimize():T = {
def minimizeAcc(iteration:Int, state:T):T =
{
if(iteration > max_iteration) state
else {
val neigs = state.neighbours
val next_state = next_best(neigs)
minimizeAcc(iteration+1, next_state)
}
}
minimizeAcc(0, start)
}
}
class GraphHillClimbing(val start:GraphState, goal:GraphState) extends HillClimbing[GraphState] {
def cost(current_state:GraphState):Double = {
val distance = goal.get_loc() - current_state.get_loc()
if(distance > 0 ) distance
else -distance
}
}
object RunHillClimbing {
def main(args: Array[String]) {
val G = Map[Int, List[Int]](1->List(2, 4, 5), 2->List(1, 3, 4), 3->List(2, 6), 4->List(1, 2, 5), 5->List(1, 4), 6->List(3))
val start = new GraphState(1, G)
val goal = new GraphState(6, G)
val hc = new GraphHillClimbing(start, goal)
print(hc.minimize())
}
}
What I get:
error: class GraphHillClimbing needs to be abstract, since:
it has 2 unimplemented members.
/** As seen from class GraphHillClimbing, the missing signatures are as follows.
* For convenience, these are usable as stub implementations.
*/
def cost(state: this.State): Double = ???
val start: this.State = ???
class GraphHillClimbing(start:GraphState, goal:GraphState) extends HillClimbing {
^
Replace GraphState in the class with State, because inheritance
demands you'll have to handle State not GraphState.
Then replace
val loc = 0
with
def loc = 0
So you can overwrite it in GraphState.

How to create custom assignment operator in Scala

I'm trying to create a custom data type that behaves like an Int, but has certain specific behavior and typing (eg., it has to be positive, it has to fit within the range of our database's 'integer' type, etc).
To make it a friendly class, I want to have custom assignment operators, etc., for instance I'd like the following to all work:
val g: GPID = 1 // create a GPID type with value 1
val g: GPID = 1L // take assignment from a Long (and downcast into Int)
if (g == 1) ... // test the value of GPID type against an Int(1)
This is what I have so far but I'm not getting the expected behavior:
case class GPID(value: Int) extends MappedTo[Int] {
require(value >= 1, "GPID must be a positive number")
require(value <= GPDataTypes.integer._2, s"GPID upper bound is ${GPDataTypes.integer._2}")
def this(l: Long) = this(l.toInt)
def GPID = value
def GPID_=(i: Int) = new GPID(i)
def GPID_=(l: Long) = new GPID(l.toInt)
override def toString: String = value.toString
override def hashCode:Int = value
override def equals(that: Any): Boolean =
that match {
case that: Int => this.hashCode == that.hashCode
case that: Long => this.hashCode == that.hashCode
case _ => false
}
}
object GPID {
implicit val writesGPID = new Writes[GPID] {
def writes(g: GPID): JsValue = {
Json.obj(
"GPID" -> g.value
)
}
}
implicit val reads: Reads[GPID] = (
(__ \ "GPID").read[GPID]
)
def apply(l: Long) = new GPID(l.toInt)
implicit def gpid2int(g: GPID): Int = hashCode
implicit def gpid2long(g: GPID): Long = hashCode.toLong
}
The problems I have are:
Assignment doesn't work, for instance:
val g: GPID = 1
Implicit conversion is not working, for instance:
val i: Int = g
Any help would be appreciated... haven't build a custom type like this before so overriding assignment and implicit conversion is new to me...
object TestInt extends App {
class GPID(val value: Int) {
require(value >= 1, "GPID must be a positive number")
require(value <= 10, s"GPID upper bound is 10")
override def equals(that: Any) = value.equals(that)
override def toString = value.toString
// add more methods here (pimp my library)
}
implicit def fromInt(value: Int) = new GPID(value)
implicit def fromInt(value: Long) = new GPID(value.toInt) //possible loss of precision
val g: GPID = 1
val g2: GPID = 1L
if (g == 1)
println("ONE: " + g)
else
println("NOT ONE: " + g)
}
Prints:
ONE: 1

Setting instance vars with apply

With Array it's possible to get and set elements with val i = xs(0) and xs(0) = i syntax. How to implement this functionality in my own class? So far I was only able to implement getting the values.
class Matrix(val m : Int, val n : Int) {
val matrix = Array.ofDim[Double](m, n)
def apply(i:Int)(j:Int) = matrix(i)(j)
}
UPDATE: Thanks to Mauricio for answer about update method. That's the final version
class Matrix(val m:Int, val n:Int) {
private val matrix = Array.ofDim[Double](m, n)
def apply(i:Int) = new {
def apply(j:Int) = matrix(i)(j)
def update(j:Int, v:Double) = { matrix(i)(j) = v }
}
}
it("matrix") {
val m = new Matrix(3, 3)
m(0)(1) = 10.0
val x = m(0)(1)
x should equal(10.0)
x.isNegInfinity should be (false) // Implicits for Double work!
}
You need to declare an update method:
class Matrix(val m : Int, val n : Int) {
private val matrix = Array.ofDim[Double](m, n)
def apply(i:Int)(j:Int) = matrix(i)(j)
def update( i : Int, j : Int, value : Double) {
matrix(i)(j) = value
}
}
val m = new Matrix( 10, 10 )
m(9, 9) = 50