Wednesday, January 24, 2024

In Scala compiling, how to tell type checker to show us the added "given" it finds

More here

Find the max-diff value in a List with the difference is from the values on the right vs. the value on the left in the List

//1 - Int
def maxIntDiff(list: List[Int]): Int =
@tailrec
def findMaxDiff(max: Int, diff: Int, as: List[Int]): Int = as match
case Nil => diff
case h :: t if h > max => findMaxDiff(h, diff, t)
case h :: t => findMaxDiff(max, Math.max(diff, max - h), t)
val rev = list.reverse
findMaxDiff(Int.MinValue, rev.head, rev.tail)
//2 - Generic way
def maxDiff[T: Ordering : Numeric](list: List[T], min: T): T =
@tailrec
def findMaxDiff(max: T, diff: T, as: List[T]): T = as match
case Nil => diff
case h :: t if Ordering[T].compare(h, max) > 0 => findMaxDiff(h, diff, t)
case h :: t => findMaxDiff(max, Numeric[T].max(diff, Numeric[T].minus(max, h)), t)
val rev = list.reverse
findMaxDiff(min, rev.head, rev.tail)
//3 - with Max/Min Pair
def maxDiffInfo[T: Ordering: Numeric](list: List[T], min: T): (T, (T, T)) =
@tailrec
def findMaxDiff(max: T, diff: T, as: List[T], pair: (T, T)): (T, (T, T)) = as match
case Nil => (diff, pair)
case h::t if Ordering[T].compare(h, max) > 0 => findMaxDiff(h, diff, t, pair)
case h::t =>
val nMaxDiff = Numeric[T].max(diff, Numeric[T].minus(max, h))
findMaxDiff(max, nMaxDiff, t, if Numeric[T].compare(nMaxDiff, diff) != 0 then (h, max) else pair)
val rev = list.reverse
findMaxDiff(min, rev.head, rev.tail, (min, min))
A simple example for Scala 3 type class derivation:
import scala.deriving.Mirror.ProductOf
object Decoder {
type Row = List[String]
extension (row: Row)
def as[T](using p: ProductOf[T], d: RowDecoder[p.MirroredElemTypes]): T =
p.fromProduct(d.decode(row))
trait RowDecoder[A]:
def decode(a: Decoder.Row): A
trait FieldDecoder[A]:
def decodeField(a: String): A
private def csvToProduct[P](row: Row)(using p: ProductOf[P], d: RowDecoder[p.MirroredElemTypes]): P = row.as[P]
given RowDecoder[EmptyTuple] with
def decode(a: Row): EmptyTuple = EmptyTuple
given FieldDecoder[Int] with
def decodeField(x: String): Int = x.toInt
given FieldDecoder[Boolean] with
def decodeField(x: String): Boolean = x.toBoolean
given FieldDecoder[String] with
def decodeField(x: String): String = x
given FieldDecoder[BigDecimal] with
def decodeField(x: String): BigDecimal = BigDecimal(x)
given FieldDecoder[Double] with
def decodeField(x: String): Double = x.toDouble
given decodeLine[H: FieldDecoder, T <: Tuple : RowDecoder]: RowDecoder[H *: T] with
def decode(row: Row): H *: T = {
val line = if (row.nonEmpty) row else List("")
summon[FieldDecoder[H]].decodeField(line.head)
*:
summon[RowDecoder[T]].decode(line.tail)
}
def main(args: Array[String]): Unit = {
case class Foo(i: Int, b: Boolean, s: String)
import Decoder.*
val foo = csvToProduct[Foo](List("42", "true", "Hello"))
//val sp500 = csvToProduct[Sp500Divdend](List("1900.01", "6.10", "0.22"))
println(foo)
}
}