I've been playing with Nim for about 4 weeks now. I've copied/run some small programs (Rosetta Stone), and translated some small Ruby snippets that compiled. Now I'm trying to do a direct translation of a bigger C++ program of about 200 loc with about 5 separate functions.
Here's an example of a snippet of code that won't compile.
When I write this routine with the following indention (starting from first column)
proc segsieve(Kn: uint):
# for Kn resgroups in segment
for b in 0 .. <Kn: # for every byte in the segment
seg[b] = 0 # set every byte bit to prime (0)
for r in 0 .. <rescnt: # for each ith (of 8) residues for P5
let biti = uint8(1 shl r) # set the ith residue track bit mask
let row = r*pcnt # set address to ith row in next[]
for j in 0 .. <pcnt: # for each prime <= sqrt(N) for restrack
if next[row+j] < uint(Kn): # if 1st mult resgroup index <= seg size
var k: int = int(next[row+j]) # get its resgroup value
let prime = primes[j] # get the prime
while k < Kn: # for each primenth byte < segment size
seg[k] = seg[k] or biti # set ith residue in byte as nonprime
next[row+j] = uint(k - Kn) # 1st resgroup in next eligible segment
k += prime
else: next[row+j] -= uint(Kn) # if 1st mult resgroup index > seg size
# count the primes in the segment
for byt in seg: # for the Kn resgroup bytes
primecnt += uint(pbits[int(byt)]) # count the '0' bits as primes
I get the following compiler message, which points to the start of the first for statement:
ssozp5segsieve.nim(56, 3) Error: expression expected, but found 'keyword for'
But when I get rid of the proc statement, and write it like below, starting from first column, it compiles and run.
#proc segsieve(Kn: uint):
# for Kn resgroups in segment
for b in 0 .. <Kn: # for every byte in the segment
seg[b] = 0 # set every byte bit to prime (0)
for r in 0 .. <rescnt: # for each ith (of 8) residues for P5
let biti = uint8(1 shl r) # set the ith residue track bit mask
let row = r*pcnt # set address to ith row in next[]
for j in 0 .. <pcnt: # for each prime <= sqrt(N) for restrack
if next[row+j] < uint(Kn): # if 1st mult resgroup index <= seg size
var k: int = int(next[row+j]) # get its resgroup value
let prime = primes[j] # get the prime
while k < Kn: # for each primenth byte < segment size
seg[k] = seg[k] or biti # set ith residue in byte as nonprime
next[row+j] = uint(k - Kn) # 1st resgroup in next eligible segment
k += prime
else: next[row+j] -= uint(Kn) # if 1st mult resgroup index > seg size
# count the primes in the segment
for byt in seg: # for the Kn resgroup bytes
primecnt += uint(pbits[int(byt)]) # count the '0' bits as primes
This happens with alll the procs in the code. What am I doing wrong? Here's the whole code (88 tloc) that runs when no indentation is used.
let pbits = [
8,7,7,6,7,6,6,5,7,6,6,5,6,5,5,4,7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3
,7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2
,7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2
,6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1
,7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2
,6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1
,6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1
,5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1,4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0
]
let residues = [1, 7, 11, 13, 17, 19, 23, 29, 31]
# Global parameters
const
modp5 = 30 # prime generator mod value
rescnt = 8 # number of residues for prime generator
let
#B = 262144
B = 354
Kn = B
Ki = 0
pcnt = 24 # number of primes from r1..sqrt(N)
var
primecnt = 3'u64 # number of primes <= N
#next: seq[uint64 | uint] # array of primes first multiples
#primes: seq[uint] # array of primes <= sqrt(N)
#seg: seq[uint8] # seg[B] segment byte array
seg = newSeq[uint8](B)
var next = newSeq[uint](rescnt*pcnt)
let primes = [7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103]
#proc next_init():
var pos = newSeq[int](modp5)
for i in 0 .. <rescnt: pos[residues[i]] = i-1
pos[1] = rescnt-1
# for each prime store resgroup on each restrack for prime*(modk+ri)
for j in 0 .. <pcnt: # for the pcnt primes r1..sqrt(N)
let prime: uint = uint(primes[j]) # for each prime
let k: uint = (prime-2) div uint(modp5) # find the resgroup it's in
let r: uint = (prime-2) mod uint(modp5) + 2 # its base residue value
for ri in residues[1 .. rescnt]: # for each residue value
let prod: int = int(r) * ri # create residues cross-product r*ri
let row: int = pos[prod mod modp5] * pcnt # create residue track address
next[row + j] = k*(prime + uint(ri)) + uint(prod-2) div uint(modp5) # resgroup for prime*(modk+ri))
#proc segsieve(Kn: uint):
# for Kn resgroups in segment
for b in 0 .. <Kn: # for every byte in the segment
seg[b] = 0 # set every byte bit to prime (0)
for r in 0 .. <rescnt: # for each ith (of 8) residues for P5
let biti = uint8(1 shl r) # set the ith residue track bit mask
let row = r*pcnt # set address to ith row in next[]
for j in 0 .. <pcnt: # for each prime <= sqrt(N) for restrack
if next[row+j] < uint(Kn): # if 1st mult resgroup index <= seg size
var k: int = int(next[row+j]) # get its resgroup value
let prime = primes[j] # get the prime
while k < Kn: # for each primenth byte < segment size
seg[k] = seg[k] or biti # set ith residue in byte as nonprime
next[row+j] = uint(k - Kn) # 1st resgroup in next eligible segment
k += prime
else: next[row+j] -= uint(Kn) # if 1st mult resgroup index > seg size
# count the primes in the segment
for byt in seg: # for the Kn resgroup bytes
primecnt += uint(pbits[int(byt)]) # count the '0' bits as primes
#proc printprms(Kn: unit, Ki: uint64):
# Extract and print the primes in each segment:
# recommend piping output to less: ./ssozpxxx | less
# can then use Home, End, Pgup, Pgdn keys to see primes
for k in 0 .. <Kn: # for Kn residues groups|bytes
for r in 0 .. <8: # for each residue|bit in a byte
if (int(seg[k]) and (1 shl r)) == 0: # if it's '0' it's a prime
write(stdout, " ", modp5*(Ki+k) + residues[r+1])
echo "\n"
#segsieve(Kn)
echo(primecnt)
echo(seg[0..353])
I'm using Nim 0.17 with Manjaro (KDE5) in VirtualBox with gcc 7.1.1 and clang 4.0.1 (same results using gcc or clang) with the following compiler directive.
[jzakiya@jabari-pc nim]$ nim c --cc:clang --d:release ssozp5segsieve.nim
Hint: used config file '/etc/nim.cfg' [Conf]
Hint: system [Processing]
Hint: ssozp5segsieve [Processing]
ssozp5segsieve.nim(56, 3) Error: expression expected, but found 'keyword for'
Hi. The correct syntax for procs is
proc next_init() =
discard
proc next_init(): MyType =
discard
not this
proc next_init():
discard
Hey thanks! That solved one set of problems.
What's the difference between have the : and not having it.
I've seen both cases in the docs and code.
# procedure without return value
proc doThis() =
discard
#procedure returns value
proc UltimateAnswerOfLifeTheUniverseAndEverything(): int =
result = 42
echo UltimateAnswerOfLifeTheUniverseAndEverything()
When the function has no argument and return nothing (void), I saw sometimes like this
proc main =
echo "In main proc"
when isMainModule:
main()
What's the difference between have the : and not having it. I've seen both cases in the docs and code.
Perhaps what you've seen is passing blocks of code using the colon like this?
template foo(actions: untyped): untyped =
actions
foo:
# anything here gets passed as the actions parameter
echo "Hello"
Note that the template definition still uses '=' to define where the code body of the template states (as with proc), but using ':' when calling foo allows you to pass the indented block to the parameter actions.