2011-05-09 9 views
6

En SML, la siguiente es posible para el modelado de la programación perezoso,tipos de datos perezosos en Objective C

// 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) 

Sé que los cierres se pueden escribir con Blocks,

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

así que creo que puedo usar como un argumento de función. El siguiente paso sería cómo usar funciones sin argumentos reales (unit value, por ejemplo, en SML fn() =>) y crear tipos de datos perezosos como el anterior.

¿Es esto posible o debería seguir una forma más obvia?

El objetivo final sería para emular el comportamiento de cálculo suspendido del SML,

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

donde la fuerza (x) es

fun force (Susp(f)) = f() 

Respuesta

5

cuestión fresco!

Usted podría implementar un contenedor de perezoso en Objective-C de la siguiente manera (pero probablemente no debería, véase más adelante):

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 

Eso es un montón de repetitivo, pero lo que sea. A continuación, se puede utilizar de esta manera:

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

Pero eso es todo bastante tonto, ya que para lo que está haciendo, que realmente no es necesario otro tipo de datos. Sólo tiene que usar bloques como su tipo de datos:

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

Esa es una forma mucho más compacta, idiomática de hacer las cosas, y es lo que sugiero. A menos que necesite agregar más semántica a sus objetos perezosos que van más allá de las utilidades básicas de los bloques, no debe envolverlos innecesariamente.

¡Salud!

+1

Gracias, no sabía si podrías haber usado bloques y typedef así. Trataré de la última manera primero y si es necesario, trabajaré con la plantilla para artículos posteriores. – phwd