LoginSignup
5
4

More than 5 years have passed since last update.

HaxeのOptionをScalaっぽくする

Last updated at Posted at 2014-12-03

null書いたら負け。そんなあなたにオススメなのが、Optionです。

Optionを使うことで、nullの値を取る場合の処理が、いい感じに書けるのですが、如何せんhaxe.ds.Optionでは物足りなさを感じてしまいます。

そこで、HaxeのOptionをScalaのOptionっぽく使えるよう、拡張してみました。
ScalaのOptionのメソッドを全て実装するのは面倒なので、個人的に良く使うものを選んで実装しました。

ScalikeOptionクラスに、静的なメソッドを定義して、
あとはusingを使ってScalikeOptionのメソッドを呼ぶだけ、とても簡単。

import haxe.ds.Option;

using ScalikeOption;

class ScalikeOption {
    public static function isEmpty<T>(opt:Option<T>) {
        return switch(opt) {
            case Some(v): false;
            case None: true;
        }
    }

    public static function isDefined<T>(opt:Option<T>) {
        return !opt.isEmpty();
    }

    public static function getOrElse<T>(opt:Option<T>, defValue:T) {
        return switch(opt) {
            case Some(v): v;
            case None: defValue;
        }
    }

    public static function map<A, B>(opt:Option<A>, f:A -> B) {
        return switch (opt) {
            case Some(v): Some(f(v));
            case None: opt;
        }
    }

    public static function fold<A, B>(opt:Option<A>, defValue:B, f:A -> B) {
        return opt.map(f).getOrElse(defValue);
    }

    public static function iter<A>(opt:Option<A>, f:A -> Void) {
        switch(opt) {
            case Some(v): f(v);
            case None: 
        }
    }

    public static function flatten<T>(opt:Option<Option<T>>) {
        return switch (opt) {
            case Some(v): v;
            case None: None;
        }   
    }

    public static function flatMap<A, B>(opt:Option<A>, f:A -> Option<B>) {
        return switch (opt) {
            case Some(v): 
                switch(f(v)) {
                    case Some(w): Some(w);
                    case None: None;
                }
            case None: None;
        }      
    }
} 

ScalaのOption.foreachは値を返さず副作用のみなのに対して、HaxeのLambda.foreachはBool値を返すので、ちょっと違います。Haxeで値を返さず副作用のみを取るのは、Lambda.iterなので、それにならい、ScalaのOption.foreachに対応するメソッドはScalikeOption.iterとしました。

ScalaのOption.getは、個人的に使っちゃいけないものだと思っているので、追加しませんでした。

使い方はこちら

import haxe.ds.Option;

using ScalikeOption;

class Sample {
    static var s = Some(1);
    static var n = None;
    static var ss = Some(s);
    static var sn = Some(n);

    public static function main(){
        trace("Some.getOrElse(0): " + s.getOrElse(0));
        trace("None.getOrElse(0): " + n.getOrElse(0));
        trace("Some.isEmpty: " + s.isEmpty());
        trace("None.isEmpty: " + n.isEmpty());
        trace("Some.isDefined: " + s.isDefined());
        trace("None.isDefined: " + n.isDefined());
        trace("Some.map: " + s.map(function(a) { return a * 10;}));
        trace("None.map: " + n.map(function(a) { return a * 10;}));
        trace("Some.fold: " + s.fold(99, function(a) { return a *10;}));
        trace("None.fold: " + n.fold(99, function(a) { return a *10;}));
        s.iter(function(a) { trace("Some.iter: " + a); });
        n.iter(function(a) { trace("None.iter: " + a); });
        trace("Some(Some).flatten: " + ss.flatten());
        trace("Some(None).flatten: " + sn.flatten());
        trace("Some.flatMap: " + s.flatMap(function(a) { if(a == 1) { return Some("one"); } else { return None;} }));
        trace("None.flatMap: " + n.flatMap(function(a) { if(a == 1) { return Some("one"); } else { return None;} }));
    }
}

ihxでこれを実行すると、

>> Sample.main(); 
Sample.hx:12: Some.getOrElse(0): 1
Sample.hx:13: None.getOrElse(0): 0
Sample.hx:14: Some.isEmpty: false
Sample.hx:15: None.isEmpty: true
Sample.hx:16: Some.isDefined: true
Sample.hx:17: None.isDefined: false
Sample.hx:18: Some.map: Some(10)
Sample.hx:19: None.map: None
Sample.hx:20: Some.fold: 10
Sample.hx:21: None.fold: 99
Sample.hx:22: Some.iter: 1
Sample.hx:24: Some(Some).flatten: Some(1)
Sample.hx:25: Some(None).flatten: None
Sample.hx:26: Some.flatMap: Some(one)
Sample.hx:27: None.flatMap: None

といった具合になります。

ちょっとしたものですが、nullのないコードが少しは書きやすくなると思います。
nullのないコードに幸あれ!

5
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4