こんなこと言ってる自分も勉強中の一人だけど。
でももっとF#の知名度上がったらいいなーと思って、Twitterとかもくもく会とかでF#の事言いまくってる。
##楽しいところ
F#はパズル組んでるみたいで書いててとても楽しい。
定数しか使えないという制約の元で、いかに読みやすくバグなく書けるか、めっちゃ頭をひねるので。1
高階関数と「|>」を使うとさらっと書けて、読みやすいコードが書ける。2
あとは以下みたいな悪しきコードが、すばらしく簡潔になったりしたときの感動はひとしお。3
// 特定の要素を取り除いた新しいリストを取得したい
// ※player.HandCardsはCard型のlistである
let askCardIndex =
(player.HandCards |> List.tryFindIndex(fun x -> (isKnown askCard x))).Value
List.append player.HandCards.[.. askCardIndex - 1] player.HandCards.[askCardIndex + 1 ..]
// ↓↓↓ 以下の1行だけで実現できる ↓↓↓
player.HandCards |> List.except [askCard]
F#について詳しく知りたい方は以下の記事が非常に良いと思います。
F# を知ってほしい
仕事と F# と私
##ローカルの実行環境
個人的には.NET Core + vscode + ionide(プラグイン)でいいと思う。
大事なのは最新版のdotnetcoreを入れる事(執筆時点では3.1.1)。
2.1とか古いままにしてると、以下のionideの超嬉しい機能が使えなかったりする。
冗長なコードをこう書き替えたら?とか聞いてくるのでとても賢い。
↓↓↓
// 書いてたやつ
[1..10] |> List.sortBy(fun _ -> Guid.NewGuid()) |> List.head
// ionideが提示した修正案
[1..10] |> List.minBy(fun _ -> Guid.NewGuid())
##オンライン開発環境
いろんな事情があってローカルで環境構築できない場合は、ここがインテリセンス効くので最強。
https://fable.io/repl/
記事の執筆時点当初では、まだ全機能がリリースされてるわけではなかったけど
メンバーの方が「リリースしたよ!」って報告してくれました。
Thanks!
https://github.com/fable-compiler/repl/issues/105
↓↓↓
ただ、Console.readLine()とか、どうしても一部動かせない処理は存在する。
こちらはインテリセンスは効かないけど、4.0相当の機能は確実に実行できる。
https://repl.it/languages/fsharp
てなわけで、fable.ioでコーディングして
実行できない関数にぶちあたってしまった場合はrepl.itでコンパイルすると吉。
##ドキュメント
msdnはドキュメントが古い。でも一覧性はとても良い。
なのでインテリセンスでどんな候補があるか見て、気になったやつをググるが確実っぽい。
自分はListとかの高階関数使うので、見るのはこれ。
こんなにあった... F#ドキュメントには未掲載のArray関数
これは知らなかった... F#ドキュメントには未掲載のコレクション関数(List編)
あとは人が書いたF#のコード眺めてると、未知の記法がある事に気付いて輸入できたりする。
O'ReillyのプログラミングF#を読みながら、徐々に理解を広げていってる感じ。
##個人的に詰まったところの覚え書き(主に文法面)
###型の注釈をどう入れるか
- リストはType名 listの形で定義
// OK
let buildPlayer (handCards:Card list) =
...
// NG(別モノになってしまう)
let buildPlayer (handCards:List<Card>) =
...
- 複数の引数に注釈入れる場合は()でそれぞれ囲む
// OK
let phase (player:Player) (enemy:Player) =
...
// 文法的にはOKだけどこれだとタプルを引数でもらうことになってしまう(カリー化できない)
let phase (player:Player, enemy:Player) =
...
// NG(シンタックスエラー)
let phase player:Player enemy:Player =
...
// OK 片側だけならこんな感じ
let rebuildAskPlayer (player:Player) askAfterHandCards =
...
###意味のない変数をどうするか
- _を使うと警告がでない
let shuffledCards =
cardList
|> List.sortBy(fun _ -> Guid.NewGuid())
###タプルの戻り値
- まとめてletできる
// xには1が yには7が
let x, y = (1, 7)
###たまに戻り値で返ってくるOptionってなに
- Some(値)かNoneが入ってる
// 値があるならSomeの中にValueがある
let x = Some(1)
printfn "%A" x.Value
// => 1
// Noneを明示的に入れたらインテリセンスが.Valueを候補として出してくれない。賢い
let y = None
printfn "%A" y
// => null
###ifは式
- 分岐で得られた値を束縛できる
let result = if playerCard.Number > enemyCard.Number then High else Low
// => resultはHighかLowが束縛される
-
他の関数型言語でも同じやろうけど ↩
-
個人差あり、最初は慣れが必要かも
ポーカーの役判定を高階関数縛りで書いてた時とかも超楽しかった。 ↩ -
インデックスアクセス怖い。でもList.removeがないと知ったときは、これしか思いつかなかった ↩