3/1から入社した職場でF#愛でLTしてきたよ。
この世界の片隅で使われている言語
みなさん、F# というプログラミング言語をご存知でしょうか
お前誰よ
- 寺嶋 哲(Terajima Satoshi)
- @meganehouser
- 3月1日からjoin
- 前職: Excelおじさん
- よさこいとHouse踊れます
F#とは
- マイクロソフトが開発した .NET Framework向けのプログラミング言語
- OCamlベースの関数型+OOP言語
- 静的片付け+型推論
- クロスプラットフォーム(Mac,Linux,Win,Android,iOS,JS/HTML5,GPU,FreeBSD)
- オープンソース
- fsharp/fsharp
F#の特徴的な機能
- exe,dllにコンパイルまたはスクリプト実行できる
- REPL標準装備
- オフサイドルールを元にしたコンパクトな軽量構文
- パイプライン演算子
- 判別共用体とパターンマッチ
- コンピュテーション式
- タイププロバイダ
- 測定単位
オフサイドルールを元にしたコンパクトな軽量構文
例 C#の場合
using System;
namespace HelloWorld
{
class Hello
{
static string AddTitle(string name)
{
return name + "さん";
}
static void Main()
{
var name = Console.ReadLine();
var nameWithTitle = AddTitle(name);
Console.WriteLine($"Hello {NameWithTitle}!");
}
}
}
F#の場合
open System
let addTitle name = name + "さん"
let nameWithTitle = Console.ReadLine() |> addTitle
printf "Hello, %s!" nameWithTitle
パイプライン演算子
関数の戻り値を次の関数の引数として渡す機能 - F#から広まった機能 - Elixir、ES2019は標準で入っている
let plus n1 n2 = n1 + n2
let multiply n1 n2 = n1 * n2
10 |> plus 40 |> multiply 2 // 100
パイプライン演算子 例2
type Person = {name:string; age: int}
let persons = [
{name="Bob"; age=32}
{name="Alice"; age=24}
]
persons
|> List.filter(fun p -> p.age > 30)
|> List.filter(fun p -> p.name.StartsWith("B"))
|> List.map(fun p -> String.Format("{0},{1}歳", (p.name), p.age))
|> fun ps -> printf "%s" (ps.Head)
コンピュテーション式
- 内部DSL。モナド用の構文として使われることも多い
- 式変形により言語の用意する構文の意味をカスタマイズ
open System
open System.Net
let fetchHtmlAsync url =
async {
let uri = Uri(url)
use webClient = new WebClient()
let! html = webClient.AsyncDownloadString(uri)
return html
}
let html = "https://dotnetfoundation.org"
|> fetchHtmlAsync
|> Async.RunSynchronously
printfn "%s" html
コード出典 非同期プログラミング | Microsoft Docs
タイププロバイダー
任意のメタデータを与えると、コンパイラがコンパイル時に"型のないもの"に"型を与えて"提供してくれる機能
- FSharp.Data
- JSON、XML、CSV、HTMLドキュメント
- SQLProvider
- DBのテーブル・カラムへの型付
- Azure のストレージ型プロバイダー
- Azure Blob、テーブル、およびキュー等
- FSharp.Data.GraphQL
- GraphQLProviderURLで指定されたGraphQL serverに基づいて型
F#の好きな機能
判別共用体(直和型)とパターンマッチ
- いわゆるリッチなEnum
改善前のコード
let doSomething (x:int) :int =
// 何か失敗するかもしれない処理
n
判別共用体(直和型)とパターンマッチ
- 判別共用体を使って書き換えたコード
type Result =
| Success of int
| Failure of int * string
let doSomething' x =
let result = // 何iか失敗するかもしれない処理
if result > 9 then
Success(result)
else
Failure(result, "faild to do something")
let result = doSomething' 1
match result with
| Success(n) -> printfn "%d" n
| Failure(errCode, errMessage) -> printfn "[%d] %s" errCode errMessage
判別共用体(直和型)とパターンマッチ
- 失敗した以降は関数を適用しない中値演算子を定義してみる
let (|>>) (x:Result) (f:int -> Result) =
match x with
| Success data -> f data
| Failure e -> Failure e
let result = 10 |> doSomething1 |>> doSomething2 |>> doSmething3
測定単位
- 数値型に単位をつけられる機能
[<Measure>] type km
[<Measure>] type hours
> 1<km> < 2<km>;;
val it : bool = true
> 1<km> < 2<hours>;;
error
let speed: int<km/hours> = 100<km> / 1<hours>;;
let doHoge (s: int<km/hours>) = // do somehting
F#何に使ってたの
- REPLで .NET Frameworkのクラスの挙動を確認
- F#スクリプトで作成中のC#アプリケーションまたはライブラリをアドホックに呼び出す
- F#スクリプトでテストデータの生成やログの集計とか
「F#、割とマジでWindowsでまともにストレスなく使える唯一のスクリプト言語なので。@igeta談」
海外でのF#コミュニティ
-
わりと活発
- F# eXchange 2019 | 4th - 5th Apr 2019 | London
- F# Weekly – Sergey Tihon's Blog
-
Kaggleのコアの解析アルゴリズムはF#で書かれていたらしい。
The F# code is consistently shorter, easier to read, easier to refactor and contains far fewer bugs. As our data analysis tools have developed … we’ve become more productive. Testimonials | The F# Software Foundation
日本でのF#コミュニティ
- 現在ではあまり活発な動きはない
- 2014年頃まではF# MVP受賞するような方が2〜3人いた
- F#談話室 → 2017年以降開催なし
- Advent Calendar → 2017年で終了
- fsugjpのgitterが残っているのみ
この~~世界~~"日本"の片隅で使われている言語
なぜ日本では片隅でしか使われていないの
- 日本では.NETはエンプラ系で使われることが多く、言語を変更するモチベーションがない
- みんなC#で満足している
- アンダース・ヘルスバーグがリードアーキテクトですし
- C#がF#の便利な機能を取り込んでいっている
Javaに対するベターJavaであるScala/Kotlin的な立場になれなかった
まとめ
- 言語が流行るかどうかはその国でのコンテクキストにも依存する
- コミュニティが強い言語は強い
- Pythonは日本でも海外でもみんなで盛り上げていく感じがあって素晴らしい
- F#のことも記憶の片隅に残しておいてほしい