Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
April 29, 2022 11:56 am GMT

How To Become a Millionaire Scala Developer

Or, Simple Web API with Http4s and Cats Effect

"The EuroMillions lottery gives you a 1 in 140 million chance of not going to work tomorrow. With alcohol it's 1 in 5." - Anonymous

OK, I'm unlikely to get any "thank you" messages from Millionaires, but if you follow this post then there is a sense in which you will become a millionaire. If our physicists are right. And for a given meaning of become.

Getting All Quantum

So, the set up is this. We use a quantum random number generator, which then splits the universe in 140 million or so worlds, and...

Wait, Splits the Universe?

According to the most austere and plain reading of quantum mechanics, any quantum event which we perceive as probabilistic, is not really - all eventualities actually happen, none of them is a special real eventuality, and it's just our parochial view on the world that only permits us to see one outcome.

So given all that, we use a quantum random number generator, create all those universes and guarantee that a version of me (or you) will win the lottery.

Enough Theory, Let's Get Coding

The first thing I did was create a service for getting random numbers. The class RandomService takes a function that for a given number will generate that many random numbers. I'm using the Cats Effect IO monad to wrap the calculation, as I don't want to immediately evaluate it. Since the call will be to a front end API, and it in turn wants to call the back-end API, I don't want to run any of it explicitly synchronously.

class RandomService(randomFunction: Int => IO[Seq[Int]])

I'm generating randoms in the service, then using them to perform a Fisher-Yates shuffle. If you ask for 5 numbers from 1-50 then it will generate all numbers from 1-50 and take 5 of them.

def generateNumberSequence(numberGroup: NumberGroup): IO[Seq[Int]] = {    randomFunction(numberGroup.size).map(rands => {        val result = shuffle(1 to numberGroup.size, rands)            .take(numberGroup.count)        if (numberGroup.isFullList) result else result.sorted    })}@tailrecfinal def shuffle(values: Seq[Int], randoms: Seq[Int], index: Int = 0): Seq[Int] = {    val n = values.size    if (index == n - 1) values    else shuffle(swap(values, index, index + (randoms(index) % (n - index))), randoms, index + 1)}@tailrecfinal def swap(seq: Seq[Int], i: Int, j: Int): Seq[Int] = {    if (i == j) seq    else if (j < i) swap(seq, j, i)    else seq.take(i) ++ Seq(seq(j)) ++ seq.slice(i + 1, j) ++ Seq(seq(i)) ++ seq.drop(j + 1)}

the NumberGroup is just a data type to carry the magnitude of numbers requested and how many of them. Note that we sort the numbers you request except when the group is full - if you request all numbers from 1-50 then the order is important, you don't just want 1,2,3 ... 50!

The other interesting part is the web service Lotto

trait Lotto {  def generate(vals: Seq[NumberGroup]): IO[Lotto.Response]}object Lotto {  final case class Response(nums: Seq[(Int, Seq[Int])])  val randomService = new RandomService(QRNG.f)  object Response {    implicit val lottoEncoder: Encoder[Response] = (resp: Response) =>      Json.obj(        ("Your Numbers:",      Json.fromFields(resp.nums.map(t => (t._1.toString, t._2.asJson)))        )      )  }  def impl: Lotto = (vals: Seq[NumberGroup]) => {    val resp = vals.map(randomService.generateNumberSequence).sequence    resp.map(r => Response(r.zipWithIndex.map(t => (t._2, t._1))))  }

I love the straightforward declarative nature of the code. Also how concise it is. Most of the complexity is in getting the response to look OK. It still needs some work though!

Notice also the .sequence method that takes a sequence of our IO monads and sequences them into one IO. Conceptually it's reorganizing the result without having to perform the computation. Nice!

All that's left is to run our Http4s server, which couldn't be simpler.

  def run: IO[Nothing] = {    val lottoAlg = Lotto.impl    val httpApp = QuantumMillionaireRoutes.lottoRoutes(lottoAlg).orNotFound    val finalHttpApp = Logger.httpApp(logHeaders = true, logBody = true)(httpApp)    EmberServerBuilder.default[IO]        .withHost(ipv4"0.0.0.0")        .withPort(port"8080")        .withHttpApp(finalHttpApp)        .build  }.useForever

And there it is. All the code is on my GitHub here

And when you do become a Millionaire, please let that version of me know - if I know him, he'll put it on his CV ...


Original Link: https://dev.to/stefintrim/how-to-become-a-millionaire-scala-developer-2elf

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To