I am new to scala.
Lately I have tried to write some math functions, but I don't understand what I am doing wrong.
import scala.annotation.tailrec
import scala.math.{pow, sqrt}
object HikeStatProcessor {
def mean(list: List[Double]): Double = {
sum(list, value => value) / list.size
}
def std(list: List[Double]): Double = {
val means: Double = mean(list)
sqrt(pow(sum(list, (head: Double) => head - means), 2) / list.size)
}
private def sum(list: List[Double],
operation: Double => Double): Double = {
#tailrec
def innerCalc(xs: List[Double], accu: Double): Double = {
if (xs.isEmpty) return accu
println(accu + operation(xs.head))
innerCalc(xs.tail, accu + operation(xs.head))
}
innerCalc(list, 0)
}
}
val a = HikeStatProcessor.std(List(1, 2, 3))
Could you please provide a fix for the above code and a brief explanation of what I was doing wrong?
Consider this statement: sum(list, (head: Double) => head - means). Let's break it down into smaller steps.
sum(list , (head: Double) => head - means)
sum(List(1,2,3), x => x - 2)
sum(List(1-2, 2-2, 3-2))
-1 + 0 + 1 = 0
If you subtract the average from each element, the sum is always going to be zero (or close to it). What was your intention?
Thanks all for the answers.
I solved the issue by changing the def std to:
def std(list: List[Double]): Double = {
val means: Double = mean(list)
sqrt( sum(list, (head: Double) => pow(head - means, 2)) / (list.size - 1) )
}
The issue was caused by the fact that I did not evaluate the pow 2 within my anonymous function.
Related
I'm trying to understand how to leverage monads in scala to solve simple problems as way of building up my familiarity. One simple problem is estimating PI using a functional random number generator. I'm including the code below for a simple stream based approach.
I'm looking for help in translating this to a monadic approach. For example, is there an idiomatic way convert this code to using the state (and other monads) in a stack safe way?
trait RNG {
def nextInt: (Int, RNG)
def nextDouble: (Double, RNG)
}
case class Point(x: Double, y: Double) {
val isInCircle = (x * x + y * y) < 1.0
}
object RNG {
def nonNegativeInt(rng: RNG): (Int, RNG) = {
val (ni, rng2) = rng.nextInt
if (ni > 0) (ni, rng2)
else if (ni == Int.MinValue) (0, rng2)
else (ni + Int.MaxValue, rng2)
}
def double(rng: RNG): (Double, RNG) = {
val (ni, rng2) = nonNegativeInt(rng)
(ni.toDouble / Int.MaxValue, rng2)
}
case class Simple(seed: Long) extends RNG {
def nextInt: (Int, RNG) = {
val newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFFL
val nextRNG = Simple(newSeed)
val n = (newSeed >>> 16).toInt
(n, nextRNG)
}
def nextDouble: (Double, RNG) = {
val (n, nextRNG) = nextInt
double(nextRNG)
}
}
}
object PI {
import RNG._
def doubleStream(rng: Simple):Stream[Double] = rng.nextDouble match {
case (d:Double, next:Simple) => d #:: doubleStream(next)
}
def estimate(rng: Simple, iter: Int): Double = {
val doubles = doubleStream(rng).take(iter)
val inside = (doubles zip doubles.drop(3))
.map { case (a, b) => Point(a, b) }
.filter(p => p.isInCircle)
.size * 1.0
(inside / iter) * 4.0
}
}
// > PI.estimate(RNG.Simple(10), 100000)
// res1: Double = 3.14944
I suspect I'm looking for something like replicateM from the Applicative monad in cats but I'm not sure how to line up the types or how to do it in a way that doesn't accumulate intermediate results in memory. Or, is there a way to do it with a for comprehension that can iteratively build up Points?
Id you want to iterate using monad in a stack safe way, then there is a tailRecM method implemented in Monad type class:
// assuming random generated [-1.0,1.0]
def calculatePi[F[_]](iterations: Int)
(random: => F[Double])
(implicit F: Monad[F]): F[Double] = {
case class Iterations(total: Int, inCircle: Int)
def step(data: Iterations): F[Either[Iterations, Double]] = for {
x <- random
y <- random
isInCircle = (x * x + y * y) < 1.0
newTotal = data.total + 1
newInCircle = data.inCircle + (if (isInCircle) 1 else 0)
} yield {
if (newTotal >= iterations) Right(newInCircle.toDouble / newTotal.toDouble * 4.0)
else Left(Iterations(newTotal, newInCircle))
}
// iterates until Right value is returned
F.tailRecM(Iterations(0, 0))(step)
}
calculatePi(10000)(Future { Random.nextDouble }).onComplete(println)
It uses by-name param because you could try to pass there something like Future (even though the Future is not lawful), which are eager, so you would end up with evaluating the same thing time and time again. With by name param at least you have the chance of passing there a recipe for side-effecting random. Of course, if we use Option, List as a monad holding our "random" number, we should also expect funny results.
The correct solution would be using something that ensures that this F[A] is lazily evaluated, and any side effect inside is evaluated each time you need a value from inside. For that you basically have to use some of Effects type classes, like e.g. Sync from Cats Effects.
def calculatePi[F[_]](iterations: Int)
(random: F[Double])
(implicit F: Sync[F]): F[Double] = {
...
}
calculatePi(10000)(Coeval( Random.nextDouble )).value
calculatePi(10000)(Task( Random.nextDouble )).runAsync
Alternatively, if you don't care about purity that much, you could pass side effecting function or object instead of F[Int] for generating random numbers.
// simplified, hardcoded F=Coeval
def calculatePi(iterations: Int)
(random: () => Double): Double = {
case class Iterations(total: Int, inCircle: Int)
def step(data: Iterations) = Coeval {
val x = random()
val y = random()
val isInCircle = (x * x + y * y) < 1.0
val newTotal = data.total + 1
val newInCircle = data.inCircle + (if (isInCircle) 1 else 0)
if (newTotal >= iterations) Right(newInCircle.toDouble / newTotal.toDouble * 4.0)
else Left(Iterations(newTotal, newInCircle))
}
Monad[Coeval].tailRecM(Iterations(0, 0))(step).value
}
Here is another approach that my friend Charles Miller came up with. It's a bit more direct since it uses RNG directly but it follows the same approach provided by #Mateusz Kubuszok above that leverages Monad.
The key difference is that it leverages the State monad so we can thread the RNG state through the computation and generate the random numbers using the "pure" random number generator.
import cats._
import cats.data._
import cats.implicits._
object PICharles {
type RNG[A] = State[Long, A]
object RNG {
def nextLong: RNG[Long] =
State.modify[Long](
seed ⇒ (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFFL
) >> State.get
def nextInt: RNG[Int] = nextLong.map(l ⇒ (l >>> 16).toInt)
def nextNatural: RNG[Int] = nextInt.map { i ⇒
if (i > 0) i
else if (i == Int.MinValue) 0
else i + Int.MaxValue
}
def nextDouble: RNG[Double] = nextNatural.map(_.toDouble / Int.MaxValue)
def runRng[A](seed: Long)(rng: RNG[A]): A = rng.runA(seed).value
def unsafeRunRng[A]: RNG[A] ⇒ A = runRng(System.currentTimeMillis)
}
object PI {
case class Step(count: Int, inCircle: Int)
def calculatePi(iterations: Int): RNG[Double] = {
def step(s: Step): RNG[Either[Step, Double]] =
for {
x ← RNG.nextDouble
y ← RNG.nextDouble
isInCircle = (x * x + y * y) < 1.0
newInCircle = s.inCircle + (if (isInCircle) 1 else 0)
} yield {
if (s.count >= iterations)
Right(s.inCircle.toDouble / s.count.toDouble * 4.0)
else
Left(Step(s.count + 1, newInCircle))
}
Monad[RNG].tailRecM(Step(0, 0))(step(_))
}
def unsafeCalculatePi(iterations: Int) =
RNG.unsafeRunRng(calculatePi(iterations))
}
}
Thanks Charles & Mateusz for your help!
I'd like to be able to do:
object AddOrSubtract {
def apply(x: Int, adding: Int) = x + adding
def apply(x: Int, subtracting: Int) = x - subtracting
}
AddOrSubtract(1, adding = 5) // should be 6
AddOrSubtract(1, subtracting = 5) // should be -4
But I get the error:
Error:(1331, 7) method apply is defined twice;
the conflicting method apply was defined at line 1330:7
def apply(x: Int, subtracting: Int) = x - subtracting
I understand that this is because the two methods have the same signatures. Is there some pattern for getting around this? The only thing I can think of is using an implicit to change the type of value, like:
object AddOrSubtract {
implicit class AddInt(val x: Int)
implicit class SubInt(val x: Int)
def apply(x: Int, adding: AddInt) = x + adding.x
def apply(x: Int, subtracting: SubInt) = x - subtracting.x
def run(): Unit = {
AddOrSubtract(1, adding = 5)
AddOrSubtract(1, subtracting = 5)
}
}
But I'm curious if there is any other less inelegant way of accomplishing this?
Your example code may be over-simplified for your real-world use case. If so then this solution won't be applicable.
object AddOrSubtract {
def apply(x: Int, adding: Int=0, subtracting: Int=0) = x + adding - subtracting
}
AddOrSubtract(1, adding = 5) // res0: Int = 6
AddOrSubtract(1, subtracting = 5) // res1: Int = -4
AFAIK there is no good solution.
The only workaround I can imagine is
object AddOrSubtract {
def apply(x: Int, adding: Int = 0, subtracting: Int = 0) =
match (adding, subtracting) {
case (0, 0) => throw Error("either adding or subtracting is required")
case (x, 0) => x + adding
case (0, x) => x - subtracting
case (_, _) => throw Error("for now both adding and subtracting is not allowed")
}
AddOrSubtract(1, adding = 5) // should be 6
AddOrSubtract(1, subtracting = 5) // should be -4
But it is far from perfect
I tried this
probability function returning only single value of list but not all why
var l=List(2.2,3.1)
def sum(xs: List[Double]): Double=
{
if(xs.isEmpty) 0.0
else xs.head+sum(xs.tail)
}
var s=sum(l)
def probability_calculation( xs: List[Double], s:Double): List[Double]=
{
var p=List[Double]()
var R=2
if(xs.isEmpty) List()
else
{
p=p:::List(xs.head*R/s)
probability_calculation(xs.tail,s)
}
p
}
probability_calculation(l,s)
You're re-initializing the list on every recursion:
var p=List[Double]()
So your final result list will only contain the last element.
I don't see the need for the recursion, you could just map it:
def probability_calculation(xs: List[Double], s: Double): List[Double] = {
val R = 2
xs.map(x => x * R / s)
}
A few comments on your approach!
Try avoiding using var's in your function as that is exactly the source of your problem that you are facing!
Also, your sum function could be written as simple as:
val sum = List(2.2, 3.1).foldLeft(0.0)(_ + _)
Your probability distribution function could be written as:
def probCaclculation(xs: List[Double], s: Double): List[Double] = xs.map(x => x * 2 / s)
Code:
object Integral {
def approx(start: Double, end: Double, nIntervals: Int)(f: Double => Double): Double = {
val delta = (end - start) / nIntervals
val halfDelta = delta / 2
val xs = start until end by delta
xs.map(x => f(x + halfDelta) * delta).sum
}
def approx(startEnd: Array[Double], nIntervas: Int)(f: Double => Double): Double = {
require(startEnd.length == 2)
val startEndSorted = startEnd.sorted
val res = approx(startEndSorted(0), startEndSorted(1), nIntervas)(f)
if(startEndSorted == startEnd) res else (-res)
}
}
object IntegralTest {
def f1(x: Double) = {
math.pow(x, 3) - 6 * x
}
println(Integral.approx(0, 3, 6)(f1))
println(Integral.approx(0, 1, 60000)(f1))
def f2(x: Double) = {
math.sqrt(1 - x * x)
}
println(Integral.approx(0, 1, 60000)(f2))
println(math.Pi / 4)
println(Integral.approx(0, 3, 60000)({
(x: Double) => x - 1
}))
println(Integral.approx(1, 2, 5)({
(x: Double) => 1 / x
}))
// test the exponential function
println(Integral.approx(1, 3, 60000)(math.exp))
println(math.exp(3) - math.exp(1))
}
I want to make approx(start: Double, end: Double, nIntervals: Int)(f: Double => Double): Double private and change all the reference to it to approx(startEnd: Array[Double], nIntervas: Int)(f: Double => Double): Double, is there a way to do this safely and hassle-free in intellij?
Update
I soon realized that for this specific case I could have handled it in a better way (by recursion):
def approx(start: Double, end: Double, nIntervals: Int)(f: Double => Double): Double = {
if(start > end) {
-approx(end, start, nIntervals)(f)
} else {
val delta = (end - start) / nIntervals
val halfDelta = delta / 2
val xs = start until end by delta
xs.map(x => f(x + halfDelta) * delta).sum
}
}
But I am still interested in finding out how to refactor the old problematic code because it might be useful in the future.
I don't know if the fact you use it for Scala changes anything, but you should be able to right-click on a function, and Change method signature to the one you want (so you wouldn't replace function1 by function2 per se, but rather modify f1 to match f2).
Edit: This won't work as per Ben comment. Leaving anyway for the sake of mentioning the functionality.
I've been trying to finish this scala code that uses a list to output the summation of all positive integers in the list.. I got it working except for having it only work for positive numbers. but i cant get it to only output the positive numbers. I have 2 versions that ive been trying to get to work, i thought maybe it would be easier wit cases, but i ended up running into the same problem. I've been trying if statements with xs<0 , but those don't work, and i cant get the filter to work with the fold. any suggestions with how to handle this?
def sum(xs: List[Int]): Int = {
xs.filter((x: Int) => x > 0)
xs.foldLeft(0) { _ + _ }
}
def sum2(xs: List[Int]): Int = xs match {
case Nil => 0
case y :: ys => y + sum(ys)
}
xs is an immutable List[Int], which means you are not just modifying the same xs value and returning it.
def sum(xs: List[Int]): Int = {
xs.filter((x: Int) => x > 0) // This is a pure expression and effectively does nothing
xs.foldLeft(0) { _ + _ } // This is the value that is returned, modifying the *original* `xs` parameter
}
What you need to do is chain the functions together, to operate on the same value.
def sum(xs: List[Int]): Int = {
xs.filter((x: Int) => x > 0).foldLeft(0) { _ + _ }
}
The type check isn't necessary here, so it can be shorted:
def sum(xs: List[Int]): Int = xs.filter(_ > 0).foldLeft(0)(_ + _)
There is also a sum method on List that does the same thing as your foldLeft.
def sum(xs: List[Int]): Int = xs.filter(_ > 0).sum
List(1, -2, 3).filter(_ > 0).sum // 4
or in a single pass
List(1, -2, 3).foldLeft(0){(acc, i) => if (i > 0) acc + i else acc } //4
Your 1st version is almost right. Remember that filter method doesn't have side effects, so just try this small change:
def sum(xs: List[Int]): Int = {
xs.filter((x: Int) => x > 0).foldLeft(0) { _ + _ }
}
Or simpler version:
def sum(xs: List[Int]): Int = {
xs.filter(_ > 0).sum
}
i ended up trying this , which i think is right. based on the suggestions
val f = xs.filter((x: Int) => x > 0)
f.foldLeft(0) { _ + _ }