Skip to content

Instantly share code, notes, and snippets.

@nomisRev
Created February 6, 2018 08:15
Show Gist options
  • Save nomisRev/8017570f2adbb744e9eaed5d21b0131a to your computer and use it in GitHub Desktop.
Save nomisRev/8017570f2adbb744e9eaed5d21b0131a to your computer and use it in GitHub Desktop.
Added traversal
import arrow.core.Option
import arrow.core.identity
import arrow.data.ListKW
import arrow.data.ListKWHK
import arrow.data.ListKWKind
import arrow.data.ev
import arrow.data.k
import arrow.lenses
interface BoundSetter<S, A> {
fun modify(f: (A) -> A): S
}
fun <T, S, A> BoundSetter<T, S>.setter(setter: Setter<S, A>): BoundSetter<T, A> {
return object : BoundSetter<T, A> {
override fun modify(f: (A) -> A): T = [email protected] { setter.modify(it, f) }
}
}
fun <T> T.setter() = object : BoundSetter<T, T> {
override fun modify(f: (T) -> T) = f(this@setter)
}
fun <S, A> BoundSetter<S, A>.set(a: A) = modify { a }
//primitives
val <T, A> BoundSetter<T, A?>.nullable get() = setter(nullableOptional<A>().asSetter())
val <T, A> BoundSetter<T, Option<A>>.some get() = setter(somePrism<A>().asSetter())
val <T, A> BoundSetter<T, ListKW<A>>.each: BoundSetter<T, A>
get() =setter(listKWKindToListKW<A>().reverse() compose Traversal.fromTraversable<ListKWHK, A, A>().asSetter())
//usage
@lenses
data class Street(val number: Int, val name: String)
@lenses
data class Address(val city: String, val street: Street)
@lenses
data class Company(val name: String, val address: Address)
@lenses
data class Employee(val name: String, val company: Company?)
@lenses
data class CompanyEmployees(val employees: ListKW<Employee>)
//Generated
val <T> BoundSetter<T, Employee>.name @JvmName("employeeName") get() = setter(employeeName().asSetter())
val <T> BoundSetter<T, Employee>.company get() = setter(employeeCompany().asSetter())
val <T> BoundSetter<T, Company>.name @JvmName("companyName") get() = setter(companyName().asSetter())
val <T> BoundSetter<T, Company>.address get() = setter(companyAddress().asSetter())
val <T> BoundSetter<T, Address>.city get() = setter(addressCity().asSetter())
val <T> BoundSetter<T, Address>.street get() = setter(addressStreet().asSetter())
val <T> BoundSetter<T, Street>.number get() = setter(streetNumber().asSetter())
val <T> BoundSetter<T, Street>.name get() = setter(streetName().asSetter())
val <T> BoundSetter<T, CompanyEmployees>.employees get() = setter(companyEmployeesEmployees().asSetter())
val john = Employee("John Doe", Company("Kategory", Address("Functional city", Street(42, "lambda street"))))
val jane = Employee("Jane Doe", Company("Kategory", Address("Functional city", Street(42, "lambda street"))))
val employees = CompanyEmployees(listOf(john, jane).k())
fun main(args: Array<String>) {
john.setter().company.nullable.address.street.name.modify(String::capitalize).let(::println)
employees.setter().employees.each.company.nullable.address.street.name.modify(String::toUpperCase).let(::println)
}
//Missing from std
/**
* [Iso] that defines equality between [ListKWKind] and [LisKW]
*/
fun <A> listKWKindToListKW(): Iso<ListKWKind<A>, ListKW<A>> = Iso(
get = { it.ev() },
reverseGet = ::identity
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment