functional java に関するメモ

概要

libraryDependencies += "org.functionaljava" % "functionaljava" % "3.0"

だけで使用可能

モジュールの分類

    • core メインとなるソース
      • core/src/main は 44563 行
      • core/src/test は 1264 行
      • テストはすべてScalacheckで書かれている
    • demo サンプルコード
      • 2038行
      • それなりに充実してるので、みんな読みましょう

F

  • F 〜 F8までの関数のためのclassは、fという名前のメソッドのみ抽象メソッド。mapなどする場合にその場で無名クラス生成して渡す用途など。
  • FやF2には、カリー化や、Stream、Option、Either、Iterable、Promise、NonEmptyList、Tree、Validationなどへの変換やユーティリティが組み込まれていたり、(Scala標準と比べて)かなり多機能。というかFunctionのclassの側に持ったほうが、使う側が都合がいいからあるという感じだろうか。

P

  • PからP8は、関数型言語でいえば、いわゆる代数型だとおもう。Scalaだとscalaパッケージ直下の Product1 、Product2... という、case classや、Tupleの親に相当するもの
  • 勿論P〜P8はすべてimmutable
  • P1ならば、_1という抽象メソッドが1つ。P3ならば、_1 _2 _3 と抽象メソッドが3つという様になっている。
  • Scalaでのcase classっぽいものを作る際には、これらを自ら継承して、それぞれ _1 、_2 というメソッドを実装して使用。
  • Tupleという名前のclassはない・・・?のでTuple使いたい場合はP 〜 P8 の無名クラス生成するのか・・・?(調査中)P ~ P8の無名クラスを生成するためのstaticなメソッドが P.java に、 p という名前で存在するようです。(P〜P8生成用メソッドの名前がすべて p で、8つオーバーロードされてる。)あえて、Pを継承してTupleというclassを作ってないのは、なにか理由があるんだろうか?*1
  • scalaでのcopyメソッド相当の、map1 〜 mapNという、n番目の要素を変更した新しいPを返すメソッドがある。
  • BottomはScalaでのNothing相当だろうが、型システムとしてサポートされてないのにBottom型があって、どうやって効果的に使うのだろうという疑問が・・・

Function

  • Function.javaはコンストラクタがprivateで、staticなユーティリティ関数が置いてあるclass
  • 関数合成、部分適用、カリー化、アンカリー化*2、flip(引数の順序の入れ替え) など
  • このあたりとか素晴らしいですね・・・

Show

  • Pを始め、ListやStreamなど、おそらくほとんどのデータ型はtoStringをoverrideしていない!
  • 代わりにShowの型クラスがある
  • このあたりがScalaと完全に異なって、Haskellに近い
  • 基本的なShowのinstanceは、Show.javaのstaticなfieldにおいてある。
  • Show以外の型クラスについても同様ですが、暗黙的に取ってくれずに明示的に渡さないといけないのでめんどくさい・・・

Equal

  • Show同様、基本的にequalsもoverrideされていない!ので、Equal型クラスがあります
  • これも明示的に渡さないといけないので(ry

Class

  • java.lang.Class用のユーティリティ。
  • 単にユーティリティなので型クラスとかではない

Ord,Ordering,Monoid,Semigroup など

  • このあたりは、ScalazやHaskellなど関数型言語やってればお馴染みのあれ
  • FunctorとかMonadとか見当たらないんだが・・・。手抜きなのか、作っても結局記述量増えて相当使いづらいのでやめたのか・・・?

Hash

  • これが、結構functionalJava独自な気がするけれども、hashCodeをオーバーライドするかわりに、Hash値を生成可能かどうかを表す型クラスにしてあるみたい?

Unit

  • 概念的にはScalaのUnitそのままかと

Primitive

  • コンストラクタはprivateでstaticなfieldのみ
  • Double から Int 変換などの、primitiveの相互変換のための関数オブジェクトが置いてある

Digit

  • scalazにも同じようなものあるけど、(型レベル計算ができるわけでもないし)イマイチ使い方わかってない・・・

data/Option

  • 概念的にはScalaのOptionやHaskellのMaybe
  • 相互変換のメソッドなどScala標準と比べると多い

data/Either

data/List

data/Stream

  • immutableで片方向リンクな遅延リスト・・・ってつまりScalaのStreamと概念的に一緒
  • でもメソッドは結構違うものも多い・・・(なんかこれしか言ってない)
  • ArrayとかListの相互変換があったり
  • Promiseとか関連していて、面白そう。

data/Set

  • red/blackで実装されたimmutableなSet
  • Set自体はabstract
  • ordのインスタンスが必ず必要?つまり自動で常にsortされた状態か
  • 内部classのTreeを実装するためのもの?(ほかにライブラリ中でSetを継承しているものが見当たらない)
  • つまり普通のjavaのHashSetとまったく同じような使い方を想定するとちょっと違うのか?(よくわかってない)

data/$

  • 関数型の知識が足りなくてうまく説明できない・・・

data/Array

  • 内部に配列を持っていて、それをラップしてる。mutable
  • setがUnit返すとか素晴らしいですね

data/Java

  • ArrayList,BitSet,EnumSet,HashSet,LinkedHashSet,LinkedList,Stack,TreeSet などなど、javaの標準のcollectionのほぼすべて(?)にたいして、fjのLitやStreamとの相互変換を提供するための関数オブジェクトがおいてある

TODO まだデータ構造いっぱいあるので、ヤル気がでたらこのあたりに追記・・・



core/src/main/java/fj/ 以下のディレクトリ毎に分けてみた

  • Functionオブジェクトや、基本的な型クラスなど、一番よく使うと思われるものがfjパッケージ直下に置いてある
  • control
    • control直下にあるのはTrampolineだけ
  • db
    • jdbcの薄いラッパー?そんなにコード量多くない。でも、DBはmonadになっていたりして面白そう
  • parallel
    • (作ってる人同じだから当たり前だが)ファイル構成をみる限り最小限でコンパクトなところが、Scalazのconcurrentモジュールにかなり似ている感じ。Actor,Callables,ParModule,Promise,Strategy
  • data
    • データ構造。結構基本的なものは網羅されていそう。Array, Conversions, Either, Enumerator, HashMap, HashSet, IO, IterableW, Iteratee, Java, LazyString, List, Natural, NonEmptyList, Option, Seq, Set, Stream, Tree, TreeMap, TreeZipper, Validation, Zipper
    • fingertrees
      • Fingertreeというデータ構造ためのclass一式。「public な class を1ファイルに対応させる必要がある」ので package-infoを除いて14ファイルもある。。。
    • hlist
      • heterogeneousなlist
    • vector
      • package-infoには"Fixed-length vectors"と書いてある。長さがすでにコンパイル時に決まっているリスト?要素の型は同じ。もちろんimmutable。1から8まである。つまりScalaには対応するもの存在しないが、使い道そんなにあるんだろうか・・・?(内部的に必要となる場面が多いとか?)
  • function
    • BigIntegers,Booleans,Characters,Doubles,Integers,Longs,Stringsと基本的な型についてよく使うとおもわれる関数を置いてある。Visitor(できれば後述)がちょっと面白そう
  • parser
    • Parser 。。。どのくらい使えるのだろうか
  • test
    • おそらく Haskell の quick check っぽいテスト用ライブラリ
    • reflect

tree表示しただけのもの↓

fj
├── Bottom.java
├── Class.java
├── Digit.java
├── Effect.java
├── Equal.java
├── F.java
├── F2.java
├── F3.java
├── F4.java
├── F5.java
├── F6.java
├── F7.java
├── F8.java
├── Function.java
├── Hash.java
├── Monoid.java
├── Ord.java
├── Ordering.java
├── P.java
├── P1.java
├── P2.java
├── P3.java
├── P4.java
├── P5.java
├── P6.java
├── P7.java
├── P8.java
├── Primitive.java
├── Semigroup.java
├── Show.java
├── Unit.java
├── control
│   ├── Trampoline.java
│   ├── db
│   │   ├── Connector.java
│   │   ├── DB.java
│   │   ├── DbState.java
│   │   └── package-info.java
│   ├── package-info.java
│   └── parallel
│       ├── Actor.java
│       ├── Callables.java
│       ├── ParModule.java
│       ├── Promise.java
│       ├── Strategy.java
│       └── package-info.java
├── data
│   ├── $.java
│   ├── Array.java
│   ├── Conversions.java
│   ├── Either.java
│   ├── Enumerator.java
│   ├── HashMap.java
│   ├── HashSet.java
│   ├── IO.java
│   ├── IterableW.java
│   ├── Iteratee.java
│   ├── Java.java
│   ├── LazyString.java
│   ├── List.java
│   ├── Natural.java
│   ├── NonEmptyList.java
│   ├── Option.java
│   ├── Seq.java
│   ├── Set.java
│   ├── Stream.java
│   ├── Tree.java
│   ├── TreeMap.java
│   ├── TreeZipper.java
│   ├── Validation.java
│   ├── Zipper.java
│   ├── fingertrees
│   │   ├── Deep.java
│   │   ├── Digit.java
│   │   ├── Empty.java
│   │   ├── FingerTree.java
│   │   ├── Four.java
│   │   ├── MakeTree.java
│   │   ├── Measured.java
│   │   ├── Node.java
│   │   ├── Node2.java
│   │   ├── Node3.java
│   │   ├── One.java
│   │   ├── Single.java
│   │   ├── Three.java
│   │   ├── Two.java
│   │   └── package-info.java
│   ├── hlist
│   │   ├── HList.java
│   │   ├── HPre.java
│   │   └── package-info.java
│   ├── package-info.java
│   └── vector
│       ├── V.java
│       ├── V2.java
│       ├── V3.java
│       ├── V4.java
│       ├── V5.java
│       ├── V6.java
│       ├── V7.java
│       ├── V8.java
│       └── package-info.java
├── function
│   ├── BigIntegers.java
│   ├── Booleans.java
│   ├── Characters.java
│   ├── Doubles.java
│   ├── Integers.java
│   ├── Longs.java
│   ├── Strings.java
│   ├── Visitor.java
│   └── package-info.java
├── package-info.java
├── parser
│   ├── Parser.java
│   ├── Result.java
│   └── package-info.java
└── test
    ├── Arbitrary.java
    ├── Arg.java
    ├── Bool.java
    ├── CheckResult.java
    ├── Coarbitrary.java
    ├── Gen.java
    ├── Property.java
    ├── Rand.java
    ├── Result.java
    ├── Shrink.java
    ├── Variant.java
    ├── package-info.java
    └── reflect
        ├── Category.java
        ├── Check.java
        ├── CheckParams.java
        ├── Main.java
        ├── Name.java
        ├── NoCheck.java
        └── package-info.java

*1:共変とかの関係で、Pの無名クラスのほうが都合がいいとか?

*2:この言い方でいいの?