Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy datatypes in Objective C

In SML, the following is possible for modelling lazy programming,

// Have a datatype to wrap a computation
datatype 'a susp = Susp of (unit -> 'a)
// A function to hold the computation
fun delay(f ) = Susp(f)

I know that closures can be written using Blocks,

int multiplier = 7;
int (^myBlock)(int) = ^(int num) {
    return num * multiplier;
};

So I think I can use it as a function argument. The next step would be how to use functions with no real arguments ( unit value e.g. in SML fn () =>) and creating lazy datatypes as the one above.

Is this possible or should I be pursuing a different more obvious way ?

The end goal would be to emulate the suspended computation behaviour from SML,

let val x = Susp(fn () => horribleComp(345))
in 
   force(x) + force(x)
end

where force(x) is

fun force (Susp(f)) = f ()
like image 562
phwd Avatar asked May 09 '11 18:05

phwd


1 Answers

Cool question!

You could implement a lazy container in Objective-C as follows (but you probably shouldn't, see below):

typedef id (^SuspBlock)(void);

@interface Susp : NSObjecti
- (id)initWithBlock:(SuspBlock)block;
+ (id)withBlock:(SuspBlock)block;
- (id)force;
@end

// -----

@interface Susp ()
@property (nonatomic, copy) SuspBlock _block;
@end

@implementation Susp
@synthesize _block;

- (id)initWithBlock:(SuspBlock)block {
  self = [super init];
  if (self != nil) {
    self._block = block;
  }

  return self
}

+ (id)withBlock:(SuspBlock)block {
  return [[[self alloc] initWithBlock:bloc] autorelease];
}

- (id)force {
  return self._block();
}

- (void)dealloc {
 self._block = nil;
 [super dealloc];
}

@end

That's a lot of boilerplate, but whatever. Then, you could use it like this:

id x = [Susp withBlock:^{ return someComputation(); }];
id result = [[x force] plus:[x force]];
// assuming the result of your computation has -plus:

But that's all rather silly, since for what you're doing, you really don't need another data type. Just use blocks as your datatype:

typedef id (^SuspVal)(void);
SuspVal x = ^{ return complicatedThing; };
id result = [x() plus:x()];

That's a much more compact, idiomatic way of going about it, and it's what I suggest. Unless you need to add further semantics to your lazy objects that go beyond the basic utilities of blocks, you shouldn't wrap them needlessly.

Cheers!

like image 136
Jonathan Sterling Avatar answered Oct 17 '22 19:10

Jonathan Sterling