From 8cf85b35c816504b4586ee5c93b590b2e170d1c4 Mon Sep 17 00:00:00 2001 From: Alejandro Serrano Date: Fri, 29 Jul 2022 10:24:50 +0200 Subject: [PATCH 1/2] Generalized copy for optics --- .../optics/arrow-optics/api/arrow-optics.api | 14 ++++ .../commonMain/kotlin/arrow/optics/Copy.kt | 71 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Copy.kt diff --git a/arrow-libs/optics/arrow-optics/api/arrow-optics.api b/arrow-libs/optics/arrow-optics/api/arrow-optics.api index d8ef229e8fe..aa6ac451a63 100644 --- a/arrow-libs/optics/arrow-optics/api/arrow-optics.api +++ b/arrow-libs/optics/arrow-optics/api/arrow-optics.api @@ -1,3 +1,17 @@ +public abstract interface class arrow/optics/Copy { + public abstract fun inside (Larrow/optics/PTraversal;Lkotlin/jvm/functions/Function1;)V + public abstract fun set (Larrow/optics/PSetter;Ljava/lang/Object;)V + public abstract fun transform (Larrow/optics/PTraversal;Lkotlin/jvm/functions/Function1;)V +} + +public final class arrow/optics/Copy$DefaultImpls { + public static fun inside (Larrow/optics/Copy;Larrow/optics/PTraversal;Lkotlin/jvm/functions/Function1;)V +} + +public final class arrow/optics/CopyKt { + public static final fun copy (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; +} + public abstract interface class arrow/optics/Fold { public static final field Companion Larrow/optics/Fold$Companion; public abstract fun all (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Z diff --git a/arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Copy.kt b/arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Copy.kt new file mode 100644 index 00000000000..5f7ed8c5041 --- /dev/null +++ b/arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Copy.kt @@ -0,0 +1,71 @@ +package arrow.optics + +public interface Copy { + /** + * Changes the value of the element(s) pointed by the [Setter]. + */ + public infix fun Setter.set(b: B) + + /** + * Transforms the value of the element(s) pointed by the [Traversal]. + */ + public infix fun Traversal.transform(f: (B) -> B) + + /** + * Declares a block in which all optics are nested within + * the given [field]. Instead of: + * + * ``` + * x.copy { + * X.a.this set "A" + * X.a.that set "B" + * } + * ``` + * + * you can write: + * + * ``` + * x.copy { + * inside(X.a) { + * A.this set "A" + * A.that set "B" + * } + * } + * ``` + */ + public fun inside(field: Traversal, f: Copy.() -> Unit): Unit = + field.transform { it.copy(f) } +} + +// mutable builder of copies +private class CopyImpl(var current: A): Copy { + override fun Setter.set(b: B) { + current = this.set(current, b) + } + override fun Traversal.transform(f: (B) -> B) { + current = this.modify(current, f) + } +} + +/** + * Small DSL which parallel Kotlin's built-in `copy`, + * but using optics instead of field names. See [Copy] + * for the operations allowed inside the block. + * + * This allows declaring changes on nested elements, + * preventing the "nested `copy` problem". Instead of: + * + * ``` + * person.copy(address = person.address.copy(city = "Madrid")) + * ``` + * + * you can write: + * + * ``` + * person.copy { + * Person.address.city set "Madrid" + * } + * ``` + */ +public fun A.copy(f: Copy.() -> Unit): A = + CopyImpl(this).also { f(it) }.run { current } From a1e9263f9aeb6740b06a8b7ea37a7189c6762cc8 Mon Sep 17 00:00:00 2001 From: Alejandro Serrano Date: Tue, 2 Aug 2022 16:38:26 +0200 Subject: [PATCH 2/2] Update arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Copy.kt Co-authored-by: Simon Vergauwen --- .../arrow-optics/src/commonMain/kotlin/arrow/optics/Copy.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Copy.kt b/arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Copy.kt index 5f7ed8c5041..5b231df3623 100644 --- a/arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Copy.kt +++ b/arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Copy.kt @@ -68,4 +68,4 @@ private class CopyImpl(var current: A): Copy { * ``` */ public fun A.copy(f: Copy.() -> Unit): A = - CopyImpl(this).also { f(it) }.run { current } + CopyImpl(this).also(f).current