Skip to content

Instantly share code, notes, and snippets.

@kubukoz
Created December 4, 2022 02:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kubukoz/dcbf87a386db172fd64e26659b55f33f to your computer and use it in GitHub Desktop.
Save kubukoz/dcbf87a386db172fd64e26659b55f33f to your computer and use it in GitHub Desktop.
Scala's type system solution of Advent of Code 2022 day 1 part 1
import scala.compiletime.ops.int.{>, +, *}
import scala.compiletime.ops.string.{Length, Substring, CharAt}
import Tuple.Map
object StringOps {
type IndexOfRec[Haystack <: String, Needle <: String, I <: Int] =
((I + Length[Needle]) > Length[Haystack]) match {
case true => -1
case false =>
Substring[Haystack, I, I + Length[Needle]] match {
case Needle => I
case _ => IndexOfRec[Haystack, Needle, I + 1]
}
}
type IndexOf[Haystack <: String, Needle <: String] =
IndexOfRec[Haystack, Needle, 0]
type SplitRec[S <: String, Delim <: String, Memory <: Tuple] =
IndexOf[S, Delim] match {
case -1 => TupleOps.Reverse[S *: Memory]
case Int =>
SplitRec[
Substring[S, IndexOf[S, Delim] + Length[Delim], Length[S]],
Delim,
Substring[S, 0, IndexOf[S, Delim]] *: Memory
]
}
type Split[S <: String, Delim <: String] =
SplitRec[S, Delim, EmptyTuple]
type ParseDigit[Ch <: Char] = Ch match {
case '0' => 0
case '1' => 1
case '2' => 2
case '3' => 3
case '4' => 4
case '5' => 5
case '6' => 6
case '7' => 7
case '8' => 8
case '9' => 9
}
type ToTuple[S <: String] = S match {
case "" => EmptyTuple
case _ => (S CharAt 0) *: ToTuple[Substring[S, 1, Length[S]]]
}
type ParseInt[S <: String] = ToTuple[S] match {
case Tuple =>
Tuple.Fold[
TupleOps.Reverse[ToTuple[S] Map ParseDigit],
0,
[A, B] =>> (A, B) match {
case (Int, Int) => A + (10 * B)
}
]
}
}
object TupleOps {
type Reverse[T <: Tuple] = T match {
case EmptyTuple => EmptyTuple
case h *: t => Tuple.Concat[Reverse[t], h *: EmptyTuple]
}
type Reduce[T <: NonEmptyTuple, F[_, _]] =
Tuple.Fold[Tuple.Tail[T], Tuple.Head[T], F]
type NonEmptyMap[T <: NonEmptyTuple, F[_]] =
F[Tuple.Head[T]] *: Tuple.Map[Tuple.Tail[T], F]
type Sum[T <: Tuple] = Tuple.Fold[
T,
0,
[A, B] =>> (A, B) match {
case (Int, Int) => A + B
}
]
}
object AdventOps {
import TupleOps._
type Groups[S <: String] = StringOps.Split[S, "\n\n"]
type Elves[Groups <: Tuple] =
Groups Map
([Group] =>> Group match {
case String =>
StringOps.Split[Group, "\n"] Map StringOps.ParseInt
})
type TopElf[Elves <: NonEmptyTuple] =
Reduce[
Elves NonEmptyMap
([Elf] =>> Elf match {
case Tuple => TupleOps.Sum[Elf]
}),
[A, B] =>> (A, B) match {
case (Int, Int) => A Max B
}
]
}
// final val text = readFileNow("/Users/kubukoz/projects/demos/input.txt")
final val text = """1000
2000
3000
4000
5000
6000
7000
8000
9000
10000"""
type S = text.type
import AdventOps._
// the inferred type of this value is the result of the task
final val result = scala.compiletime.constValue[TopElf[Elves[Groups[S]]]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment