我是函数式编程和 Kotlin 的绝对初学者,试图解决我从问自己的问题中创建的练习;我目前的问题是“如何使用端口和适配器架构将函数式编程应用到现实世界的应用程序中?”
目前正在学习Either
monad,我有以下函数,其中Perhaps<T>
只是重命名Either<Err, T>
用于异常处理。
此函数接受RequestModel
包含任意 HTTP 参数的 a,并且可能Perhaps
返回一个CountBetweenQuery
仅包含两个 的数据类LocalDate
。
private fun requestCountBetweenQueryA(model: RequestModel): Perhaps<CountBetweenQuery> {
return try {
Perhaps.ret(CountBetweenQuery(extractLocalDateOrThrow(model, "begin"), extractLocalDateOrThrow(model, "end")))
} catch (e: UnsupportedTemporalTypeException) {
Perhaps.Fail(Err.DATE_FORMAT_IS_INVALID)
} catch (e: DateTimeException) {
Perhaps.Fail(Err.DATE_FORMAT_IS_INVALID)
}
}
private fun extractLocalDateOrThrow(it: RequestModel, param: String): LocalDate =
LocalDate.from(DateTimeFormatter.ISO_DATE.parse(it.parameters.first { it.key == param }.value))
在 OO 语言中,我将对其进行重构,以便在通用异常处理程序中以以下方式处理异常,或在以上(其中重复的代码被提取到单个方法中)更高的方式处理异常。自然地,我想把我的extractLocalDateOrThrow
变成perhapsExtractLocalDate
我的练习的一部分:
private fun perhapsExtractLocalDate(it: RequestModel, param: String): Perhaps<LocalDate> = try {
Perhaps.ret(LocalDate.from(DateTimeFormatter.ISO_DATE.parse(it.parameters.first { it.key == param }.value)))
} catch (e: UnsupportedTemporalTypeException) {
Perhaps.Fail(Err.DATE_FORMAT_IS_INVALID)
} catch (e: DateTimeException) {
Perhaps.Fail(Err.DATE_FORMAT_IS_INVALID)
}
我已经挣扎了一个小时,试图弄清楚如何CountBetweenQuery
在保留延续传递风格的同时调用构造函数。
这就是我想出的:
private fun requestCountBetweenQueryB(me: RequestModel): Perhaps<CountBetweenQuery> {
val newCountBetweenQueryCurried: (begin: LocalDate) -> (end: LocalDate) -> CountBetweenQuery =
::CountBetweenQuery.curried()
return Perhaps.ret(newCountBetweenQueryCurried)
.bind { function -> perhapsExtractLocalDate(me, "begin").map(function) }
.bind { function -> perhapsExtractLocalDate(me, "end").map(function) }
}
起初我希望使用return
并且apply
因为这两个方法调用perhapsExtractLocalDate
是独立的,因此我会使用应用程序样式。相反,我无法弄清楚如何避免使用bind
,根据我的理解,这意味着一种单子风格。
我的问题是:
如果我的理解是正确的,我怎样才能把它变成应用风格?
在上面的实现中是否有任何严重的错误?(即成语,误用柯里化)