Home   Archive   Permalink



What is wrong ?

Hi
Just discovering Rebol and i try this below:
factorial: func [n] [either n > 1 [n * factorial (n - 1)] [1]]
print factorial (3)
print factorial (2)
print factorial (3) * factorial (2)
    
The output is
6 (OK)
2 (OK)
720 (wrong?????)
What i am doing wrong?

posted by:   Gérard       29-Nov-2012/6:14:33-8:00



Evaluation in REBOL is left to right, but infix operations take precedence over prefix operations.    
    
The "*" symbol takes two values, so your code is evaluated as:
    
factorial (3 * (factorial 2))
factorial (3 * 2)
factorial 6
720
    
Use parentheses to force precedence:
    
>> factorial 2 + 1 * 2
== 720
>> factorial (2 + 1) * 2
== 720
>> factorial 2 + (1 * 2)
== 24
>> (factorial 2 + 1) * 2
== 12
    
So the code you want is:
    
print (factorial 3) * (factorial 2)
or
print (factorial 3) * factorial 2     ; second parens not required
    
(factorial 3) * (factorial 2)
6 * 2
12
    
To add some more clarification, all infix operators have prefix versions:
    
(2 * 2) = (* 2 2)
    
So, another way to write your intended expression could be:
    
print * factorial 3 factorial 2
    
Be sure to look at the source:
    
source *
    
*: native [
     "Returns the first value multiplied by the second."
     value1 [number! pair! char! money! time! tuple!]
     value2 [number! pair! char! money! time! tuple!]
]
    
The prefix version is * value1 value2
The infix version is value1 * value2 <- (VALUE1 * VALUE2) WILL BE COMPUTED
                                            _BEFORE_ THE REST OF A SURROUNDING
                                            LEFT-TO-RIGHT EXPRESSION
    
Hope that helps :)

posted by:   Nick       30-Nov-2012/6:06:49-8:00



Notice there's a difference in performance between infix and prefix operators:
    
do http://www.fm.vslib.cz/~ladislav/rebol/timblk.r
>> time-block [loop 1000 [2 + 2]] .05
== 4.4464111328125E-4
>> time-block [loop 1000 [+ 2 2]] .05
== 8.6083984375E-4

posted by:   Nick       30-Nov-2012/6:16:26-8:00



I'm not sure I can figure out which is consistently faster:
    
R E B O L []
    
factorial: func [n] [either > n 1 [* n factorial (- n 1)] [1]]
wait 1
start: now/time/precise
loop 100000 [(factorial 3) * factorial 2]
print now/time/precise - start
wait 1
start: now/time/precise
loop 100000 [* factorial 3 factorial 2]
print now/time/precise - start
halt
    
factorial: func [n] [either n > 1 [n * factorial (n - 1)] [1]]
wait 1
start: now/time/precise
loop 100000 [(factorial 3) * factorial 2]
print now/time/precise - start
wait 1
start: now/time/precise
loop 100000 [* factorial 3 factorial 2]
print now/time/precise - start
halt
    
0:00:02.231
0:00:02.372

posted by:   Nick       30-Nov-2012/6:24:24-8:00



That's actually really interesting to me. I always tend to use parentheses, but would have tended to consider the prefix notation more "REBOLish" (I remember reading somewhere that infix notation was first converted to prefix notation, then interpreted from there). It'll be really interesting to see the code soon - I'm sure there will be all sorts of tests and optimization attempts...

posted by:   Nick       30-Nov-2012/6:35:23-8:00



Anyone know the answer to this already? Is infix faster than prefix notation?

posted by:   Nick       3-Dec-2012/22:36:04-8:00