2017-04-03 99 views
2

我试着写了Kleisli幂在科特林:Kleisli幂在科特林

fun <A,B> kleisli(n: Int, f: (A) -> B): (A) -> B = if (n == 1) f else { it -> f(kleisli(n-1, ::f)(it)) } 

,只是组成fn倍(请不要把n = 0在我的代码)。

Kotlin(1.0.6)抱怨error: unsupported [References to variables aren't supported yet]指向::f

我做错了什么?

回答

3

使用的只是f代替::f,它已经是一个功能值(即一个参数,变量或功能型的属性),所以你不需要做它的一个调用的参考。

... else { it -> f(kleisli(n - 1, f)(it)) } 

此外,您的例子似乎有一个类型不匹配:kleisli(n - 1, f)返回(A) -> B类型,这就是所谓的A类型的it,返回B类型的结果的功能。然后结果传递到f,但f只能收到A。为了解决这个问题,你可以删除类型参数B只有A离开:

fun <A> kleisli(n: Int, f: (A) -> A) : (A) -> A = 
    if (n == 1) 
     f else 
     { it -> f(kleisli(n - 1, f)(it)) } 

(runnable demo of this code)


此外,该代码演示的意图非常清楚的实用的风格,但它可能会导致成冗余对象分配和不希望的调用堆栈增长。但是,它可以被重写为命令式,这将更有效地工作:

fun <T> iterativeKleisli(n: Int, f: (T) -> T) : (T) -> T = { x -> 
    var result = x 
    for (i in 1..n) 
     result = f(result) 
    result 
} 
+0

谢谢!这样可行。似乎我需要更多地了解Kotlin。也很抱歉错过了构成f,f需要是 - > a。 –

+0

只是为了好奇,那个错误是什么意思(引用变量还不支持)? –

+1

@Koyomi-chan,如果支持,':: f'将意味着对函数参数'f'的可调用引用 - 一个包含有关该参数的一些信息并提供获取其值的方法的对象。已经有[函数引用](http://kotlinlang.org/docs/reference/reflection.html#function-references)和[绑定可调用引用](https://gist.github.com/udalov/f86fbea722a53730f3f5777d871ab8ba) Kotlin,都使用'::'。但现在不支持局部变量和参数引用。 – hotkey