Is it possible to have an inline iterator, which accepts another inline iterator as a parameter? My goal is to make a simple pipeline-like processing and get it unrolled into serial C code. An example which I can't get to work:
iterator test2(it: iterator(): int {.inline.}): int =
for i in it():
yield i*2
iterator test1(): int =
yield 10
yield 20
yield 30
for i in test2(test1()):
echo j
With the error:
test.nim(2, 14) Error: type mismatch: got (int) but expected one of:
iterator items[IX, T](a: array[IX, T]): T
iterator items[](E: typedesc[enum]): E:type
iterator items(a: string): char
iterator items[T](s: Slice[T]): T
iterator items[T](a: openArray[T]): T
iterator items[T](a: seq[T]): T
iterator items[T](a: set[T]): T
iterator items(a: cstring): char
> Process terminated with exit code 256
you have 2 options (at least)
define your iterator as {.closure.}
use templates to wrap the iterator and, which is a little ugly but works:
template runIterator(it, exec: untyped): typed =
block:
it(myIterator)
for i in myIterator() :
exec(i*2)
template defineTest1(name: untyped): typed =
iterator `name`(): int {.inline.} =
yield 10
yield 20
yield 30
template defineTest2(name: untyped): typed =
iterator `name`(): int {.inline.} =
yield 5
yield 10
yield 15
template exec(i: int): typed = echo i
runIterator(defineTest1, exec)
runIterator(defineTest2, exec)
edit:
the idea is to use a template instead of an inline iterator and to inject the code - so there is no second iterator but a template.
maybe this makes it clearer:
template test2(it, yielder, exec: untyped): typed =
for i in it() :
let `yielder` {.inject.} = 2 * i
exec
iterator test1(): int {.inline.} =
yield 10
yield 20
yield 30
iterator test1b(): int {.inline.} =
yield 5
yield 10
yield 15
test2(test1, i):
echo i
test2(test1b, i):
echo i
Related
I would like to define overloads of map and min/max (as originally defined in sequtils) that works for tables.keys. Specifically, I want to be able to write something like the following:
import sequtils, sugar, tables
# A mapping from coordinates (x, y) to values.
var locations = initTable[(int, int), int]()
# Put in some random values.
locations[(1, 2)] = 1
locations[(2, 1)] = 2
locations[(-2, 5)] = 3
# Get the minimum X coordinate.
let minX = locations.keys.map(xy => xy[0]).min
echo minX
Now this fails with:
/usercode/in.nim(12, 24) Error: type mismatch: got <iterable[lent (int, int)], proc (xy: GenericParam): untyped>
but expected one of:
proc map[T, S](s: openArray[T]; op: proc (x: T): S {.closure.}): seq[S]
first type mismatch at position: 1
required type for s: openArray[T]
but expression 'keys(locations)' is of type: iterable[lent (int, int)]
expression: map(keys(locations), proc (xy: auto): auto = xy[0])
Below are my three attempts at writing a map that works (code on Nim playground: https://play.nim-lang.org/#ix=3Heq). Attempts 1 & 2 failed and attempt 3 succeeded. Similarly, I implemented min using both attempt 1 & attempt 2, and attempt 1 failed while attempt 2 succeeded.
However, I'm confused as to why the previous attempts fail, and what the best practice is:
Why does attempt 1 fail when the actual return type of the iterators is iterable[T]?
Why does attempt 2 fail for tables.keys? Is tables.keys implemented differently?
Is attempt 2 the canonical way of taking iterators / iterables as function arguments? Are there alternatives to this?
Attempt 1: Function that takes an iterable[T].
Since the Nim manual seems to imply that the result type of calling an iterator is iterable[T], I tried defining map for iterable[T] like this:
iterator map[A, B](iter: iterable[A], fn: A -> B): B =
for x in iter:
yield fn(x)
But it failed with a pretty long and confusing message:
/usercode/in.nim(16, 24) template/generic instantiation of `map` from here
/usercode/in.nim(11, 12) Error: type mismatch: got <iterable[(int, int)]>
but expected one of:
iterator items(a: cstring): char
first type mismatch at position: 1
required type for a: cstring
but expression 'iter' is of type: iterable[(int, int)]
... (more output like this)
From my understanding it seems to say that items is not defined for iterable[T], which seems weird to me because I think items is exactly what's need for an object to be iterable?
Attempt 2: Function that returns an iterator.
I basically copied the implementation in def-/nim-itertools and defined a map function that takes an iterator and returns a new closure iterator:
type Iterable[T] = (iterator: T)
func map[A, B](iter: Iterable[A], fn: A -> B): iterator: B =
(iterator: B =
for x in iter():
yield fn(x))
but this failed with:
/usercode/in.nim(25, 24) Error: type mismatch: got <iterable[lent (int, int)], proc (xy: GenericParam): untyped>
but expected one of:
func map[A, B](iter: Iterable[A]; fn: A -> B): B
first type mismatch at position: 1
required type for iter: Iterable[map.A]
but expression 'keys(locations)' is of type: iterable[lent (int, int)]
proc map[T, S](s: openArray[T]; op: proc (x: T): S {.closure.}): seq[S]
first type mismatch at position: 1
required type for s: openArray[T]
but expression 'keys(locations)' is of type: iterable[lent (int, int)]
expression: map(keys(locations), proc (xy: auto): auto = xy[0])
which hints that maybe tables.keys doesn't return an iterator?
Attempt 3: Rewrite keys using attempt 2.
This replaces tables.keys using a custom myKeys that's implemented in a similar fashion to the version of map in attempt 2. Combined with map in attempt 2, this works:
func myKeys[K, V](table: Table[K, V]): iterator: K =
(iterator: K =
for x in table.keys:
yield x)
Explanation of errors in first attempts
which hints that maybe tables.keys doesn't return an iterator
You are right. It does not return an iterator, it is an iterator that returns elements of the type of your Table keys. Unlike in python3, there seems to be no difference between type(locations.keys) and type(locations.keys()). They both return (int, int).
Here is keys prototype:
iterator keys[A, B](t: Table[A, B]): lent A
The lent keyword avoids copies from the Table elements.
Hence you get a type mismatch for your first and second attempt:
locations.keys.map(xy => xy[0]) has an incorrect first parameter, since you get a (int, int) element where you expect a iterable[A].
Proposals
As for a solution, you can either first convert your keys to a sequence (which is heavy), like hola suggested.
You can directly rewrite a procedure for your specific application, mixing both the copy in the sequence and your operation, gaining a bit in performance.
import tables
# A mapping from coordinates (x, y) to values.
var locations = initTable[(int, int), int]()
# Put in some random values.
locations[(1, 2)] = 1
locations[(2, 1)] = 2
locations[(-2, 5)] = 3
func firstCoordinate[X, Y, V](table: Table[(X, Y), V]): seq[X] =
result = #[]
for x in table.keys:
result.add(x[0])
let minX = locations.firstCoordinate.min
echo minX
This is not strictly adhering your API, but should be more efficient.
I am trying to find the find the result of num1 raised to the power num2:
This is my code ->
fun power(num1 : Int, num2: Int): Int {
var result = 1
while (num2 != 0) {
return result *= num1
num2--
}
}
But the above code is producing the following error -->
Calculator.kt:30:16: error: assignments are not expressions, and only expressions are allowed in this context
return result *= num1
^
Calculator.kt:33:5: error: a 'return' expression required in a function with a block body ('{...}')
}
^
I have read a number of articles but not able to understand. Any help will be highly appreciated.
Thank you
An expression is something that evaluates to a value. An assignment is something that assigns a value to a variable or property.
x *= y is an assignment that is shorthand for x = x * y.
You cannot return an assignment, because it does not evaluate to a value. An assignment contains an expression on the right side of the equals sign, but as a whole does not represent an expression.
There are some other syntax problems you have. You can't modify a function paramter's value (num2-- isn't allowed).
The logic also doesn't make sense. return returns an expression immediately. To fix your code, you need to create a local variable from num2, and move the return statement to the end.
fun power(num1 : Int, num2: Int): Int {
var result = 1
var count = num2
while (count != 0) {
result *= num1
count--
}
return result
}
FYI, there's a function called repeat that is simpler than using a while loop with a counter. It runs the code inside the brackets by the number of times you give.
fun power(num1 : Int, num2: Int): Int {
var result = 1
repeat(num2) {
result *= num1
}
return result
}
You function contains multiple errors, I suggest you to study Kotlin, here a reference. Kotlin website has some more material.
Back to your problem, I have modified your function:
fun power(num1 : Int, num2: Int): Int {
var result = 1
var num2_local = num2
while (num2_local != 0) {
result *= num1
num2_local--
}
return result
}
Problems with your version:
you return from the function immediately
basic types args passed to kotlin functions are passed by const copy, this means that you cannot modify them (e.g num2--)
If you keep a local modifiable reference (var keyword) withing your function, then you achieve your goal
I have a question about Kotlin.
I tried two versions of Kotlin, 1.0.0 and 1.2.6.
Using Kotlin, we can initialize an array and access to its element like this.
val n: Int = 10
val arr = Array(n, { it } )
val i: Int = 0
println(arr[i])
However, I got an error with this code.
val n: Long = 10
val arr = Array(n, { it } )
val i: Long = 0
println(arr[i])
It seems that it is an only way to cast Long to Int in order to compile this code.
val n: Long = 10
val arr = Array(n.toInt(), { it } )
val i: Long = 0
println(arr[i.toInt()])
However, it seems too redundant to me, but I couldn't find any solutions. So my question is
Is there any way to initialize arrays and access elements with a Long
variable?
Does Kotlin have any reasons that Long variable should not be accepted here?
Kotlin comes with longArrayOf(1, 2, 3) which will create an array for you which contains Longs.
Note that what you are trying to do with println(arr[i]) is getting a Long value out of arr, but the indexing of arrays is done with Ints. It will never work with Longs:
/**
* Returns the array element at the given [index].
* This method can be called using the index operator.
*/
public operator fun get(index: Int): Long
If you want to initialize an array of longs of the given length, you can use the same top-level Array function:
val n = 10 // n is Int
val arrayOfLongs = Array(n) { it.toLong() } // Array of 10 longs
Here the number n is Int and the initializer function converts the integer index it of an element being initialized to Long, therefore we get an array of longs as the result.
Or you can use another similar function to create a specialized LongArray:
val longArray = LongArray(n) { it.toLong() } // LongArray of 10 longs
Both arrays store longs, but the latter does it more compactly.
When looping through a list (or an array), is there a way to know the index of the current element inside the loop?
Of course, the problem can be solved by looping through indices:
my #aa = 8 .. 12;
say "$_\t#aa[$_]" for 0 ..^ #aa.elems;
But maybe something like the following is possible (I marked with .CURRENT_INDEX the method I'm looking for)?
my #aa = 8 .. 12;
say $_.CURRENT_INDEX\t$_ for #aa;
To get the loop index of the current element of loop over a list, you can use the .kv method of a list. It returns an interleaved sequence of indexes and values:
my #aa = 8 .. 12;
for #aa.kv -> $i, $_ { say "$i: $_" }
Output:
0: 8
1: 9
2: 10
3: 11
4: 12
TLDR: Use .kv or .pairs.
This is sort of what is really happening under the hood:
my #aa = 8 .. 12;
my \iterator = #aa.iterator;
while ($_ := iterator.pull-one) !=:= IterationEnd {
say $_
}
The value in iterator in this case is an anonymous class that does the Iterator role.
An Iterator may or may not have any way to know how many values it has produced. For example the Iterator for .roll(*) doesn't need to know how many values it has produced so far, so it doesn't.
It is possible for an Iterator to implement a method that returns its current index.
my #aa = 8 .. 12;
my \iterator = class :: does Iterator {
has $.index = 0; # declares it as public (creates a method)
has #.values;
method pull-one () {
return IterationEnd unless #!values;
++$!index; # this is not needed in most uses of an Iterator
shift #!values;
}
}.new( values => #aa );
say "{iterator.index}\t$_" for Seq.new: iterator;
1 8
2 9
3 10
4 11
5 12
You could also do it in a higher level construct;
my #aa = 8 .. 12;
my $index = 0;
my $seq := gather for #aa { ++$index; take $_ };
say "$index\t$_" for $seq;
To get $_.CURRENT-INDEX to work requires wrapping the result.
class Iterator-Indexer does Iterator {
has Iterator $.iterator is required;
has $!index = 0;
method pull-one () {
my \current-value = $!iterator.pull-one;
# make sure it ends properly
return IterationEnd if current-value =:= IterationEnd;
# element wrapper class
class :: {
has $.CURRENT-INDEX;
has $.value;
# should have a lot more coercion methods to work properly
method Str () { $!value }
}.new( CURRENT-INDEX => $!index++, value => current-value )
}
}
multi sub with-index ( Iterator \iter ){
Seq.new: Iterator-Indexer.new: iterator => iter;
}
multi sub with-index ( Iterable \iter ){
Seq.new: Iterator-Indexer.new: iterator => iter.iterator;
}
my #aa = 8 .. 12;
say "$_.CURRENT-INDEX()\t$_" for with-index #aa.iterator;
# note that $_ is an instance of the anonymous wrapper class
Again with a higher level construct:
my #aa = 8 .. 12;
my \sequence := #aa.kv.map: -> $index, $_ {
# note that this doesn't close over the current value in $index
$_ but role { method CURRENT-INDEX () { $index }}
}
say "$_.CURRENT-INDEX()\t$_" for sequence;
I would argue that you should just use .pairs if you want it something like this. (or use .kv but that basically requires using the block form of for with two parameters)
my #aa = 8 .. 12;
say "$_.key()\t$_.value()" for #aa.pairs;
Here's another way, using your own index variable:
my #aa = 8..12;
say $++, ": $_" for #aa;
Output:
0: 8
1: 9
2: 10
3: 11
4: 12
The question is, how to create a python like iterator in Kotlin.
Consider this python code that parses string into substrings:
def parse(strng, idx=1):
lst = []
for i, c in itermarks(strng, idx):
if c == '}':
lst.append(strng[idx:i-1])
break
elif c == '{':
sublst, idx = parse(strng, i+1)
lst.append(sublst)
else:
lst.append(strng[idx:i-1])
idx = i+1
return lst, i
>>>res,resl = parse('{ a=50 , b=75 , { e=70, f=80 } }')
>>>print(resl)
>>>[' a=50', ' b=75', [' e=7', ' f=80'], '', ' f=80']
This is a play example just to illustrate a python iterator:
def findany(strng, idx, chars):
""" to emulate 'findany' in kotlin """
while idx < len(strng) and strng[idx] not in chars:
idx += 1
return idx
def itermarks(strng, idx=0):
while True:
idx = findany(strng, idx, ',{}"')
if idx >= len(strng):
break
yield idx, strng[idx]
if strng[idx] == '}':
break
idx += 1
Kotlin has iterators and generators, and as I understand it there can only be one per type. My idea is to define a type with a generator and instance that type. So the for loop from 'parse' (above) would look like this :
for((i,c) in IterMarks(strng){
......
}
But how do i define the generator, and what is the best idiom.
Kotlin uses two interfaces: Iterable<T> (from JDK) and Sequence<T>. They are identical, with the exception that the first one is eager, while the second one is lazy by convention.
To work with iterators or sequences all you have to do is implement one of those interfaces. Kotlin stdlib has a bunch of helper functions that may help.
In particular, a couple of functions for creating sequences with yield was added in 1.1. They and some other functions are called generators. Use them if you like them, or implement the interfaces manually.
OK, after some work, here is the Kotlin for the iterator:
import kotlin.coroutines.experimental.*
fun iterMarks(strng: String, idx:Int=0)=buildSequence{
val specials = listOf("\"", "{", "}", ",")
var found:Pair<Int,String>?
var index = idx
while (true){
found = strng.findAnyOf(specials, index)
if (found == null) break
yield (found)
index= found.first + 1
}
}
The main discoveries were that an iterator can be returned by any function, so the there is no need to add the iterator methods to an existing object. The JetBrains doco is solid, but lacks examples so hopefully the above example helps. You can also work from the basics, and again the notes are good but lack examples. I will post more on other approaches if there is interest.
The this code for 'parse' then works:
fun parse(strng:String, idxIn:Int=1): Pair<Any,Int> {
var lst:MutableList<Any> = mutableListOf()
var idx = idxIn
loop# for (mark in iterMarks(strng, idx)){
if(mark==null ||mark.first <= idx){
// nothing needed
}
else
{
when( mark.second ) {
"}" -> {
lst.add(strng.slice(idx..mark.first - 1))
idx = mark.first + 1
break#loop
}
"{" -> {
val res: Pair<Any, Int>
res = parse(strng, mark.first + 1)
lst.add(res.first)
idx = res.second
}
"," -> {
lst.add(strng.slice(idx..mark.first - 1))
idx = mark.first + 1
}
}
}
}
return Pair(lst, idx)
}
Hopefully this example will make it less work for the next person new to Kotlin, by providing an example of implementing an iterator. Specifically if you know how to make an iterator in python then this example should be useful