-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add 🌟 Scala 3 🌟 support #5
Changes from 6 commits
e0772a1
509a353
744d61b
a74e291
ddebf65
45ca115
df13c74
6760268
d37b58a
3883c12
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package zipper | ||
|
||
import contrib.shapeless3.{Replacer, Selector} | ||
import shapeless3.deriving.K0 | ||
import shapeless3.deriving.K0.* | ||
|
||
import scala.collection.Factory | ||
|
||
private[zipper] trait ForImpl { | ||
given unzipListBased[A, L <: Tuple](using | ||
generic: K0.ProductGeneric[A] { type MirroredElemTypes = L }, | ||
selector: Selector[L, List[A]], | ||
replacer: Replacer.Aux[L, List[A], List[A], (List[A], L)] | ||
): Unzip[A] with { | ||
def unzip(node: A): List[A] = selector(generic.toRepr(node)) | ||
def zip(node: A, children: List[A]): A = { | ||
val repr = replacer(generic.toRepr(node), children) | ||
generic.fromRepr(repr._2) | ||
} | ||
} | ||
|
||
class For[A, Coll[X] <: Seq[X]]: | ||
/** Derive an instance of `Unzip[A]` */ | ||
inline given derive[L <: Tuple](using | ||
generic: K0.ProductGeneric[A] { type MirroredElemTypes = L }, | ||
selector: Selector[L, Coll[A]], | ||
replacer: Replacer.Aux[L, Coll[A], Coll[A], (Coll[A], L)], | ||
factory: Factory[A, Coll[A]] | ||
): Unzip[A] with { | ||
def unzip(node: A): List[A] = selector(generic.toRepr(node)).toList | ||
def zip(node: A, children: List[A]): A = { | ||
val repr = replacer(generic.toRepr(node), children.to(factory)) | ||
generic.fromRepr(repr._2) | ||
} | ||
} | ||
|
||
object For: | ||
/** | ||
* @tparam A The type of the tree-like data structure | ||
* @tparam Coll The type of the collection used for recursion (e.g. Vector) | ||
*/ | ||
def apply[A, Coll[X] <: Seq[X]]: For[A, Coll] = new For[A, Coll] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package contrib.shapeless3 | ||
|
||
trait Replacer[L <: Tuple, U, V]: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a matter of fact, the full-fledged migration of shapeless-2 to Scala 3 is currently in progress (milessabin/shapeless#1200 — it's such a monumental work, I'm just shocked). So we need to migrate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But yeah, I think some clarifications should be put into the comments. I'll go over it tomorrow. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if the native derivation capabilities of Scala 3 are sufficiently powerful to eschew shapeless altogether? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can imagine a solution powered by a Macro. However, it should also work with Scala 2 Macros. But I don't know if Scala 3 has anything out of pocket for replacing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I meant this: https://docs.scala-lang.org/scala3/reference/contextual/derivation.html#how-to-write-a-type-class-derived-method-using-low-level-mechanisms-1. But after a closer look it does not seem powerful enough (yet?). And I don’t like that using it seems to require writing a lot of |
||
type Out <: Tuple | ||
def apply(t: L, v: V): Out | ||
|
||
object Replacer: | ||
def apply[L <: Tuple, U, V](using r: Replacer[L, U, V]): Aux[L, U, V, r.Out] = r | ||
|
||
type Aux[L <: Tuple, U, V, Out0] = Replacer[L, U, V] { type Out = Out0 } | ||
|
||
given tupleReplacer1[T <: Tuple, U, V]: Aux[U *: T, U, V, (U, V *: T)] = | ||
new Replacer[U *: T, U, V] { | ||
type Out = (U, V *: T) | ||
|
||
def apply(l: U *: T, v: V): Out = (l.head, v *: l.tail) | ||
} | ||
|
||
given tupleReplacer2[H, T <: Tuple, U, V, OutT <: Tuple](using | ||
ut: Aux[T, U, V, (U, OutT)]): Aux[H *: T, U, V, (U, H *: OutT)] = | ||
new Replacer[H *: T, U, V] { | ||
type Out = (U, H *: OutT) | ||
|
||
def apply(l: H *: T, v: V): Out = { | ||
val (u, outT) = ut(l.tail, v) | ||
(u, l.head *: outT) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package contrib.shapeless3 | ||
|
||
trait Selector[L <: Tuple, U]: | ||
def apply(t: L): U | ||
|
||
object Selector: | ||
given[H, T <: Tuple]: Selector[H *: T, H] with { | ||
def apply(t: H *: T): H = t.head | ||
} | ||
|
||
given[H, T <: Tuple, U] (using s: Selector[T, U]): Selector[H *: T, U] with { | ||
def apply(t: H *: T): U = s (t.tail) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,3 @@ | ||
package zipper | ||
|
||
import shapeless.{HList, Generic} | ||
import shapeless.ops.hlist.{Selector, Replacer} | ||
|
||
private[zipper] trait GenericUnzipInstances extends ForImpl { | ||
implicit def `Unzip List-based`[A, L <: HList]( | ||
implicit generic: Generic.Aux[A, L], | ||
select: Selector[L, List[A]], | ||
replace: Replacer.Aux[L, List[A], List[A], (List[A], L)] | ||
): Unzip[A] = new Unzip[A] { | ||
def unzip(node: A): List[A] = select(generic.to(node)) | ||
def zip(node: A, children: List[A]): A = generic.from(replace(generic.to(node), children)._2) | ||
} | ||
} | ||
private[zipper] trait GenericUnzipInstances extends ForImpl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it's the most controversial thing. The recent version of Scala 3 is
3.4.2
. But since Scala 3 doesn't keep forward compatibility between minor versions, we should barely stick with it. Also, Scala 3.3 is an LTS — https://virtuslab.com/blog/technology/scala-3-roadmap-for-2024/#at-least-one-lts-patch-for-every-two-next-patch-releases. Last but not least, many libraries I used to contribute have decided to stick with 3.3. I propose to act similarly.