Maybe referentially transparent proxy object


Inherits from: Object : AbstractFunction : Ref


A Maybe object can contain either nil or some other object, and allows to construct calculations without knowing this other object yet. If the calculation fails, due to a loop or a not yet defined object, Maybe returns nil.


The name Maybe stems from the programming language Haskell, where it represents a somewhat similar entity. See also: Fdef


Overview: JITLib




*new(object)

create a new instance

object - an object or nil.

// example:

a = Maybe.new;

b = Maybe(a + 6);

b.value; // => nil

a.value = 1;

b.value; // => 7


source

return the contained object

source_(obj)

set the contained object

value_(obj)

set the contained object

value(arg1, arg2...)

return the source, or the value of the contained object, if it is a Maybe.

If there is a recursion, return nil.

apply(arg1, arg2...)

return the value, or the value of the contained object, if it is a Maybe.

This method allows recursion, so that recursive calcualtions can be made.

doesNotUnderstand(selector, ... args) (called by any message that Maybe doesn't understand)

returns a composition function that, when evaluated, returns the value.

// example:

a = Maybe.new;

a.respondsTo(\flop) // false: Maybe constructs a placeholder instead

b = Maybe(a.flop);

b.value; // => nil

a.value = [1, 2, [2, 3]];

b.value; // => [ [ 1, 2, 2 ], [ 1, 2, 3 ] ]




// the following examples use a LazyEnvir with a Maybe as a proxy class.

// instead of writing a = Maybe.new; a.value = something; 

// one can simply write ~a = something.

// the Maybe is implictly created for you.


(

p.pop.clear;

p = LazyEnvir.new;

p.proxyClass = Maybe;

p.linkDoc; // here: connect to current doc only.

);



// sets

~a = Set[0, 4, 5, 7];

~b = Set[4, 5];

~c = ~a union: ~b; // union of the two sets (note that the shortcut | does not work here.). 

~d = ~a sect: ~b; // intersection of a and b

~c.postcs;""; // post the whole construction

~d.postcs;"";

~c.value; // Set[ 4, 0, 5, 7 ]

~d.value; // Set[ 4, 5 ]

~b = Set[4, 5, 13, 0];

~c.value;

~d.value; // Set[ 4, 0, 5 ]

~b.source.add(~w); // add another placeholder

~c.value; // it is part of the union.

~d.value; // but not part of the intersection



// envirs

~a = (note: [1, 2]);

~b = (dur: 1);

~c = ~a.putAll(~b) // provisionally put everything into the placholder 

~c.value;

~a = (note: [1, 2, 4]);

~c.value;

~d = ~a.at(\note);

~d.value;

~a = (note: [7.5]);

~d.value; // [7.5]


// patterns

~a = Pseq([1, 2, 3]);

~b = Pseq([5, ~a, ~a + 10], inf);

~b.value.asStream.nextN(10);



~a = Prand([100, 200]);

~b.value.asStream.nextN(10);



// to do : flop!


//////////////// deep recursion


// with normal functions:

f = { |x| if(x <= 1) { 1 } { x * f.(x - 1) } };

f.(12)



~faculty = { |x| if(x == 1) { 1 } { x * ~faculty.(x - 1) } };

~faculty.(12) // doesn't work (=> nil). here we _do_ want recursion ...


// for explicit recursion use "apply"

~faculty = { |x| if(x == 1) { 1 } { x * ~faculty.apply(x - 1) } };

~faculty.(12)


/*// safety (not yet implemented)

Maybe.maxDepth = 1e2; // higher depth is risky..

~faculty = { |x|  x * ~faculty.apply(x - 1)  }; // infinite recursion

~faculty.(12)


Maybe.maxDepth = nil; // unsafe again.*/



//////////////// recursion prevention tests


~b = ~a;

~a = ~b;

~a.value; // => nil



~a = ~b;

~b = ~c;

~c = ~a;

~a.value; // => nil


~a = ~b + ~c;

~c = ~a;

~a.value; // => nil



~a = ~b;

~b = 19;

~a.value; // => 19

~b.value; // => 19


// function evaluation and argument passing


~a = { |x| x + 2 };

~a.value;  // => nil


~a.value(~c);  // => nil

~b = 2000;

~a.value(~b); // => 2002

~x = [600, 1000];


(~a + 1).value(~b); // 2003

(~a + 1).value(~x); // [ 603, 1003 ]

(~a + 1).value({ 8 }); // binary op func.

(~a + 1).value({ 5 + 3 }).value // 11


~a = { |x| x + 2 + ~b };

~a.value(8); // 2010


~c = nil;

~a = { |x|  x + 2 + ~c }; // ~c is undefined.

~a.value(8); // => nil


~c = 100; // define ~c


~a.value(8); // now returns a value.


~c = ~b; // now recursion?

~b = ~a;

~a.value(8); // caught recursion  => nil


~c = { 100.rand }; // ~c is a function


~a.value(8);

~a.value(8);


~c = { ~a + ~b };

~a.value(8); // ~c is a recursion with ~a  => nil



// function composition

~a = {|x| x + 1 };

~v = ~a <> ~a <> ~a; // same as: { ~a.(~a.(~a)) }

~v.value(0); // => 3


~a = {|x| x + 2 };

~v.value(0); // transparent.  => 6


// {|x| x }.valueEnvir // doesn't work with current implementation of Function:valueEnvir



// calculations with functions:

~c = 0;

~a = { |ff| { ff = ff + 1; ~c + ff + 2 + ~c } };

~x = ~a.value(8);

~x.value; // return 11, 12, 13...

~x.value;

~x.value; 

~c = 100;

~x.value; // return 214, 215 ...

~x.value;


// binary op functions:

~c = 0;

~a = { |ff| { [600, 800] } + { ff + 2 + ~c } };


~x = ~a.value(8);

~x.value; // return [ 610, 810 ]


~c = { [10, -10].rand };

~x.value; // return random between [ 610..620, 800..810 ]