简体   繁体   中英

Can't create sequence of Ints in Kotlin through succesor function. Says “Type Inference failed”

I'm trying to create a stream/sequence of natural numbers from the number 0 and a successor function S, through the generateSequence function.

Here's what I've got:

package core

fun sequenceOfNumbers(): Sequence<Int> {
    return generateSequence(0){x -> S(x)}
}

class S: (Int) -> Int {
    override operator fun invoke(x: Int) = x + 1
}

fun main(args: Array<String>) {
    println(sequenceOfNumbers().take(10).toList())
}

I am aware this may not seem like the best way to solve this, as there already are increment operators, and that there already is a shortcut for generating the first n natural numbers, but I want S to be a class or at least object for some other reasons later.

When I compile it I get the following messages:

Type inference failed: Cannot infer type parameter T in 

fun <T : Any> generateSequence(
   seed: T?,
   nextFunction: (T) → T?
) : Sequence<T>

None of the following substitutions    
(S?, (S) → S?)    
(Int?, (Int) → Int?)
(Any?, (Any) → Any?)
can be applied to    
(Int, (Int) → S)

and

Too many arguments for public constructor S() defined in core.

Other things I've tried is rewriting S as

class S: Function<Int> {
    operator fun invoke(x: Int) = x + 1
}

or changing the generateSequence function to

fun sequenceOfNumbers(start: Int): Sequence<Int> {
    return generateSequence(seed = start, nextFunction = (x: Int) -> S(x))
}

which didn't work either. Last function got the compile messages "Unexpected type specification" and "Unexpected tokens (use ';' to separate expressions on the same line".

Any way to solve this so that the println function prints out the first 10 natural numbers, and still uses the successor class?

The problem in your code that your actually calling the constructor of S , rather than invoke() . You should change to following to make it work:

return generateSequence(0){x -> S()(x)}

Of course it will be better, if you store S in local variable and reuse it in sequence generator:

fun sequenceOfNumbers(): Sequence<Int> {
    val s = S()
    return generateSequence(0){x -> s(x)} //generateSequence(0, s::invoke)
}

Or even better to make S singleton:

fun sequenceOfNumbers(): Sequence<Int> {
    return generateSequence(0) { x -> S(x)} //generateSequence(0, S::invoke)
}

object S: (Int) -> Int {
    override operator fun invoke(x: Int) = x + 1
}

So in the end your code will look like in your example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM