LoginSignup
94
55

More than 3 years have passed since last update.

なぜ私は F# を使うのか

Last updated at Posted at 2021-02-10

この記事は、短く書けて何でもできてライブラリも豊富なのに(何故か)知名度が上がらないF#を布教するための記事です。

※分かりやすくするため、手続き的/オブジェクト指向的な言葉を使っています。関数使いの皆さんは代入という言葉を見ても目くじらを立てないで下さい

F# とは

関数指向をベースとしてオブジェクト指向の要素も取り入れたプログラミング言語で、.NET上で動作します。
「.NET と言えばWindows」という印象が未だに根強いようですが、最近の .NET Core や .NET5 は Mac や Linux でも動きますし、動作もそれなりに速いです。1

F# はとにかく短く書ける!!

私がF#を使う一番の理由はこれ。短く書けるからPython使ってる人にもF#をおすすめしたいです。
F#はベースとなった言語である OCaml と比べて徹底的に無駄な文字を省略できるようになっており、コードのほとんどが本質的に必要なものだけで構成されます。
一般的な言語のと比べてもかなり短く書けるほうで、例えば同じ.NET系の言語であるC#と比べて7割程度のコード量で済みます。

軽量な構文

F# は Python などと似ているインデントを使った軽量構文をサポートします。

F#によるFizzBuzz
let fizzBuzz () =
    for i in 1..30 do
        if i % 15 = 0 then
            printfn "FizzBuzz"
        elif i % 3 = 0 then
            printfn "Fizz"
        elif i % 5 = 0 then
            printfn "Buzz"
        else
            printfn "%i" i

F# において、式中の = は代入ではなく等値比較です。
for や if の終わりを示す記号はありませんが、より浅いインデントに入った時点でブロックを抜けたとみなされます。
書き味としては、C言語系よりも Python などに近いですね。

ちなみにこれくらいの長さだったら、F#er は then の後ろに式を書きます。

F#によるFizzBuzz
let fizzBuzz () =
    for i in 1..30 do
        if i % 15 = 0 then printfn "FizzBuzz"
        elif i % 3 = 0 then printfn "Fizz"
        elif i % 5 = 0 then printfn "Buzz"
        else printfn "%i" i

F# はこのような書き方を公式が推奨2しており、総合的にコードの行数が少なくなりやすいのが特徴です。

柔軟性

F# では関数の中に書けるすべての言語構成要素が (= 評価されると値になるもの)です。
例えばF#のif式値を返せるので、他言語におけるif構文と三項演算子の両方の性質を持ちます。

if式でFizzBuzzを書き換えた例
let fizzBuzz () =
    for i in 1..30 do
        // if式の"結果"を変数に代入(束縛)できる
        let text =
            // "文字列を返す" if式
            if i % 15 = 0 then "FizzBuzz"
            elif i % 3 = 0 then "Fizz"
            elif i % 5 = 0 then "Buzz"
            else i.ToString()
        printfn "%s" text

強力な型推論

F#は強い静的型付けの言語なので、コンパイル時に型の整合性がとれているかチェックが入ります。にもかかわらず、ソースコード上にほとんど型を書く必要がありません。これはF#の型推論が利く範囲が非常に広いためで、型が特定できない場合は自動でジェネリック化もしてくれます。

FizzBuzzのメインロジック部分
let fizzBuzz i =
    if i % 15 = 0 then "FizzBuzz"
    elif i % 3 = 0 then "Fizz"
    elif i % 5 = 0 then "Buzz"
    else i.ToString()

上記のコードはコード中に一切型を書いていませんが、 fizzBuzzint型の引数iをとりstring型を返す関数としてきちんと定義されます。

null フリー

F# にも null という概念はありますが、基本的に使うことはありません。3
未初期化の変数を用意しなくてもよいような様々なサポートがあります。

コレクション操作が簡単

標準で用意されているコレクション操作関数が豊富であるほか、複雑な式を使ったコレクション初期化も簡潔に書くことができます。

様々なリストの初期化
// 値を直に指定
let list1 = [ 1; 3; 5 ]

// [ 1; 2; 3; 4; 5 ]
let list2 = [ 1..5 ]

// for を使って式の結果をリストに格納
// [ 10; 20; 30; 40; 50 ]
let list3 = [ for i in 1..5 -> i * 10 ]

// ifを使ってフィルタリングするなど、括弧の中に式を書ける
// [ 20; 40; 60; 80; 100 ]
let list4 = [
    for i in 1..10 do
    if i % 2 = 0 then
        i * 10
]

パターンマッチが強力

F#にも関数型言語ではお馴染みのパターンマッチがあります。知らない人のために簡単に説明すると、switch - case超超超強化版みたいなやつです。
ちゃんと説明するとめちゃくちゃ長くなるので、よく使われる例を貼っておきます。

パターンマッチ
// パターンマッチに対応している型の定義 (F# では「判別共用体」と呼ばれる)
type Shape =
    | Rectangle of width: float * height: float
    | Circle of radius: float

// Shape型の変数には、widthとheightをフィールドに持つ「Rectangle」という値か、
// radiusをフィールドに持つ「Circle」という値を代入できる
// オブジェクト指向で言うところのサブクラスに近い
let shape1 : Shape = Rectangle(12.0, 15.0)
let shape2 : Shape = Circle(1.0)

// パターンマッチ
// Shape型の値を、RectangleとCircleに「場合分け」して処理する
let area (s: Shape) =
    match s with
    | Rectangle(height, width) -> height * width
    | Circle(radius) -> Math.PI * radius * radius
既存の型に対するパターンマッチ
// 整数を奇数と偶数に「場合分け」するパターンを定義
let (|Even|Odd|) (x: int) =
    if x % 2 = 0 then Even else Odd

// Shapeの例と同じように整数を「場合分け」できる
let printInt (x: int) =
    match x with
    | Even -> printfn "even"
    | Odd -> printfn "odd"

その他

最近の言語によくあるものは大体あります。

  • ラムダ式・高階関数
  • クラス・インターフェイス (オブジェクト指向要素)
  • 例外
  • タプル
  • レコード型
  • Option型
  • コンピュテーション式 (Haskell の do 構文に相当)

まとめ

他にも色々語りたいことはありますが、F#は手軽に使えて大規模プログラムにも向いているいい言語なので使ってみてください!!!!

参考リンク

MSDN
お馴染み、Microsoftによる翻訳ガバガバ公式ドキュメント。
英語版のほうが読みやすいし、英語が分からなくても英語版をGoogle翻訳したほうが読みやすいです。

GutHub(fsharp)
次のバージョンで言語に追加される機能などがここでディスカッションされてます。

GitHub(dotnet/fsharp)
コアライブラリの主なソースコードはここ。F#で書かれており、一部は読みやすくサンプルコードにもなります。4

Midoliy
F#を日本語で解説しているサイトの中で一番分かりやすいと思います。
とっつきやすいぶん、詳細までは書いてないのでもっと詳しく知りたい場合はおとなしくMSDN読みましょう。


  1. .NET は遅いと勘違いされがちですが、近年はMicrosoftの努力によってかなり速くなっています。少なくともインタプリタで動作するRubyやPythonよりは100倍速いです。 

  2. 日本語がおかしい? 英語版のほうが分かりやすいですか? 

  3. null は .NET の他言語との相互運用のために仕方なく用意してあるとも言えます。 

  4. 「コアライブラリ内でのみ使える構文」があったりするので、参考にする際はご注意を。 

94
55
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
94
55