Skip to content

Commit

Permalink
Fix traverse mutability
Browse files Browse the repository at this point in the history
  • Loading branch information
joroKr21 committed Sep 25, 2021
1 parent c6fdb82 commit a44fa6e
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -160,18 +160,25 @@ private[shapeless3] final class ErasedProductInstancesN[K, FT](val mirror: Mirro

final def erasedTraverse(x0: Any)(map: (Any, Any) => Any)(pure: Any => Any)(ap: (Any, Any) => Any)(f: (Any, Any) => Any) = {
val n = is.length

def prepend(xs: List[Any])(x: Any) = x :: xs
def fromList(xs: List[Any]) =
val arr = new Array[Any](n)
@tailrec def toProduct(xs: List[Any], i: Int): ArrayProduct = xs match
case x :: xs => arr(i) = x; toProduct(xs, i - 1)
case Nil => new ArrayProduct(arr)
mirror.fromProduct(toProduct(xs, n - 1))

if (n == 0) pure(x0)
else {
val x = toProduct(x0)
val arr = new Array[Any](n)
var acc = pure(())
var acc = pure(Nil)
var i = 0
while(i < n) {
val j = i // avoid capturing `i` when the applicative is lazy
acc = ap(map(acc, (_: Unit) => arr.update(j, _)), f(is(j), x.productElement(j)))
acc = ap(map(acc, prepend), f(is(i), x.productElement(i)))
i = i+1
}
map(acc, (_: Unit) => mirror.fromProduct(new ArrayProduct(arr)))
map(acc, fromList)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ object adts {
sealed trait CList[+A] derives Eq, Show, Read, Functor, EmptyK, Traverse, Foldable
case class CCons[+A](hd: A, tl: CList[A]) extends CList[A]
case object CNil extends CList[Nothing]
object CList {
def apply[A](x: A, xs: A*): CCons[A] =
CCons(x, xs.foldRight[CList[A]](CNil)(CCons.apply))
}

case class Order[F[_]](
item: F[String],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,20 +225,21 @@ class DerivationTests {
assert(v3.traverse(Nn)((x: Int) => List(x + 1)) == List(Nn))

val v4 = Traverse[Const[CNil.type]]
assert(v4.traverse(CNil)(Option(_)) == Some(CNil))
assert(v4.traverse(CNil)(Option.apply) == Some(CNil))
val v5 = Traverse[CCons]
assert(v5.traverse(CCons("foo", CCons("bar", CNil)))(Option(_)) == Some(CCons("foo", CCons("bar", CNil))))
assert(v5.traverse(CList("foo", "bar"))(Option.apply) == Some(CList("foo", "bar")))
val v6 = Traverse[CList]
assert(v6.traverse(CCons("foo", CCons("bar", CNil)))(Option(_)) == Some(CCons("foo", CCons("bar", CNil))))
assert(v6.traverse(CNil)(Option(_)) == Some(CNil))
assert(v6.traverse(CCons("foo", CCons("bar", CNil)))(() => _).apply() == CCons("foo", CCons("bar", CNil)))
assert(v6.traverse(CList("foo", "bar"))(Option.apply) == Some(CList("foo", "bar")))
assert(v6.traverse(CNil)(Option.apply) == Some(CNil))
assert(v6.traverse(CList("foo", "bar"))(() => _).apply() == CList("foo", "bar"))
assert(v6.traverse(CList(1, 2))(x => List(x, x + 1)) == List(CList(1, 2), CList(1, 3), CList(2, 2), CList(2, 3)))

val v7 = Traverse[OptE]
assert(v7.traverse(SmE(1))((x: Int) => List(x + 1)) == List(SmE(2)))
assert(v7.traverse(NnE)((x: Int) => List(x + 1)) == List(NnE))

val v8 = Traverse[Phantom]
assert(v8.traverse(Phantom())(Option(_)) == Some(Phantom()))
assert(v8.traverse(Phantom())(Option.apply) == Some(Phantom()))
}


Expand Down

0 comments on commit a44fa6e

Please sign in to comment.