Skip to content

Instantly share code, notes, and snippets.

@javiergamarra
Created September 20, 2017 06:30
Show Gist options
  • Save javiergamarra/1f5cc859ce70eff7d86be22548f17697 to your computer and use it in GitHub Desktop.
Save javiergamarra/1f5cc859ce70eff7d86be22548f17697 to your computer and use it in GitHub Desktop.
Playing with kotlin and functional concepts
import java.util.function.Consumer
data class User(val name: String, val password: String, val age: Int, var organizationId: Int?)
fun addUser(name: String, password: String, age: Int): Result<User, UserError> {
val user = User(name, password, age, 0)
val userValidator: Validator = compose(compose(validateAge, nameValidator), validatePassword)
return user.let(::addUserToDB).let(::Success)
}
fun compose(one: Validator, two: Validator): Validator = { t: User ->
val result = one(t)
when (result) {
is Success -> two(t)
else -> result
}
}
fun addUserToDB(user: User): User = user
val nameValidator: Validator = { user: User ->
user.takeIf { it.name.isBlank().not() }
?.let { Success<User, UserError>(it) }
?: Failure(UserError.BLANK_NAME)
}
val validatePassword: Validator = { user: User ->
user.takeIf { user.password.length >= 10 }
?.let { Success<User, UserError>(it) }
?: Failure(UserError.PASSWORD_TOO_LONG)
}
val validateAge: Validator = { user: User ->
user.takeIf { it.age < 18 }
?.let { Success<User, UserError>(it) }
?: Failure(UserError.ADULT)
}
fun main(args: Array<String>) {
val addUser = addUser("Víctor", "is tonto", 25)
val map = addUser
.map({ it })
.flatMap({ it: User -> Organization() })
println(map)
// addUser.map { it.name }.ifSuccess<String, UserError>(Consumer { println(it) })
// addUser.map { it.name }.ifFailure(::println)
}
fun toOrganization(id: Int): Result<Organization, Error> {
return Success(Organization())
}
class DBError {
}
class Organization {
}
typealias Validator = (U: User) -> Result<User, UserError>
sealed class Result<S, E>
data class Success<S, E>(val value: S) : Result<S, E>()
data class Failure<S, E>(val error: E) : Result<S, E>()
fun <S, E, R> Result<S, E>.map(transform: (S) -> R): Result<R, E> = when (this) {
is Success -> Success(transform(this.value))
is Failure -> Failure(this.error)
}
fun <U, R> Result<U, UserError>.flatMap(transform: (U) -> R): Result<R, UserError> = when (this) {
is Success -> this.map(transform)
is Failure -> Failure(UserError.BLANK_NAME)
}
fun <S, E> Result<S, E>.ifSuccess(operation: Consumer<S>) {
if (this is Success) operation.accept(this.value)
}
fun <S, E> Result<S, E>.ifFailure(operation: (err: E) -> (Unit)) {
if (this is Failure) operation(this.error)
}
enum class UserError {
BLANK_NAME, PASSWORD_TOO_LONG, ADULT
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment