import random, algorithm
# a < b ==> cmp(a, b) < 0
proc cmp(a, b: int): int =
(a > b).int - (a < b).int
proc quicksort(a: var openarray[int]; left, right: int; cp: proc (a, b: int): int) =
proc qsort(left, right: int) =
var l, r, p: int
let len = right - left
let len2 = len div 2
if true: # insertion sort on tiny array
for i in left + 1 .. right:
for j in countdown(i, left + 1):
if cp(a[j], a[j - 1]) >= 0: break # this is the line with error
swap(a[j], a[j - 1])
return
qsort(a.low, a.high)
var
x: array[2e6.int, int]
quicksort(x, x.low, x.high, cmp)
e.nim(15, 17) Error: illegal capture 'a
I tried writing it in this way because recursively passing the cmp proc makes sorting a bit slower. I tried pragmas procvar and closure, but that seems to make no difference.
That has to do with the fact that lambdas in Nim are not as great as in other languages. This is how I got it to compile:
proc cmp(a, b: int): int =
(a > b).int - (a < b).int
proc quicksort(a: var openarray[int]; left, right: int; cp: proc (a, b: int): int) =
proc qsort(a: var openarray[int]; left, right: int) =
var l, r, p: int
let len = right - left
let len2 = len div 2
if true: # insertion sort on tiny array
for i in left + 1 .. right:
for j in countdown(i, left + 1):
if cp(a[j], a[j - 1]) >= 0: break # this is the line with error
swap(a[j], a[j - 1])
return
qsort(a, a.low, a.high)
var
x: array[2e6.int, int]
quicksort(x, x.low, x.high, cmp)
That has to do with the fact that lambdas in Nim are not as great as in other languages.
Hey, that's not fair. :P It has to do with the fact that lambdas do not break memory safety.
I am sorry I was not entirely fair. I do not understand lambdas in Nim very well. It would be nice to know how they work internally, so I would feel more comfortable to use them, and I can predict better what they are able to do and what they are not able to do. I only know two kinds of lambdas:
C++: In C++ lambdas are very explicit in what they capture, and how they capture it. When I capture something by reference, it is in my responsibility, that the lambda does not outlive the lifetime of the objects it references. Other things I can simply pass as value
Scala: In scala lambdas are compiled to simple java casses. Everdthing that applies to classes also applies to lambdas. No surprises here. But unlike java they made the corner cases that are a bit harder to compile just work.
In Nim everything is a bit more mysterious to me. The syntax to create lambda objects is not as compact as the scala representation (especially with the lambda argument type inference). In the end I just don't use lambdas as often as I would like to, just because of that. I haven't checked the documentation recently though.
Krux02: I found the following document earlier today that explains some of the internals: here
I also made this several months ago to test out functional programming in Nim. Had been away from Nim for a while so I am not sure if there are better libraries doing that now. I could not get it to work without the pipe iterator.