なごやかJavaで発表してきた
なごやかJava第一回で、「.NET系開発者から見たJava」というタイトルで発表してきました。 Javaのこの機能って.NET開発者から見てどうなの?というような内容です。
大阪から参加してくれた方の感想を載せておきます。
おかしい、終わった後の感想が「F# すごい!」だ…… #ngojava
— irof@Javarista (@irof) 2014, 11月 30
F# 4.0プレビュー版公開!
拡張機能が使えるVisual Studioが条件付きで無償化されたことによって、 快適な開発環境でF#を学べるようになることでしょう。
それはそれで楽しみなことは間違いないのですが、今回はF#自体の使い勝手の向上に目を向けたいと思います。
昨日はVS Communityが無償提供されたほか、様々な発表がありましたが、F#も4.0のプレビュー版が公開されました。
新機能一覧
プレビュー版までで実装されたものは以下の通りです。
- 言語に関するもの
- ライブラリに関するもの
- VSツールの改善
- プロジェクトテンプレートへの
AssemblyInfo.fs
の追加 - F# Interactiveの起動の高速化
- F# Interactiveのショートカットを追加(セッションのリセット、すべてクリア)
- プロジェクトテンプレートへの
あっと驚く新機能はないものの、全体的に使い勝手を向上させることを目的にしているように思います。 このほかの実装予定の機能については、Status of F#4.0+ Approved Language/Library Itemsを参考にしてください。
今回は、F#4.0のプレビュー版までで実装されたもの中から、コレクションモジュールの正規化を取り上げたいと思います。
コレクションモジュールの正規化
F#はList
/Array
/Seq
という3つのコレクションモジュールを持っていましたが、
「こっちのモジュールでは提供されているけどこっちのモジュールでは提供されていない」という関数が多くありました。
F#4.0では、この状況が大幅に改善されます。 どのように改善されるのか見ていきましょう。
Seq
にしかなかった関数のList
/ Array
への追加
compareWith
第一引数として渡された関数をもとに、コレクションの大小を求める関数です。
(* val List.fで、Listモジュールのf関数と思ってください *) val List.compareWith: ('a -> 'a -> int) -> 'a list -> 'a list -> int val Array.compareWith: ('a -> 'a -> int) -> 'a [] -> 'a [] -> int
groupBy
要素を変換した結果と、その変換のもとになったコレクションのペアのコレクションにして返す関数です。
val List.groupBy: ('a -> 'b) -> 'a list -> ('b * 'a list) list when 'b : equality val Array.groupBy: ('a -> 'b) -> 'a [] -> ('b * 'a []) [] when 'b : equality
countBy
要素を変換した結果と、その個数のペアのコレクションにして返す関数です。 変換結果でグループ化して個数も求めるような感じですね。
val List.countBy: ('a -> 'b) -> 'a list -> ('b * int) list when 'b : equality val Array.countBy: ('a -> 'b) -> 'a [] -> ('b * int) [] when 'b : equality
distinct
/ distinctBy
distinct
は要素の重複を取り除く関数で、
distinctBy
は重複の基準を関数として渡せるdistinct
です。
val List.distinct: 'a list -> 'a list when 'a : equality val List.distinctBy: ('a -> 'b) -> 'a list -> 'a list when 'b : equality val Array.distinct: 'a[] -> 'a [] when 'a : equality val Array.distinctBy: ('a -> 'b) -> 'a [] -> 'a [] when 'b : equality
exactlyOnce
コレクション中に要素が一つしかなかった場合に、それを取り出す関数です。 複数の要素があった場合は例外を投げます。
val List.exactlyOnce: 'a list -> 'a val Array.exactlyOnce: 'a [] -> 'a
last
コレクションの最後の要素を返す関数です。
val List.last: 'a list -> 'a val Array.last: 'a [] -> 'a
pairwise
/ windowed
windowed
は、スライド式のウィンドウを生成する関数です。
pairwise
はこの特別なバージョンで、ウィンドウのサイズが2に固定化され、ウィンドウは配列ではなくタプルとしてあらわされます。
val List.pairwise: 'a list -> ('a * 'a) list val List.windowed: int -> 'a list -> 'a [] list val Array.pairwise: 'a[] -> ('a * 'a) [] val Array.windowed: int -> 'a[] -> 'a [] []
singleton
渡された要素のみを含むコレクションを生成する関数です。
val List.singleton: 'a -> 'a list val Array.singleton: 'a -> 'a []
skip
/ skipWhile
/ take
/ takeWhile
/ truncate
なぜなかった感のある関数群ですね。説明は不要でしょう。
unfold
種となる値からコレクションを生成する関数です。 これも、なぜなかったのか・・・
where
filter
の別名です。これ、むしろいらんやろ・・・
List
にしかなかった関数のArray
/ Seq
への追加
tail
先頭要素を除くコレクションを返す関数です。
map3
3つのリストに対するmap
関数です。
val Array.map3: ('a -> 'b -> 'c -> 'd) -> 'a [] -> 'b [] -> 'c [] -> 'd [] val Seq.map3: ('a -> 'b -> 'c -> 'd) -> 'a seq -> 'b seq -> 'c seq -> 'd seq
replicate
指定した個数の指定した要素を含むコレクションを返す関数です。
val Array.replicate: int -> 'a -> 'a [] val Seq.replicate: int -> 'a -> 'a seq
List
とArray
にあった関数のSeq
への追加
fold2
/ foldBack
/ foldBack2
/ reduceBack
/ scanBack
fold
系の派生関数群ですね。
iteri2
/ mapi2
インデックスを伴ったiter2
とmap2
です。
今回、map3
は追加されますが、List
にもともとmapi3
がなかったためか、mapi3
は追加されないようです。
permute
インデックスの変換関数を元に要素を置換したコレクションを返します。
val Seq.permute: (int -> int) -> 'a seq -> 'a seq
rev
シーケンスを逆順にしたシーケンスを返す関数です。
sortWith
比較関数を指定してコレクションをソートする関数です。
val Seq.sortWith: ('a -> 'a -> int) -> 'a seq -> 'a seq
List
とSeq
にあった関数のArray
への追加
head
コレクションの先頭要素を返す関数です。
今までなかった関数のList
とArray
への追加
splitAt
指定されたインデックスでコレクションを分割します。
val List.splitAt: int -> 'a list -> 'a list * 'a list val Array.splitAt: int -> 'a [] -> 'a [] * 'a []
今までなかった関数のList
とArray
とSeq
への追加
contains
今まで、
xs |> List.exists ((=)x)
などとしていましたが、今後はcontains
が使えます。
findBack
/ findIndexBack
/ tryFindBack
/ tryFindIndexBack
find
系の関数に、後ろから探すものが追加されました。
tryHead
/ tryLast
失敗するかもしれない関数にoption
を返すバージョンが追加されました。
tryTail
が無いのは・・・?
indexed
コレクションの要素にインデックスを付けたコレクションにして返す関数です。
val List.indexed: 'a list -> (int * 'a) list val Array.indexed: 'a [] -> (int * 'a) [] val Seq.indexed: 'a seq -> (int * 'a) seq
item
/ tryItem
今まで、n番目の要素を取り出す関数としてnth
がありました。
しかし、これはArray
にはなく、またList
とSeq
で引数の順番が違うというとてもアレな関数でした。
val List.nth: 'a list -> int -> 'a val Seq.nth: int -> 'a seq -> 'a
F#4.0では、nth
は非推奨となり、引数の順番が統一されたitem
が提供されます。
val List.item: int -> 'a list -> 'a val Array.item: int -> 'a [] -> 'a val Seq.item: int -> 'a seq -> 'a
option
を返すバージョンであるtryItem
も追加されました。
val List.tryItem: int -> 'a list -> 'a option val Array.tryItem: int -> 'a [] -> 'a option val Seq.tryItem: int -> 'a seq -> 'a option
これは朗報ですね!
mapFold
/ mapFoldBack
fold
は種の型が戻り値の型になりましたが、mapFold
は第一引数として渡す関数の結果として次の種だけではなく追加の値も返せるようにしたことで、
map
とfold
の処理を同時に行えるようになりました。
結果として返されるタプルの一つ目にmap
の結果が、二つ目にfold
の結果が入ってきます。
val List.mapFold: ('b -> 'a -> 'c * 'b) -> 'b -> 'a list -> 'c list * 'b val Array.mapFold: ('b -> 'a -> 'c * 'b) -> 'b -> 'a [] -> 'c [] * 'b val Seq.mapFold: ('b -> 'a -> 'c * 'b) -> 'b -> 'a seq -> 'c seq * 'b
mapFoldBack
はfoldBack
とmap
を同時にするバージョンです。
sortByDescending
/ sortDescending
逆順のソートをする関数です。 これないのつらかったんですが、ようやく入ってくれました。
VS Pro相当が無償化されたことだし、F#をやろう!
とのことらしいですよ! F#*1も入っており、拡張機能も使えるようです。 ということは、素敵拡張機能であるVFPTが使えるということですよ!
もし今回のことでF#を始めるという方は、是非VFPTを導入した環境でF#を触ることをお勧めします。
そして、ついでにF# Advent Calendar 2014に参加してみるというのもいいでしょう。
みんなでF#やりましょう!
F#!F#!
追記: オープンソース開発してVisual Studio Community 2013を使おう! Visual Studio Community 2013 - Visual Studio
函数型なんたらの集い 2014 in Tokyo
函数型なんたらの集い 2014 in Tokyoに参加してきました。
発表資料はこちら。
内容は、Excel方眼紙を倒すためにDSLで頑張ったというものです。 この中で紹介しているTableDslは、いろいろと発展を考えているので「アレ使えばいいじゃない」は通じないのです。 あとそのアレ、Excel方眼紙吐けないじゃないですかー。
コメントで「いじられたくないならPDFにしてしまえばいいじゃない」というのがありましたが、Excelで提出することが決まっているのにそういうことできないですからね・・・
12月6日のNGK2014B 昼の部で、DSLとは違ったExcelの話をするので興味のある人はどうぞ。
F# Meetup in Tokyo
今更シリーズその2。8月3日に、F# Meetup in Tokyoに参加してきました。
発表資料はこちら。
内容は、業務でF#を使った事例の紹介です。
F#オンリーのイベントにたくさんの人が参加してくれて、またいろいろな話が聞けてよかったです。 名前出していいかわからないから伏せますけど、LangExtを使っているという声も聞けました。 あんな変態ライブラリ、自分ら以外使わんやろー、と思っていたけど、実際に使われているとわかるとうれしいものですね。
またああいうイベント、やりたい!
クラウド温泉4.0@小樽 - The Return of F#
今更シリーズその1。 7月の25から28日に、 クラウド温泉4.0@小樽 - The Return of F#に参加するために北海道に行ってきました。
発表資料はこちら。
内容はコンピュテーション式のyieldとreturnについての話で、
あたりの流れの一つのまとめになっています。 上であげた、「コンピュテーション式におけるreturnとyield」では状態引数による実装のみを紹介していましたが、 今回の発表資料の中では、
- 例外による実装
- 状態変数による実装
- 状態引数による実装
- 継続による実装
と、多数の実装方法を紹介しています。
また、FSharpxやExtCoreといったF#の有名ライブラリが、コンピュテーション式を正しく実装できていない点(yieldやreturn以前の問題)も明らかにしました。 詳しくは追っていませんが、実は標準のAsyncコンピュテーション式がそもそもダメという話も・・・ そもそも、コンピュテーション式を展開して考えている実装者はおそらく皆無であり、 ネット上にある間違った情報をもとにコンピュテーション式を実装している場合が多いように思います。 モナドやモナドプラス以上の表現力のものを実装する場合は、せめてコンピュテーション式の展開規則を理解したうえで実装しましょう。