Arrowの紹介その1

DANEKO
PicApp Tech Blog
Published in
8 min readNov 30, 2018

--

Picapp アドベントカレンダー初日です。
唐突にはじまりましたが、普段みんなが気になっている技術だったり仕事で利用しているものだったり、エモい話を書きたい人が書くアドベントカレンダー(のはず)です。
とりあえず言い出しっぺの私が初日と二日目を埋めますので、どうぞよろしくおねがいします。

Λrrow(以下Arrow)というLibraryをご存知でしょうか?

Λrrow is a library for Typed Functional Programming in Kotlin.

とあるように、関数型プログラミングのためのライブラリです。

というとなんだか怖いイメージが生まれてしまそうですが、
今回はこのArrowの中のDataTypesから幾つかとっつきやすそうなものを紹介していこうと思います。

なお基本姿勢ですが…
基本的に公式Documentと動画、KotlinSlackの#arrowが最強だと思っています。
(結果としてリンク集みたいになってしまいました…)
英語に拒否反応が無いならそちらを見ればすべて解決!
でもちょっと日本語で…の方(主に自分みたいな)のためにめっちゃゆるふわな説明を書いていきたいと思います。
ある程度そんなもんかー、となったらあとは公式Documentで…w

依存関係への追加とかはこの辺で。

Option

おそらくこの手のLibraryで最初に使われる代表格だと思います。

Option<A> is a container for an optional value of type A. If the value of type A is present, the Option<A> is an instance of Some<A>, containing the present value of type A. If the value is absent, the Option<A> is the object None.

とあるように、値があればSome、なければNoneで表します。
よくnull(が文脈上値が無いことを示している場合)に対してこれを使いましょう!みたいなケースが多いかと思います。

いろいろなケースがあると思いますが、ちょっとだけ

充実の公式Documentはこちら

Either

EitherはErrorをうまく扱うための一つの方法です。

うまく…とはとなりますが、普通(?)に書いているとErrorはExceptionとしてthrowする…となると思います。(あるいはnullとして返してしまうのでしょうか?)

が、こいつが曲者でメソッド見ただけじゃ何のエラー返すかわからんやんけ!(@Throwsとかはあるけども)どうなっているか一々中を見に行かないと駄目じゃん/(^o^)\
だったら明示的に返しちまえ!!

そこでEitherですよ!!!

みたいなのが公式Documentの冒頭に書いてあります(こんなテンションでは無いですが)

Try

TryはEither同様Errorを上手に扱うためのものです。
Eitherと異なるのはThrowableに限定しているところです。
既存のExceptionをThrowしてくるものをラップすることで、
Error時のRecover用便利メソッドを使えて嬉しい感じです。

なお公式Documentによると

When using Try, it is a common scenario to convert the returned Try<Throwable, DomainObject> instance to Either<DomainError, DomainObject>.

Tryが返されたらEitherに変換するのが普通だよ、みたいな記述があります。

Validated

TryやEither同様、Errorをうまく扱うためのものです。

In general, Validated is used to accumulate errors, while Either is used to short-circuit a computation upon the first error.

ValidatedはErrorを累積するのに対して、Eitherは最初のエラーを返すでー(めっちゃ意訳)とあります。
どういうことかの全体像は、公式Documentのサンプルがわかりやすいのでそちらを参照してください。
公式DocumentのサンプルのConnectionParamsのように、urlのParseが失敗したのかPortのParseに失敗したのか、あるいは「その両方か」みたいなケースにはEitherよりもこちらが便利です。

なおEitherと同じような使い方もできますが、ValidatedにflatMapはありません。

おまけ SemigroupとMonoid

SemigroupはMonoidから単位元を取り除いたものです…

で終わるなら説明要らないですね。
でも多分Monoidのほうがわかりやすいので…
Wikipediaにも…って思って開いたら、難しい言葉たくさんありました。
https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%8E%E3%82%A4%E3%83%89

Monoidは雑に言ってしまえば「足し算できる構造」です。
引き算ではありません。
単位元は「足し算で言うところの0、何に足しても元の性質を変えないもの」です。
足し算を利用した説明が一番わかり易いと思います。
なんかないかなーって探したらSepteni Engineer’s Blogの説明が良さそうなので、リンクを張っておきます。
(言語的にはScalaでの説明になっていますが、Scalaがわからなくても大丈夫な内容だと思います)

http://labs.septeni.co.jp/entry/2016/01/21/132531

そんなMonoidから単位元…足し算で言うところの0をなくしたらSemigroup
上のBlogで言うところの「1.3 単位元の存在」を無くすとSemigroup
となります。

さて、なんでこんな話になったかというと…
ValidatedはError側でNonEmptyListを持つことをよく期待されています。
(実際ValidatedNelというtypealiasも用意されています。)
NonEmptyListはSemigroupです。(Listにおいて空リストは単位元的な)

これでValidatedまわりはきっと大丈夫ですね!

最後に

上記で紹介したものを利用することは、Kotlinを書く上で望ましいのでしょうか?
個人的には大変嬉しいですが、とはいえチームでの方針等々で100%こちらを選択するのが正しい!ということは無いと思います。
ましてや(2018/11/23)現在0.8.1というunstableなVersionが振られいるライブラリですし。

ちなみに上記サンプルをnullableで書いたらこんな感じでしょうか?
これだけ見ると特に嬉しさは感じないと思います。
これとの比較だったらぶっちゃけ要らない…って人も多いかと…

またKotlin1.3M1で入ったSuccessOrFailure(1.3ではResult)のKEEPのこの辺とかをみると、Result型を返すよりもNullable(個人的にはやめてほしい)かそれ専用の型を返せ!とあります。
ArrowのTryもOption/Eitherに(最終的に)変換されるのが普通らしいので、近いと思います。
なので大差ないとも考えられますが、この場合専用の型はたいていEither等を特化させたようなケースが多いと思います。
すでによく使われるパターンが組み込まれたEither等を自前で用意することを考えると、Arrowがあるだけで楽になるケースは多いハズです。

とはいえそのためだけにArrowを入れるかは(他のものもいっぱい入ってくる&学習コストを加味して)ケース・バイ・ケースだと思います。

繰り返しになりますが、個人的にはおすすめです!
私がチームに居てKotlinを選択するなら、いずれ依存関係にarrowという文字列を見ることは間違いありません!(たぶん)
実際一部では利用しています。

ということで、これだけでは嬉しさが伝わりにくいはずですし(人数と枠の関係上もあり)またこのAdventCalener別日にArrowの普及を含めた記事を書こうと思います!

最後の最後に
一緒にArrowを普及するメンバーも随時募集(従業員という意味でも知人という意味でも)しています。
少しでも興味を持っていただけたら、下記FormでなくともDMとかでお気軽にお声掛けください。
お試し就職とかもあるよ!

https://dmm-corp.com/recruit/engineer/5552

--

--