Find arity of a rebol function
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 :)