Author Message

How can I write a function so that its behavior depends on the number of
arguments?

For example, here's a function called 'range' written in Mathematica.
(implemented without error checking)

range::"usage"=
"range[a,b,dx] returns a list from a to b with increment dx. dx can be
negative if a > b. range[n] is equivalent to range[1,n,1]. range[a,b] is
equivalent to range[a,b,1].";

range[a_]:=range[1,a,1];
range[a_,b_]:=range[a,b,1];
range[a_,b_,dx_]:=Prepend[range[a+dx,b,dx],a];

I want to write range in both Perl and Scheme. Suggestion of common practice
appreciated. (if it cannot be done as is)

http://www.*-*-*.com/ ~xah/Wallpaper_dir/c0_WallPaper.html
"Unix + C + Perl = Apocalypse"

Wed, 14 Jun 2000 03:00:00 GMT

Here's a correction to the Mathematica code I gave:

range[a_]:=range[1,a,1];
range[a_,b_]:=range[a,b,1];

http://www.best.com/~xah/Wallpaper_dir/c0_WallPaper.html
"Unix + C + Perl = Apocalypse"

Wed, 14 Jun 2000 03:00:00 GMT

Sorry folks. The Mathematica code I gave is incorrect again. I just realized
that a correct solution cannot be coded recursively using only one symbol.
Anyhow, my original question is how to write a function in Perl and Scheme
such that different number of arguments calles different definitions.

If you are interested in writing Range for fun, let's start another thread.
(or you can email me first, then I'll give you the complete spec.

Xah

Quote:

>Here's a correction to the Mathematica code I gave:

>range[a_]:=range[1,a,1];
>range[a_,b_]:=range[a,b,1];

> http://www.best.com/~xah/Wallpaper_dir/c0_WallPaper.html
> "Unix + C + Perl = Apocalypse"

Wed, 14 Jun 2000 03:00:00 GMT

Quote:

> How can I write a function so that its behavior depends on the number of
> arguments?

> For example, here's a function called 'range' written in Mathematica.
> (implemented without error checking)

> range::"usage"=
>   "range[a,b,dx] returns a list from a to b with increment dx. dx can be
> negative if a > b. range[n] is equivalent to range[1,n,1]. range[a,b] is
> equivalent to range[a,b,1].";

> range[a_]:=range[1,a,1];
> range[a_,b_]:=range[a,b,1];
> range[a_,b_,dx_]:=Prepend[range[a+dx,b,dx],a];

> I want to write range in both Perl and Scheme. Suggestion of common practice
> appreciated. (if it cannot be done as is)

Scheme:

Use dot in the parameter list:
(this is the usual way to treat the arbitrary lists of args, see
r4rs 4.1.1)

(define (range a . x)
(if (null? x) (make-range 1 a 1)
(let ((b (car x)) (dx (cdr x)))
(if (null? dx) (make-range a b 1)
(make-range a b dx)))))

here make-range can be something like (probably can be much more elegant):

(define (make-range a b dx)
(if (= 0 dx) (breakpoint "0 delta in make-range")
(if (= (sign (- b a)) (sign dx))
(let ((end-range
(if (> dx 0) (lambda (x) (> x b))
(lambda (x) (< x b)))))
(letrec ((really-make-range
(lambda (x res)
(if (end-range x) (reverse res)
(really-make-range (+ x dx) (cons x res))))))
(really-make-range a '() )))
'() )))
(define (sign x) (if (>= x 0) 1 -1))

-------

Wed, 14 Jun 2000 03:00:00 GMT

Sorry, in my previous posting it should be:

(define (range a . x)
(if (null? x) (make-range 1 a 1)
(let ((b (car x)) (dx (cdr x)))
(if (null? dx) (make-range a b 1)
(make-range a b (car dx))))))

-----------------------
Then it works in all the cases:

Quote:
> (range -10 1)

'(-10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1)
Quote:
> (range -10 1 3)
'(-10 -7 -4 -1)
> (range 3)
'(1 2 3)

> (range -10)

'()

Wed, 14 Jun 2000 03:00:00 GMT

Quote:

> How can I write a function so that its behavior depends on the number of
> arguments?

> For example, here's a function called 'range' written in Mathematica.
> (implemented without error checking)

> range::"usage"=
>   "range[a,b,dx] returns a list from a to b with increment dx. dx can be
> negative if a > b. range[n] is equivalent to range[1,n,1]. range[a,b] is
> equivalent to range[a,b,1].";

> range[a_]:=range[1,a,1];
> range[a_,b_]:=range[a,b,1];
> range[a_,b_,dx_]:=Prepend[range[a+dx,b,dx],a];

> I want to write range in both Perl and Scheme. Suggestion of common practice
> appreciated. (if it cannot be done as is)

For completely unspecified arity, replace the parameter list with a
single identifier (which is bound at call time to a list containing all of
the arguments).  Here's how I'd write RANGE:

(define range
(lambda args
(let ((arg-count (length args)))
(if (not (<= 1 arg-count 3))
(error 'range "wrong number of arguments"))
(let ((start (if (= arg-count 1) 1 (car args)))
(finish (if (= arg-count 1) (car args) (cadr args)))
(increment (if (= arg-count 3) (caddr args) 1)))
(let ((beyond (cond ((positive? increment) >)
((negative? increment) <)
(else (error 'range "zero increment")))))
(let loop ((result '())
(counter start))
(if (beyond counter finish)
(reverse result)
(loop (cons counter result) (+ counter increment)))))))))

If you want some number of required parameters followed by zero or
more optional ones, write the parameter list as

(required-1 required-2 ... required-n . optional)

A call will then contain n or more arguments, the first n bound to
REQUIRED-1, REQUIRED-2, ..., REQUIRED-N, and the remaining ones assembled
into a list that is bound to OPTIONAL.

--
======  John David Stone - Lecturer in Computer Science and Philosophy  =====
==============  Manager of the Mathematics Local-Area Network  ==============
==============  Grinnell College - Grinnell, Iowa 50112 - USA  ==============

Wed, 14 Jun 2000 03:00:00 GMT

Quote:

> How can I write a function so that its behavior depends on the number of
> arguments?

in such cases i write a "meta-routine" which figures out how many
arguments there are then calls another routine to do the actual work.
the meta-routine can supply default arguments or switch the order
around if it likes:

Quote:
>range[a_]:=range[1,a,1];

Quote:
>range[a_,b_]:=range[a,b,1];

and so on.  good luck :)

--
brian d foy                                 <http://computerdog.com>
#!/usr/bin/perl
\$_=q|osyrNewkecnaYhe.mlorsePptMskurj|;s;[NY.PM]; ;g;local\$\=

\$pm=join'',reverse(\$ny,\$pm);open(NY,'>&STDOUT');print NY \$pm

Wed, 14 Jun 2000 03:00:00 GMT

(Perl here)

This is trivial in Perl, but it's fun to talk about anyway.

Let's not forget to point out specifically that the number of supplied

sub how_many_args_have_i {

print "I'm a \$argc-argument subroutine!\n";
}

No humanitarian purpose is served by the following snippet, but here
it goes (5.004 only):

sub way_too_much_technology_here {
(\${{

}

way_too_much_technology_here 1;
way_too_much_technology_here 1,2;
way_too_much_technology_here 1,2,3,4;
way_too_much_technology_here;

-joseph
http://www.effectiveperl.com

Quote:

> > How can I write a function so that its behavior depends on the number of
> > arguments?

> in such cases i write a "meta-routine" which figures out how many
> arguments there are then calls another routine to do the actual work.
> the meta-routine can supply default arguments or switch the order
> around if it likes:

> >range[a_]:=range[1,a,1];

> >range[a_,b_]:=range[a,b,1];

> and so on.  good luck :)

Thu, 15 Jun 2000 03:00:00 GMT

Joseph> No humanitarian purpose is served by the following snippet, but here
Joseph> it goes (5.004 only):

Joseph>   sub way_too_much_technology_here {
Joseph>     (\${{

Joseph>   }

Joseph>   way_too_much_technology_here 1;
Joseph>   way_too_much_technology_here 1,2;
Joseph>   way_too_much_technology_here 1,2,3,4;
Joseph>   way_too_much_technology_here;

Or, slightly easier to read, perhaps, but still too much technology:

sub way_too_much_technology_here {
([
undef,

}

way_too_much_technology_here 1;
way_too_much_technology_here 1,2;
way_too_much_technology_here 1,2,3,4;
way_too_much_technology_here;

print "Just another Perl hacker," # but not what the media calls "hacker!" :-)
## legal fund: \$20,990.69 collected, \$186,159.85 spent; just 247 more days

--
Name: Randal L. Schwartz / Stonehenge Consulting Services (503)777-0095
Keywords: Perl training, UNIX[tm] consulting, video production, skiing, flying