public class EnumReverseLookup<E extends Enum<E>, ATTR> {
private final Class<E> enumClass;
private final Function<E, ATTR> getter;
public EnumReverseLookup(final Class<E> enumClass, final Function<E, ATTR> getter) {
this.enumClass = enumClass;
2015/07/24 関数型Scalaの集い
- 中村 学
- @gakuzzzz
- 株式会社 Tech to Value
- Scala関西 Summit 2015 スポンサーしてます
この記事は エムスリー Advent Calendar 2015 の18日目の記事です。
Java8 で色々便利になりました。でもエラー処理でやっぱり困る事は多々あって、そういう時に Either
が欲しくなるものです。
Either
といえば Java7 以前から Atlassian の fugue というライブラリがサポートしていました。
Validator
に (validateToEither
と同様な)validateToAp
みたいなのを作らずApplicativeValidator
を別に用意したのは何故なんでしょう?validateToValidation
みたいな謎な名前になってしまうから?
- ApplicativeBuilder的な
ComposingN
があるのでFunctionN
にcurried
を持たせなくても良さそうですね(実装は泥臭くなりますがオブジェクト生成数を抑制できます)- 逆にカリー化できる関数があると
ComposingN
のようなものを不要にできたりもします。 - とは言えYAVIのユースケースだと
Validator
からメソッドチェーンで使うのが主だと思うので、ComposingN
の方が有用そうですね。 - 完全に余談ですが、カリー化できる
FunctionN
を別途定義するより、curried
を static メソッドにするとcurried(Foo::bar)
みたいな使い方が可能になるので個人的にはそちらの方がお勧めです。(Functions
的な1クラスのoverloadですませられますし)
- 逆にカリー化できる関数があると
Validation<E, >
のapply
がValidation<List<E>, >
を返すのがびっくりしますね。Applicative の挙動を期待するなら型としてはValidation<E, >
になるので。- YAVI の利用範囲から考えると、エラーの集約方法を汎用化する必要もなさそうなので、error は最初から
List
に決め打ちしちゃってもいいかもしれません。以下のようなイメージです。
package controllers.util | |
import play.api.mvc.{Result, Controller} | |
import play.api.data.Form | |
import scala.util.Either.RightProjection | |
object Implicits { | |
implicit def formToEither[A](form: Form[A]): Either[Form[A], A] = form.fold(Left.apply, Right.apply) |
Java8以降の Stream API で畳み込みを行いたい場合は Stream#reduce
か Collectors.reducing
を使用します。
しかし、Stream API は基本的に parallel で動作する事を考慮に入れる必要があるため、Stream#reduce
および Collectors.reducing
には強い制約があります。
つまり、初期値は必ず単位元である必要があり、演算は結合則を満たす必要があります。
試しにその制約を満たしていない引数を渡すと、結果が定まらない事が見て取れます。
例えば 50
という初期値から 1~100
までの数値を順番に引いていくと -5000
になるはずです。
IntStream.rangeClosed(1, 100).boxed().parallel().reduce(50, (a, b) -> a - b, (a, b) -> a + b); // -3250 になる
- 2014/07/13 Scalaz勉強会
- @gakuzzzz
- 中村 学
- 株式会社Tech to Value
- play2-auth が scala-awesomeに載りました
Java Stream API で foldLeft/foldRight で宿題にした StackOverflow しない実装の一例です。
面白ポイントとしては、foldRight
/foldLeft
の実装差分は Function::compose
/Function::andThen
が Endo::compose
/Endo::andThen
に変わっただけ、という所ですね。
(注意)ただしこれは不変な List の concat を Stream を使って実装しているため、非常に遅いです。 高速な実装については読者への宿題とします。
class Foo {
type L[A] = Either[String, A]
foo[L](bar)
}
↓
https://twitter.com/cero_t/status/1305994285897011200 の話。
Map<String, Integer> someKeyName2ValueName = new LinkedHashMap<>(Map.of(
"foo", 10,
"bar", 20,
"baz", 30
));