Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Superpositions and laziness

22 views
Skip to first unread message

Piers Cawley

unread,
Nov 6, 2002, 9:08:16 AM11/6/02
to perl6-l...@perl.org
It occurred to me that being able to set up 'pure' functions in such a
way that they are lazily evaluated when passed a superposition might
be a win.

And then I got to thinking about what would be required from the
language to allow me to implement this functionality in a module. I am
assuming (for the purposes of this example) that functions will get
called with 'simple' argument lists, no defaulting etc, and a maximum
of one superposed argument...)

class PureFunction is Sub {

# I'm assuming here that 'apply' is equivalent to func(...)
method apply(*@arglist) {
my @curry_list;
my $super_arg;
for @arglist; .param_list -> $arg; $param {
when Superposition {
die "Too many superposed args" if defined $super_arg;
$super_arg = $arg;
}
otherwise {
push @curry_list, ($param.symbol => $arg);
}
}

return FunctionApplication::Superposed
.new( superposition => $super_arg,
func => $self.given(*@curry_list) );
}
}
}

class FunctionApplication::Superposed is Superposition {
my $.superposition;
my $.func;

method force ($self is rw:) {
return $self = ($.func($.superposition)).force;
}

method eigenstates {
.force.eigenstates;
}
}

method Superposition::force ($self:) { $self }

The idea being that, when you do

a_pure_func($val1|$val2|$val3)

instead of Perl going away and doing the calculation right away, you
get back a 'special' superposition which stores an 'invocation
description' and calculation is deferred until you need to get a
superposition's list of possible states.

If that were all there were to it of course then there wouldn't be
much gain from doing this, however, consider:

# Ignore duplicates, it's a proof of concept dammit!
method FunctionApplication::Superposed::choose {
loop {
$.function($.superposition.choose);
CATCH Exception::SuperPositionExhausted { die $@ }
CATCH Exception::ChooseFailure { redo }
otherwise { throw $@ }
}
}

method Superposition::choose($self:) {
for @.states -> $state {
when Superposition {
loop {
my $val = try {
$state.choose;
CATCH Exception::SuperPositionExhausted { last }
otherwise { die $@ }
}
yield $val;
}
}
otherwise { yield $state }
}
throw Exception::SuperPositionExhausted: $self;
}

And, ooh, look, we have something that'll Do The Right Thing with the
nondeterministic algorithm I posted last week.

*Damn* but Perl 6 is going to be a potent programming language...


--
Piers

"It is a truth universally acknowledged that a language in
possession of a rich syntax must be in need of a rewrite."
-- Jane Austen?

Damian Conway

unread,
Nov 7, 2002, 4:48:50 AM11/7/02
to perl6-l...@perl.org
Piers Cawley mused:

> The idea being that, when you do
>
> a_pure_func($val1|$val2|$val3)
>
> instead of Perl going away and doing the calculation right away, you
> get back a 'special' superposition

Remember to s/superposition/junction/g. For this week, at least ;-)


> which stores an 'invocation description' and calculation is deferred
> until you need to get a superposition's list of possible states.

You get most of that with just:

$deferred = &a_pure_func.assuming(arg=>$val1|$val2|$val3);

Then, later, when you want the result junction:

$junction = $deferred();

Of course, the utility of this kind of laziness isn't restricted to
superpositions, so maybe there would be an C<is lazy> property for
subroutines. For example, given the eager subroutine:

sub a_pure_func(Num $n) returns Num {
return $n ** $n
}

we could make it lazy thus:

sub a_pure_func(Num $n) is lazy returns Num {
return $n ** $n
}

which would cause any invocation of C<a_pure_func> to cache
its arguments (probably in a closure) and return a "proxy"
Num that carries out the computation only when the proxy is
evaluated.

Then it wouldn't matter what the subroutine did, or whether
the argument was a simple number, some species of junction,
or some mysterious object of a class derived from Num.

Damian

Luke Palmer

unread,
Nov 7, 2002, 3:49:14 PM11/7/02
to dam...@conway.org, perl6-l...@perl.org
> Date: Thu, 07 Nov 2002 20:48:50 +1100
> From: Damian Conway <dam...@conway.org>

>
> we could make it lazy thus:
>
> sub a_pure_func(Num $n) is lazy returns Num {
> return $n ** $n
> }
>
> which would cause any invocation of C<a_pure_func> to cache
> its arguments (probably in a closure) and return a "proxy"
> Num that carries out the computation only when the proxy is
> evaluated.

sub a_pure_func(Num $n) returns Num {
class is Num {
method FETCH { $n * $n } }.new
}

Yes? No?

Luke

Buddha Buck

unread,
Nov 7, 2002, 4:17:10 PM11/7/02
to Luke Palmer, perl6-l...@perl.org
Luke Palmer wrote:
>>Mailing-List: contact perl6-lan...@perl.org; run by ezmlm
>>From: Luke Palmer <fibo...@babylonia.flatirons.org>
>>Cc: perl6-l...@perl.org
>>Date: Thu, 7 Nov 2002 13:49:14 -0700 (MST)
>>X-SMTPD: qpsmtpd/0.12, http://develooper.com/code/qpsmtpd/
> Whoops, I mean...

>
> sub a_pure_func(Num $n) returns Num {
> class is Num {
> has Num $cache;
> method FETCH { $cache //= $n * $n } } }
>
> Wow, I've never seen such a compact implementation of such a thing. I
> love you, Perl 6 <3]

This is better, but it doesn't deal with STORE.... or does it? Nope, it
doesn't. You need to delegate to $cache.

Hmmm...

sub a_pure_func(Num a) returns Num {
class is Num {
has Num $cache is delegate;
method FETCH {$cache //= $n * $n } }.new }

Or...

sub a_pure_func(Num $a) returns Num {
class is Num (
has Num $cache;
method FETCH { .cache //= $n * $n }
method STORE(Num $x) { .cache = $x } }.new }

I think....


>
> Luke
>

Luke Palmer

unread,
Nov 7, 2002, 3:55:03 PM11/7/02
to fibo...@babylonia.flatirons.org, dam...@conway.org, perl6-l...@perl.org
> Mailing-List: contact perl6-lan...@perl.org; run by ezmlm
> From: Luke Palmer <fibo...@babylonia.flatirons.org>
> Cc: perl6-l...@perl.org
> Date: Thu, 7 Nov 2002 13:49:14 -0700 (MST)
> X-SMTPD: qpsmtpd/0.12, http://develooper.com/code/qpsmtpd/
>

Whoops, I mean...

sub a_pure_func(Num $n) returns Num {
class is Num {

has Num $cache;
method FETCH { $cache //= $n * $n } } }

Wow, I've never seen such a compact implementation of such a thing. I
love you, Perl 6 <3

Luke

Billy Naylor

unread,
Nov 8, 2002, 3:36:19 AM11/8/02
to Damian Conway, perl6-l...@perl.org
Damian Conway wrote:

> we could make it lazy thus:
>
> sub a_pure_func(Num $n) is lazy returns Num {
> return $n ** $n
> }
>
> which would cause any invocation of C<a_pure_func> to cache
> its arguments (probably in a closure) and return a "proxy"
> Num that carries out the computation only when the proxy is
> evaluated.
>

Would it be useful to apply memoization in a similar fashion...

sub square ( Num $n ) is memo {
return $n ** $n;
}

-banjo

Damian Conway

unread,
Nov 8, 2002, 4:22:17 AM11/8/02
to perl6-l...@perl.org
Billy Naylor asked:

> Would it be useful to apply memoization in a similar fashion...
>
> sub square ( Num $n ) is memo {
> return $n ** $n;
> }

Yes. Larry indicated this in A2
(see http://search.cpan.org/perl6/apo/A02.pod#Properties).

The name of the property is still under debate. Larry favours:

sub square ( Num $n ) is same {...}

whereas others feel that:

sub square ( Num $n ) is memoized {...}

is more appropriate.

Damian

Damian Conway

unread,
Nov 8, 2002, 4:35:00 AM11/8/02
to perl6-l...@perl.org
Luke Palmer wrote:


> sub a_pure_func(Num $n) returns Num {
> class is Num {
> method FETCH { $n * $n } }.new
> }
>
> Yes? No?

Not quite.


> sub a_pure_func(Num $n) returns Num {
> class is Num {

> has Num $cache;
> method FETCH { $cache //= $n * $n } } }


Still not quite.

You don't want a C<FETCH> method (which won't be called unless the
object somehow becomes the implementation of a tied variable).

What you want are conversion-to-(num|str|bool) methods:

sub a_pure_func(Num $n) returns Num {
class is Num {

has Num $cache;
sub value { $n * $n }
method operator:+ ($self:) { +($cache //= value ) }
method operator:~ ($self:) { ~($cache //= value ) }
method operator:? ($self:) { ?($cache //= value ) }
}.new
}


> Wow, I've never seen such a compact implementation of such a thing. I
> love you, Perl 6

:-)

Damian

Nicholas Clark

unread,
Nov 8, 2002, 10:04:16 AM11/8/02
to Damian Conway, perl6-l...@perl.org

We're looking for a word that tersely expresses has_no_side_effects_and_can_safely_have_its_results_cached_based_on_parameter_types_and_values_and_calling_context ?

And to people in the perl5 know, Memoize is the module that implements this,
hence why people who know of how and what Memoize can do favour that name.
Except that it's not necessarily obvious to everyone else?
cacheable is rather long and sufficiently made up that my copy of ispell
doesn't recognise it. But at least all English speakers can agree how to
spell words that don't end in i[zs]e (or end ou?r or [cs]e :-)

Nicholas Clark

Paul Johnson

unread,
Nov 8, 2002, 11:30:00 AM11/8/02
to Nicholas Clark, Damian Conway, perl6-l...@perl.org
On Fri, Nov 08, 2002 at 03:04:16PM +0000, Nicholas Clark wrote:
> On Fri, Nov 08, 2002 at 08:22:17PM +1100, Damian Conway wrote:
> > The name of the property is still under debate. Larry favours:
> >
> > sub square ( Num $n ) is same {...}
> >
> > whereas others feel that:
> >
> > sub square ( Num $n ) is memoized {...}
> >
> > is more appropriate.
>
> We're looking for a word that tersely expresses has_no_side_effects_and_can_safely_have_its_results_cached_based_on_parameter_types_and_values_and_calling_context ?

The functional programmers will tell you that word would be "pure".
Might confuse C++ types, but I think fortran uses it in this context.

> And to people in the perl5 know, Memoize is the module that implements this,
> hence why people who know of how and what Memoize can do favour that name.
> Except that it's not necessarily obvious to everyone else?

I have to admit that I find "memoize" to be a horrible word. The first
time I saw it I thought there was an "r" missing.

> cacheable is rather long and sufficiently made up that my copy of ispell
> doesn't recognise it. But at least all English speakers can agree how to
> spell words that don't end in i[zs]e (or end ou?r or [cs]e :-)

Quite.

--
Paul Johnson - pa...@pjcj.net
http://www.pjcj.net

Luke Palmer

unread,
Nov 8, 2002, 2:12:53 PM11/8/02
to ni...@ccl4.org, dam...@conway.org, perl6-l...@perl.org
> Date: Fri, 8 Nov 2002 15:04:16 +0000
> From: Nicholas Clark <ni...@ccl4.org>

>
> And to people in the perl5 know, Memoize is the module that implements this,
> hence why people who know of how and what Memoize can do favour that name.
> Except that it's not necessarily obvious to everyone else?
> cacheable is rather long and sufficiently made up that my copy of ispell
> doesn't recognise it. But at least all English speakers can agree how to
> spell words that don't end in i[zs]e (or end ou?r or [cs]e :-)

What's wrong with C<cached>?

C<pure> ain't bad either, but it won't appeal to
non-mathematicians---even certain kinds of mathematicians.
Mathematica thinks a "pure" function is what we think of as an
"anonymous" sub. So I like C<cached>.

Luke

Brent Dax

unread,
Nov 8, 2002, 2:41:38 PM11/8/02
to Luke Palmer, ni...@ccl4.org, dam...@conway.org, perl6-l...@perl.org
Luke Palmer:
# What's wrong with C<cached>?
#
# C<pure> ain't bad either, but it won't appeal to
# non-mathematicians---even certain kinds of mathematicians.
# Mathematica thinks a "pure" function is what we think of as
# an "anonymous" sub. So I like C<cached>.

How about C<steady>, in an analogy to physics?

steady state
n. Physics

A stable condition that does not change over time or in which change in
one direction is continually balanced by change in another.

--Brent Dax <bren...@cpan.org>
@roles=map {"Parrot $_"} qw(embedding regexen Configure)

Wire telegraph is a kind of a very, very long cat. You pull his tail in
New York and his head is meowing in Los Angeles. And radio operates
exactly the same way. The only difference is that there is no cat.
--Albert Einstein (explaining radio)

Paul Johnson

unread,
Nov 8, 2002, 3:06:46 PM11/8/02
to Luke Palmer, ni...@ccl4.org, dam...@conway.org, perl6-l...@perl.org
On Fri, Nov 08, 2002 at 12:12:53PM -0700, Luke Palmer wrote:

> What's wrong with C<cached>?
>
> C<pure> ain't bad either, but it won't appeal to
> non-mathematicians---even certain kinds of mathematicians.
> Mathematica thinks a "pure" function is what we think of as an
> "anonymous" sub. So I like C<cached>.

Part of the reason I would prefer something like "pure" over something
like "cached" is because it describes the function rather than telling
the compiler how to deal with it. That feels better to me. It's
working at a higher level. Maybe the end result is the same, or maybe
there are other optimisations which can be made with "pure" functions.
It's a way of nailing down the contract on the function rather than
specifying implementation details.

Buddha Buck

unread,
Nov 8, 2002, 3:33:24 PM11/8/02
to du...@pobox.com, Paul Johnson, Nicholas Clark, Damian Conway, perl6-l...@perl.org
Jonathan Scott Duff wrote:

> On Fri, Nov 08, 2002 at 05:30:00PM +0100, Paul Johnson wrote:
>
>>On Fri, Nov 08, 2002 at 03:04:16PM +0000, Nicholas Clark wrote:
>>
>>>On Fri, Nov 08, 2002 at 08:22:17PM +1100, Damian Conway wrote:
>>>
>>>>The name of the property is still under debate. Larry favours:
>>>>
>>>> sub square ( Num $n ) is same {...}
>>>>
>>>>whereas others feel that:
>>>>
>>>> sub square ( Num $n ) is memoized {...}
>>>>
>>>>is more appropriate.
>>>
>>>We're looking for a word that tersely expresses has_no_side_effects_and_can_safely_have_its_results_cached_based_on_parameter_types_and_values_and_calling_context ?
>>
>>The functional programmers will tell you that word would be "pure".
>
>
> I like "memoize" only because perl has made me used to the term.
> But "pure" works too.

To me, "pure" described the function, but it doesn't imply any
optimization. "cached" or "memoized" implies optimization.

sub fib1(int $x) is pure {
return 1 if $x < 2;
return fib1($x-1) + fib($x-2);
}

print time { fib1(1000); };
print time { fib1(1000); };

could print the same time for both operations.

sub fib2(int $x) is memoize { fib1($x); }

print time { fib2(1000); };
print time { fib2(1000); };

should return a long time for the first call, and a very short time for
the second call.

Actually, I can think of another use for 'pure', as an optimization hint.

sub foo {
for 1..1_000_000 -> {
an_impure_fibonacci($_);
}
return 10;
}

versus

sub bar {
for 1..1_000_000 -> {
a_pure_fibonacci($_);
}
return 10;
}

Both foo() and bar() return 10, and both do a similar amount of work
computing 1000000 fibonacci numbers. But I can see that the optimizer,
seeing that bar uses a pure version of fibonacci knows that it is
side-effect free, so optimizes sub bar {...} to the much faster

sub bar {10};

(I still don't understand the rules for when and where the semi is
expected).

I'm not sure that "memoize" works for that. Imagine:

sub opendb($dsn, $user, $password) is memoize { ... };

>
> -Scott

Jonathan Scott Duff

unread,
Nov 8, 2002, 3:15:09 PM11/8/02
to Paul Johnson, Nicholas Clark, Damian Conway, perl6-l...@perl.org
On Fri, Nov 08, 2002 at 05:30:00PM +0100, Paul Johnson wrote:
> On Fri, Nov 08, 2002 at 03:04:16PM +0000, Nicholas Clark wrote:
> > On Fri, Nov 08, 2002 at 08:22:17PM +1100, Damian Conway wrote:
> > > The name of the property is still under debate. Larry favours:
> > >
> > > sub square ( Num $n ) is same {...}
> > >
> > > whereas others feel that:
> > >
> > > sub square ( Num $n ) is memoized {...}
> > >
> > > is more appropriate.
> >
> > We're looking for a word that tersely expresses has_no_side_effects_and_can_safely_have_its_results_cached_based_on_parameter_types_and_values_and_calling_context ?
>
> The functional programmers will tell you that word would be "pure".

I like "memoize" only because perl has made me used to the term.
But "pure" works too.

-Scott
--
Jonathan Scott Duff
du...@cbi.tamucc.edu

Nicholas Clark

unread,
Nov 8, 2002, 3:21:49 PM11/8/02
to Brent Dax, Luke Palmer, ni...@ccl4.org, dam...@conway.org, perl6-l...@perl.org
On Fri, Nov 08, 2002 at 11:41:38AM -0800, Brent Dax wrote:
> Luke Palmer:
> # What's wrong with C<cached>?
> #
> # C<pure> ain't bad either, but it won't appeal to
> # non-mathematicians---even certain kinds of mathematicians.
> # Mathematica thinks a "pure" function is what we think of as
> # an "anonymous" sub. So I like C<cached>.
>
> How about C<steady>, in an analogy to physics?
>
> steady state
> n. Physics
>
> A stable condition that does not change over time or in which change in
> one direction is continually balanced by change in another.

steady - a physics term
cached - a software term

I think I prefer the software term

1: more likely that people will know what it means
2: in the words of the adverts of a certain UK varnish manufacturer:
"cached - does exactly what it says on the tin"

Nicholas Clark
--
COBOL better than perl? http://www.perl.org/advocacy/spoofathon/

Adam D. Lopresto

unread,
Nov 8, 2002, 10:03:14 AM11/8/02
to Damian Conway, perl6-l...@perl.org
I still prefer "cached", which sounds less lingo-ish than "memoized" but reads
better than "same" ("Same as what?").

--
Adam Lopresto (ad...@cec.wustl.edu)
http://cec.wustl.edu/~adam/

"I cannot read the fiery letters," said Frodo in a quavering voice
"No," said Gandalf. "But I can. The letters are Elvish, of an ancient mode,
but the language is that of Laywers, which I will not utter here. But this in
the Common Tongue is what is said, close enough:

If at any time you are not completely satisfied with your One Ring product,
return it to its point of manufacture at the Cracks of Doom, in the Land of
Mordor, where the Shadows lie, for a full refund."

Piers Cawley

unread,
Nov 8, 2002, 5:25:11 PM11/8/02
to Paul Johnson, Luke Palmer, ni...@ccl4.org, dam...@conway.org, perl6-l...@perl.org
Paul Johnson <pa...@pjcj.net> writes:

This man is right. Listen to him. After all, if functions get labelled
as 'pure' one could potentially write:

package MemoizePureFuncs {
sub import($package) {
for $package.functions -> $func {
Memoize::memoize($func) if $func.attribs{pure};
}
}
}

Or any other optimization you think is worth applying to all pure
functions.

Michael Lazzaro

unread,
Nov 8, 2002, 5:36:41 PM11/8/02
to Adam D. Lopresto, perl6-l...@perl.org

On Friday, November 8, 2002, at 07:03 AM, Adam D. Lopresto wrote:
> I still prefer "cached", which sounds less lingo-ish than "memoized"
> but reads
> better than "same" ("Same as what?").

Insert obligatory reference to Eiffel here, which IIR uses the word
"once":

sub square ( Num $n ) is same { ... }

sub square ( Num $n ) is pure { ... }
sub square ( Num $n ) is once { ... }
sub square ( Num $n ) is cached { ... }


sub square ( Num $n ) is memoized { ... }

MikeL

Damian Conway

unread,
Nov 11, 2002, 5:03:49 AM11/11/02
to perl6-l...@perl.org
Nicholas Clark wrote:

> We're looking for a word that tersely expresses
> has_no_side_effects_and_can_safely_have_its_results_cached_based_on_parameter_types_
> and_values_and_calling_context ?
>
> And to people in the perl5 know, Memoize is the module that implements this,
> hence why people who know of how and what Memoize can do favour that name.
> Except that it's not necessarily obvious to everyone else?
> cacheable is rather long and sufficiently made up that my copy of ispell
> doesn't recognise it. But at least all English speakers can agree how to
> spell words that don't end in i[zs]e (or end ou?r or [cs]e :-)

Except, of course, that many (near-)English speakers would be tempted to
spell your suggestion "cachable".

Hence I suspect that "cached" might be better. Then we will only have to
contend with those few remaining Romantic poets who will want to write
it "cachéd". ;-)

Damian

Damian Conway

unread,
Nov 11, 2002, 5:19:03 AM11/11/02
to perl6-l...@perl.org
Paul Johnson wrote:

> Part of the reason I would prefer something like "pure" over something
> like "cached" is because it describes the function rather than telling
> the compiler how to deal with it. That feels better to me. It's
> working at a higher level. Maybe the end result is the same, or maybe
> there are other optimisations which can be made with "pure" functions.
> It's a way of nailing down the contract on the function rather than
> specifying implementation details.

I can certainly see your point, but to me this is disquieteningly
reminiscent of the horror that is C<const> in C++ methods. Because,
if you're serious about C<pure> meaning "pure" in the mathematical
sense, then C<pure> subs can't access globals or C<caller>,
can't have C<rw> parameters, and call non-C<pure> subroutines.

One of the reasons I like C<cached> is because it does specify
exactly the way the subroutine is to behave (i.e. be called the first time,
and not called every subsequent time the same arguments are supplied). So
I can do nasty^H^H^H^H^Hhandy things like giving the sub side-effects, in
the sure knowledge that they won't be invoked more than once.

With C<pure> I can never be sure what optimizations the compiler is
or isn't going to make, or even whether those optimzations will be the
same from platform to platform [*]. So I can never be sure what the
precise behaviour of my sub will be. :-(

Damian

[*] I can easily imagine architectures under which re-calling a particular
pure function is actually faster than retrieving a previously cached
result.


Michael Lazzaro

unread,
Nov 11, 2002, 12:44:37 PM11/11/02
to Damian Conway, perl6-l...@perl.org

On Monday, November 11, 2002, at 02:19 AM, Damian Conway wrote:
> One of the reasons I like C<cached> is because it does specify
> exactly the way the subroutine is to behave (i.e. be called the first
> time,
> and not called every subsequent time the same arguments are supplied).
> So
> I can do nasty^H^H^H^H^Hhandy things like giving the sub side-effects,
> in
> the sure knowledge that they won't be invoked more than once.
>
> With C<pure> I can never be sure what optimizations the compiler is
> or isn't going to make, or even whether those optimzations will be the
> same from platform to platform [*]. So I can never be sure what the
> precise behaviour of my sub will be. :-(

Amen. The more abstract or metaphorical the name, the more difficult
it is to be really sure of what it does. Of the choices, "cached"
seems by far the most self-explanatory. If we used "pure", we'd have
to teach people what "pure" means, which would be much harder than
teaching them what "cached" means.

MikeL

Piers Cawley

unread,
Nov 12, 2002, 4:03:22 PM11/12/02
to Damian Conway, perl6-l...@perl.org
Damian Conway <dam...@conway.org> writes:

> Luke Palmer wrote:
>
>
>> sub a_pure_func(Num $n) returns Num {
>> class is Num {
>> method FETCH { $n * $n } }.new }
>> Yes? No?
>
> Not quite.
>
>
> > sub a_pure_func(Num $n) returns Num {
> > class is Num {
> > has Num $cache;
> > method FETCH { $cache //= $n * $n } } }
>
>
> Still not quite.
>
> You don't want a C<FETCH> method (which won't be called unless the
> object somehow becomes the implementation of a tied variable).
>
> What you want are conversion-to-(num|str|bool) methods:
>
> sub a_pure_func(Num $n) returns Num {
> class is Num {
> has Num $cache;
> sub value { $n * $n }
> method operator:+ ($self:) { +($cache //= value ) }
> method operator:~ ($self:) { ~($cache //= value ) }
> method operator:? ($self:) { ?($cache //= value ) }
> }.new
> }

So, we'd have 'is lazy' do something like the following to the
declared sub?

sub make_lazy(&func) {
my $new_func = {
&func.returns.make_deferred_object( &func, *@_ }
};
$new_func.signature(&func.signature);
return $new_func;
}

And then, say:

class Object {
method make_deferred_object($class is Class : &func, *@args) {
class is $class {
has $class $cache;
sub value { &func(*@args) }
method operator:+ { +($cache //= value) }
method operator:~ { ~($cache //= value) }
method operator:? { ?($cache //= value) }
}.new
}
}

Which is somewhat dependent on being able to do C<class is $class>. If
that's not possible then I'd hope you could do something like:

given my $anon_class = Class.new {
my $cache;
.isa($class);
.add_sub 'value' => { &func(*@args) }
.add_method 'operator:+' => {...}
.add_method 'operator:~' => {...}
.add_method 'operator:?' => {...}
return .new;
}

Hang on, couldn't you rewrite things to not use the cache?

class is $class {
sub value { &func(*@args) }
method operator:+ ($self is rw:) { +($self = value) }
method operator:~ ($self is rw:) { ~($self = value) }
method operator:? ($self is rw:) { ?($self = value) }
}.new

I don't know if I hope that works or hope it fails miserably.

Also note that, if you were feeling sufficiently lazy with numbers,
you could define the set of binary operators for your deferred
numbers:

method operator:+ ($self: Num $other) is lazy { +($self) + $other }
method operator:* ($self: Num $other) is lazy { +($self) * $other }
method operator:/ ($self: Num $other) is lazy { +($self) / $other }
method operator:- ($self: Num $other) is lazy { +($self) - $other }

Or would that just be evil, Bad And Wrong?

Piers Cawley

unread,
Nov 12, 2002, 4:11:36 PM11/12/02
to Michael Lazzaro, Adam D. Lopresto, perl6-l...@perl.org
Michael Lazzaro <mlaz...@cognitivity.com> writes:

Having said I prefer 'pure', on further consideration I like cached,
but I think there's still a place for 'pure', but probably not as a
core property.

Paul Johnson

unread,
Nov 12, 2002, 5:33:03 PM11/12/02
to Michael Lazzaro, Damian Conway, perl6-l...@perl.org
[ I've added some of Damian's text back into Michael's message to save
replying to two separate messages. ]

On Mon, Nov 11, 2002 at 09:44:37AM -0800, Michael Lazzaro wrote:
> On Monday, November 11, 2002, at 02:19 AM, Damian Conway wrote:

> > I can certainly see your point, but to me this is disquieteningly
> > reminiscent of the horror that is C<const> in C++ methods. Because,

Yes, there are those overtones. You can never retrofit purity.

> > if you're serious about C<pure> meaning "pure" in the mathematical
> > sense, then C<pure> subs can't access globals or C<caller>, can't
> > have C<rw> parameters, and call non-C<pure> subroutines.

Yes, unless "pure" really means "pure enough".

> > One of the reasons I like C<cached> is because it does specify
> > exactly the way the subroutine is to behave (i.e. be called the
> > first time, and not called every subsequent time the same arguments
> > are supplied). So I can do nasty^H^H^H^H^Hhandy things like giving
> > the sub side-effects, in the sure knowledge that they won't be
> > invoked more than once.

I think I agree that if you want to give perl a hint about how to
optimise your program, and you want to specify that the results of
calling a function should be cached, then "cached" seems the best way to
do that.

> > With C<pure> I can never be sure what optimizations the compiler is
> > or isn't going to make, or even whether those optimzations will be
> > the same from platform to platform [*]. So I can never be sure what
> > the precise behaviour of my sub will be. :-(

I would say that would be the whole point of "pure". If you declare a
function to be "pure" (and you're telling the truth), then when and how
often that function is called should have no bearing on the output of
the program, except maybe for when it appears. The function could be
cached, optimised away, farmed out to one of the 63 processors you're
not using or be optimised in any number of helpful ways.

Having said all that, I'm not overly wedded to the idea. It seems
useful, but so does actually specifying "cached". I'm not convinced
that either has to be a part of the core language to be useful.

In fact, I only poked my head up because I knew the answer to Nick's
question :-)

> Amen. The more abstract or metaphorical the name, the more difficult
> it is to be really sure of what it does. Of the choices, "cached"
> seems by far the most self-explanatory. If we used "pure", we'd have
> to teach people what "pure" means, which would be much harder than
> teaching them what "cached" means.

A "pure" function may be run zero, one or more times every time you call
it. And every time you don't. ;-)

[ I notice that Piers has just said about the same as me in one sentence. ]

Piers Cawley

unread,
Nov 13, 2002, 1:09:01 AM11/13/02
to Paul Johnson, Michael Lazzaro, Damian Conway, perl6-l...@perl.org
Paul Johnson <pa...@pjcj.net> writes:
> [ I notice that Piers has just said about the same as me in one
sentence. ]

Ah, but I get lots of practice boiling stuff down when I'm writing the
summaries. Though the current one is still giving me headaches -- I'm
about halfway through perl6-language and I've not even started on
perl6-documentation.

Peter Haworth

unread,
Nov 13, 2002, 9:06:29 AM11/13/02
to Piers Cawley, Michael Lazzaro, Adam D. Lopresto, perl6-l...@perl.org
On Tue, 12 Nov 2002 21:11:36 +0000, Piers Cawley wrote:
> Michael Lazzaro <mlaz...@cognitivity.com> writes:
> > On Friday, November 8, 2002, at 07:03 AM, Adam D. Lopresto wrote:
> >> I still prefer "cached", which sounds less lingo-ish than "memoized"
> >> but reads better than "same" ("Same as what?").
> >
> > Insert obligatory reference to Eiffel here, which IIR uses the word
> > "once":

But that means "once per system", not "once per unique argument list".

--
Peter Haworth p...@edison.ioppublishing.com
Interesting trivia: If you took all the sand in North Africa and spread
it out... it would cover the Sahara desert.

Larry Wall

unread,
Nov 13, 2002, 2:39:16 PM11/13/02
to Piers Cawley, Damian Conway, perl6-l...@perl.org
On Tue, Nov 12, 2002 at 09:03:22PM +0000, Piers Cawley wrote:
: Hang on, couldn't you rewrite things to not use the cache?

:
: class is $class {
: sub value { &func(*@args) }
: method operator:+ ($self is rw:) { +($self = value) }
: method operator:~ ($self is rw:) { ~($self = value) }
: method operator:? ($self is rw:) { ?($self = value) }
: }.new
:
: I don't know if I hope that works or hope it fails miserably.
:
: Also note that, if you were feeling sufficiently lazy with numbers,
: you could define the set of binary operators for your deferred
: numbers:
:
: method operator:+ ($self: Num $other) is lazy { +($self) + $other }
: method operator:* ($self: Num $other) is lazy { +($self) * $other }
: method operator:/ ($self: Num $other) is lazy { +($self) / $other }
: method operator:- ($self: Num $other) is lazy { +($self) - $other }
:
: Or would that just be evil, Bad And Wrong?

I believe the correct term is "opaque". And I don't mean that
in the good sense...

Larry

Larry Wall

unread,
Nov 13, 2002, 2:26:27 PM11/13/02
to Damian Conway, perl6-l...@perl.org
On Fri, Nov 08, 2002 at 08:35:00PM +1100, Damian Conway wrote:
: What you want are conversion-to-(num|str|bool) methods:

:
: sub a_pure_func(Num $n) returns Num {
: class is Num {
: has Num $cache;
: sub value { $n * $n }
: method operator:+ ($self:) { +($cache //= value ) }
: method operator:~ ($self:) { ~($cache //= value ) }
: method operator:? ($self:) { ?($cache //= value ) }
: }.new
: }

Just a nit, but those are probably prefix: rather than operator:, since
we may need more clues than just the arguments to distinguish:

prefix:
infix:
postfix:
circumfix: (or should that really be outfix:?)

Larry

Damian Conway

unread,
Nov 16, 2002, 4:33:39 PM11/16/02
to perl6-l...@perl.org
Piers Cawley wrote:

[Speculations elided]

> Which is somewhat dependent on being able to do C<class is $class>.

Which you can't do, since C<is> is compile-time.


Damian

Piers Cawley

unread,
Nov 20, 2002, 4:07:51 AM11/20/02
to Damian Conway, perl6-l...@perl.org
Damian Conway <dam...@conway.org> writes:

So, how would one create a class which inherits from some other class
when you don't know what said other class is until runtime? Does this work:

class {
push @ISA, $class;
...
}

Admittedly it's not something you'd want to do often (though I have
done something like it several times in Perl 5...), but it's really
handy to be able to.

Damian Conway

unread,
Nov 20, 2002, 8:42:35 PM11/20/02
to perl6 >> "perl6-language@perl.org"
Piers Cawley wrote:

>> C<is> is compile-time.
>
> So, how would one create a class which inherits from some other class
> when you don't know what said other class is until runtime?

Use Perl5-ish classes, or an C<eval>.


> Does this work:
>
> class {
> push @ISA, $class;
> ...
> }

I sincerely hope not!

Damian

Brent Dax

unread,
Nov 20, 2002, 9:53:01 PM11/20/02
to Piers Cawley, Damian Conway, perl6-l...@perl.org
Piers Cawley:
# So, how would one create a class which inherits from some
# other class when you don't know what said other class is
# until runtime?

AUTOLOAD! *ducks*

--Brent Dax <bren...@cpan.org>
@roles=map {"Parrot $_"} qw(embedding regexen Configure)

"If you want to propagate an outrageously evil idea, your conclusion
must be brazenly clear, but your proof unintelligible."
--Ayn Rand, explaining how today's philosophies came to be

Piers Cawley

unread,
Nov 21, 2002, 7:01:27 AM11/21/02
to Damian Conway, perl6 >> "perl6-language@perl.org"
Damian Conway <dam...@conway.org> writes:

> Piers Cawley wrote:
>
>>> C<is> is compile-time.
>> So, how would one create a class which inherits from some other
>> class
>> when you don't know what said other class is until runtime?
>
> Use Perl5-ish classes, or an C<eval>.

Perl5-ish classes? You mean 'bless {}, Foo' is still going to work?
Frankly, I find that scary.

And eval is such a hackish way of doing this kind of malarkey.


>> Does this work:
>> class { push @ISA, $class;
>> ...
>> }
>
> I sincerely hope not!

Okay, assuming that a class definition is actually an instance of the
Class class, please tell me I can do:

Class.new( isa => $class ) {
method { ... }
method { ... }
}.new

Hmm... a constructor with an optional block... that looks scary, but
good scary.

0 new messages