3

We have two entities: one our hash is a number, it is represented by a Nat, and another is the sized vector. We want that our hash number belong to one of the elements of the sized vector. Normally we would compute a desired index with mod nat % size.

class SizedVector[A, L <: Nat: ToInt](s: Sized[Vector[A], L]) {
  def shard[Hash <: Nat: ToInt, Index <: Nat](
    hash: Hash32[Hash]
  )(
    implicit
    mod: Mod.Aux[Hash, L, Index],
    index: ToInt[Index]
  ): A = s.at[Index]
}

How can we prove that the result of the mod Index at the type-level is within the length of the sized vector? Currently the compiler would tell you

could not find implicit value for parameter diff: shapeless.ops.nat.Diff[L,shapeless.Succ[Index]]
): A = s.at[Index]

Assuming it has no idea what is the difference between the vector length and the computed index.

Is it possible to ensure the safe access and make it total this way?

Scastie: https://scastie.scala-lang.org/kubum/AmbBX3rwQfyXjqRrglYyIg/5

kubum
  • 469
  • 2
  • 13

1 Answers1

3

If compiler lacks some implicit you add it as a parameter. Try

def shard[Hash <: Nat: ToInt, Index <: Nat](
  hash: Hash32[Hash]
)(
  implicit
  mod: Mod.Aux[Hash, L, Index],
  index: ToInt[Index],
  diff: Diff[L, Succ[Index]]
): A = s.at[Index]
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • Ah, thank you, Dmytro, fantastic! I am not sure why I only tried to do it with `Aux` before. This works well, I wonder what are the steps when you abstract it away, https://scastie.scala-lang.org/kubum/AmbBX3rwQfyXjqRrglYyIg/10? – kubum Apr 20 '19 at 10:08
  • 1
    With `Aux` this should also work: `def shard[Hash <: Nat: ToInt, Index <: Nat, Out <: Nat]( hash: Hash32[Hash] )( implicit mod: Mod.Aux[Hash, L, Index], index: ToInt[Index], diff: Diff.Aux[L, Succ[Index], Out] ): A = s.at[Index]` – Dmytro Mitin Apr 20 '19 at 11:08
  • 1
    @kubum Once again, if compiler lacks some implicits you add them as parameters. `class Container[TotalBuckets <: Nat: ToInt, Index <: Nat](implicit mod: Mod.Aux[_13, TotalBuckets, Index], diff: Diff[TotalBuckets, Succ[Index]], index: ToInt[Index])...` `new Container[_5, _3]` – Dmytro Mitin Apr 20 '19 at 11:44
  • 1
    @kubum If you want to hide second type parameter `_3` you can try "partial application" trick or creating custom type class https://stackoverflow.com/a/55236130/5249621 https://stackoverflow.com/a/55637495/5249621 – Dmytro Mitin Apr 20 '19 at 11:54
  • I see your idea, @dmytro-mitin. Thank you. One last moment, does it mean the `Nats` cannot come from the inside of the `Container`? Now it is a total function, it accepts any nats and gives an element back. How do people encode it without hardcoding the index into the constructor? *UPD:* I see you commented! Thanks! – kubum Apr 20 '19 at 11:57