CARVIEW |
Every repository with this icon (

Every repository with this icon (

Description: | Functional APIs for Objective-C |
Clone URL: |
git://github.com/mogeneration/functionalkit.git
Give this clone URL to anyone.
git clone git://github.com/mogeneration/functionalkit.git
|
name | age | message | |
---|---|---|---|
![]() |
.gitignore | Mon Mar 16 04:29:08 -0700 2009 | Moving code over to functionalkit from motive. [tomjadams] |
![]() |
Etc/ | Sun Apr 05 19:31:24 -0700 2009 | Newtype generation. Now we have NewType8s [nkpart] |
![]() |
LICENCE | Mon Mar 16 04:29:08 -0700 2009 | Moving code over to functionalkit from motive. [tomjadams] |
![]() |
NOTICE | Wed Mar 18 22:34:47 -0700 2009 | Added euqlaus, hash, description, etc. [tomjadams] |
![]() |
README.markdown | Tue Apr 21 22:29:37 -0700 2009 | [nkpart] |
![]() |
Source/ | Tue May 12 19:40:50 -0700 2009 | Group by is now nil-safe: Wrapped functions tha... [tomjadams] |
![]() |
functionalkit.xcodeproj/ | Wed Apr 15 21:59:48 -0700 2009 | removed tests from main target [nkpart] |
FunctionalKit: It's Functional for Objective-C.
FunctionalKit is an attempt to use functional paradigms in Objective-C. It is a set of low level functional types & APIs. It contains types such as either, option, etc. that allow your to write correct, clean, tight, succinct and (where possible) typesafe code. It also provides more advanced concepts such as lifting functions into monads.
FunctionalKit is loosely modelled on Functional Java.
Setup
- Clone the project into your project somewhere, we use Source/External/functionalkit.
- Add the Source/Main directory into your Xcode project.
- Rock!
Examples
Function creation
Create a function from a selector.
id <FKFunction> doSomethingFunction = [FKFunction functionFromSelector:@selector(doSomething:) target:self];
Use a nested function (requires -fnested-functions):
// With -fnested-functions enabled. - (void)testDummy {
NSString *f(NSString *a) {
return [a substringToIndex:1];
}
NSDictionary *d = [NSARRAY(@"one", @"two", @"three") groupByKey:functionP(f)];
}
Mapping
Map across the elements of an array of names and turn them into people.
NSArray *names = [NSArray arrayWithObject:@"Fred", @"Mary", @"Pete", nil];
NSArray *people = [names map:[FKFunction functionFromSelector:@selector(makePersonFromName:) target:self]];
// Given each chapter has an array of pages
NSArray *chapters = ...;
int pageCount = [[NSArray concat:[chapters map:functionS(pages)]] count];
Nil values
Handle a possibly nil value safely.
NSDictionary *dict = ...;
FKOption *couldBeNil = [KFOption fromNil:[dict objectForKey:@"SomeKey"]];
Handling failures
Construct an either representing failure.
FKEither *failed = [FKEither errorWithReason:@"Credentials have not been saved"];
Perform an operation that may fail, apply a selector to the result if successful, otherwise on failure propagate the error.
MVEither *maybeResponse = [HttpApi makeRequestToUrl:@"https://www.foo.com/json-api"];
MVEither *maybeParsedJson = [maybeResponse.right mapWithSelector:@selector(JSONValue)];
Perform an operation that returns nil & an error on failue. Return the error on the left on failure or the returned object on the right.
NSError *error;
SBJSON *parser = [[SBJSON new] autorelease];
id parsedObject = [parser objectWithString:self error:&error];
FKEither maybeParsedObject = [[FKOption fromNil:parsedObject] toEither:error];
Validate parsed values, turn them into a domain model class on success
Note. This is a bit messy, could be cleaner.
FKOption *maybeTitle = [FKOption fromNil:[dictionary objectForKey:@"title"] ofType:[NSString class]];
FKOption *maybeOwnerName = [FKOption fromNil:[dictionary objectForKey:@"owner_name"] ofType:[NSString class]];
FKOption *maybeHeadlineImgId = [FKOption fromNil:[dictionary objectForKey:@"headline_img_id"] ofType:[NSString class]];
if ([NSARRAY(maybeTitle, maybeOwnerName, maybeHeadlineImgId) all:@selector(isSome)]) {
return [FKOption some:[FlickrGallery galleryWithTitle:[maybeTitle some] ownerName:[maybeOwnerName some] sampleImgId:[maybeHeadlineImgId some]]];
} else {
return [FKOption none];
}
Side effects
Comap a function with an effect, to have the function execute then perform a side effect using the function's result.
id <FKFunction> getPhotosF = [FKFunction functionFromSelector:@selector(photos)];
id <FKEffect> galleriesOp = [FKEffect comap:[self effectThatDoesSomethingWithPhotos] :getPhotosF];
Lifting
The following example lifts a function into the array monad, applying the function to each element of the array.
// Parse a photo's details out of a dictionary, return Some(FlickrPhoto) on success or None on failure.
- (FKOption *)parsePhotoForDictionary:(NSDictionary *)dictionary {
FKOption *maybeTitle = [FKOption fromNil:[dictionary objectForKey:@"title"] ofType:[NSString class]];
FKOption *maybeId = [FKOption fromNil:[dictionary objectForKey:@"photo_id"] ofType:[NSString class]];
if ([NSARRAY(maybeTitle, maybeId) all:@selector(isSome)]) {
return [FKOption some:[FlickrPhoto photoWithId:[maybeId some] title:[maybeTitle some]]];
} else {
return [FKOption none];
}
}
// Retrieve the array of photos.
FKOption *maybePhotos = [FKOption fromNil:[dictionary objectForKey:@"photos"] ofType:[NSArray class]];
// Still within the option monad, lift the parse function (above) into the array monad and map across the option.
id <FKFunction> parsePhotoF = [FKFunction functionFromSelector:@selector(parsePhotoForDictionary:) target:self];
FKOption *maybeParsedPhotos = [maybePhotos map:[NSArray liftFunction:parsePhotoF]];
Other Work
Here's some other work we know of that does similar things to FunctionalKit.