Find arity of a rebol function I needed a way to find the number of arguments a function or operation in Rebol accepts (the functions arity). I could not find any direct support for this in the language, so I made my own arity function:

arity: func [
    "Returns the arity of a function, disregarding refinements."
    :f [function! op! native! action!]
    /local spec result
] [
    result: 0
    spec: copy third :f
    loop length? spec [
        switch type?/word first spec [
            word! [ result: result + 1 ]
            refinement! [ break ]
        ]   
        spec: next spec
    ]   
    result
]   


Let's take it for a spin:

REBOL/Core 2.7.8.4.2 (2-Jan-2011)
&gt;&gt; do load %arity.reb
&gt;&gt; help arity
USAGE:
    ARITY :f 

DESCRIPTION:
     Returns the arity of a function, disregarding refinements.
     ARITY is a function value.

ARGUMENTS:
     f -- (Type: function op native action)
&gt;&gt; arity print
== 1
&gt;&gt; arity +
== 2
&gt;&gt; arity either
== 3
&gt;&gt; arity quit
== 0


Questions I have:


Are there really no easier, built in way of getting the arity?
Am I covering everything (all function types) by specifying [function! op! native! action!]?
Are there any corner cases where this function will give the wrong answer?
Does it make sense to copy the parameter block from f like I do here?
Finally: Can you suggest any improvements to my code?
Finally: Can you suggest any improvements to my code?


Fair warning ahead: I've only tried the following with Rebol 3. That said: going into a different direction than the improvements suggested by @HostileFork, here's an alternative approach:

arity: func [
    "Returns the arity of a function, disregarding refinements."
    f [any-function!]
] [
    -1 + index? find join words-of :f /sentinel refinement!
]


(No get-/lit-argument tricks here, sorry. Also refer to @HostileFork's answer for that particular aspect.)

The Gory Details

For those not that familiar with Rebol, let's dissect that step by step. First, a fully parenthesised variant of the core expression:

-1 + (index? (find (join (words-of :f) /sentinel) refinement!)


@HostileFork's answer already mentions WORDS-OF, which is a convenient way to get only the core parts of a function spec:

&gt;&gt; words-of :append
== [series value /part length /only /dup count]

&gt;&gt; words-of :+
== [value1 value2]


Building on that, the core idea is to use FIND with a datatype, to position to the first refinement! argument:

&gt;&gt; find words-of :append refinement!
== [/part length /only /dup count]


Great! But what about functions which have no refinements at all, like + shown above?

&gt;&gt; find words-of :+ refinement!
== none


To counter that, we simply add a sentinel value at the end, so that we can ensure that there'll always be a refinement! present:

&gt;&gt; join words-of :+ /sentinel
== [value1 value2 /sentinel]

&gt;&gt; find join words-of :+ /sentinel refinement!
== [/sentinel]


For our final step, we utilise the fact that Rebol blocks are "cursor-like". FIND does not return a copy of the original block with just the remaining elements after and including the match, FIND returns a new block "cursor" which is positioned right after the match within the original data. We can use INDEX? to ask this "cursor" its current position:

&gt;&gt; index? find join words-of :+ /sentinel refinement!
== 3


As we can see, this expression using INDEX? gives us the (1-based) position of the first refinement. Subtract 1 from that, and we have the count of non-refinement arguments. (If we'd have zero-based functions already, we could get rid of that final step.)

Et voilà:

&gt;&gt; -1 + index? find join words-of :+ /sentinel refinement!
== 2


I hope you enjoyed the ride :)