Objective-C Like ScaLa

新感覚アドベントカレンダーLL/ML Advent Calendar 2012 (#LLAdventJP) の13日目

Objective-Cを書いているとどうしても長くなってしまうので、Scalaくらい短く書きたい。というわけでいろいろな方法を使って短くしたいと思います、FizzBuzzを。

理想

1 to 100 map { i =>
  (i%3, i%5) match {
    case (0, 0) => "FizzBuzz"
    case (0, _) => "Fizz"
    case (_, 0) => "Buzz"
    case _ => i.toString
  }
} foreach println

Objective-Cだと普通はこんなかんじでしょう

for (NSInteger i = 1 ; i <= 100; i ++) {
    if (i % 15 == 0) {
        NSLog(@"FizzBuzz");
    } else if (i % 3 == 0) {
        NSLog(@"Fizz");
    } else if (i % 5 == 0) {
        NSLog(@"Buzz");
    } else {
        NSLog(@"%d", i);
    }
}

NSLogが複数あるのを一つにする。@(i)でNSNumberのObjectにすることができる。
NSIntegerが長いので省略

typedef NSInteger Int;

for (Int i = 1 ; i <= 100; i ++) {
    NSLog(@"%@",
        (i % 15 == 0)? @"FizzBuzz" :
        (i % 3 == 0)? @"Fizz" :
        (i % 5 == 0)? @"Buzz" :
        [@(i) stringValue]
    );
}

Categoryという機能を使って既存のclassにメソッドを追加することができます。
NSArrayにmapとforeachのmethodを追加します。

@interface NSArray (Fanctional)

- (NSArray *(^)(id (^)(id)))map;
- (void (^)(void (^func)(id)))foreach;
@end

@implementation NSArray (Fanctional)

- (NSArray *(^)(id (^func)(id)))map {
    return ^(id (^func)(id)){
        NSMutableArray *array = [NSMutableArray array];
        for (Int i = 0, _len = [self count]; i < _len; i++) {
            array[i] = func(self[i]);
        }
        return array;
    };
}
- (void (^)(void (^)(id)))foreach {
    return ^(void (^func)(id)){
        for (Int i = 0, _len = [self count]; i < _len; i++) {
            func(self[i]);
        }
    };
}
@end
NSMutableArray *ma = [NSMutableArray new];
for (Int i = 0 ; i < 100; i ++) {
    ma[i] = @(i + 1);
}
ma.map(^(id n) {
    Int i = [n integerValue];
    return
        (i % 15 == 0)? @"FizzBuzz" :
        (i % 3 == 0)? @"Fizz" :
        (i % 5 == 0)? @"Buzz" :
        [@(i) stringValue];
}).foreach(^(id s){NSLog(@"%@",s);});

NSNumbarにtoメソッドを追加する

@interface NSNumber (Fanctional)

- (NSArray *(^)(Int))to;

@end

@implementation NSNumber (Fanctional)

- (NSArray *(^)(Int))to {
    return ^(Int to){
        NSMutableArray *ma = [NSMutableArray array];
        Int i = 0, from = [self integerValue];
        to -= from;
        for (; i <= to ; i++) {
            ma[i] = @(i + from);
        }
        return ma;
    };
}

@end
@(1).to(100).map(^(id n) {
    Int i = [n integerValue];
    return
        (i % 15 == 0)? @"FizzBuzz" :
        (i % 3 == 0)? @"Fizz" :
        (i % 5 == 0)? @"Buzz" :
        [@(i) stringValue];
}).foreach(^(id s){NSLog(@"%@",s);});

パターンマッチを実装したいところですが、すでに13日がなくなっているのでこの辺にしておきます。

そもそも理想が間違ってるとかいうな