1

我是函数式编程和 Kotlin 的绝对初学者,试图解决我从问自己的问题中创建的练习;我目前的问题是“如何使用端口和适配器架构将函数式编程应用到现实世界的应用程序中?”

目前正在学习Eithermonad,我有以下函数,其中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,根据我的理解,这意味着一种单子风格。

我的问题是:

  • 如果我的理解是正确的,我怎样才能把它变成应用风格?

  • 在上面的实现中是否有任何严重的错误?(即成语,误用柯里化)

4

1 回答 1

2

我相信我明白出了什么问题。

在用适当的函数式编程语言编写的 FP 示例中,应用样式的编写方式与someFunction map a apply bKotlin 类似,因为我们正在处理对象的方法,所以在从左到右阅读时以保留顺序编写,但在术语中以正确的顺序编写论据评估。这让我非常困惑。

private fun requestCountBetweenQueryC(me: RequestModel): Perhaps<CountBetweenQuery> {
    val newCountBetweenQueryCurried: (begin: LocalDate) -> (end: LocalDate) -> CountBetweenQuery =
            ::CountBetweenQuery.curried()

    val a = perhapsExtractLocalDate(me, "begin")
    val b = perhapsExtractLocalDate(me, "end")

    return b.apply(a.map(newCountBetweenQueryCurried))
}

如果我的理解是正确的,这也称为lift2函数。

于 2017-12-10T15:09:12.033 回答