Skip to content

필사 모드: 모던 F# 2026 — F# 9 (.NET 9) / Saturn / Giraffe / Bolero / Fable / Feliz / Elmish / Fantomas 심층 가이드

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

프롤로그 — 2026년에도 F#을 쓰는 사람들이 있다

매년 누군가는 묻는다. "F#, 아직도 써요?"

쓴다. 그것도 .NET 진영 안에서 점점 더 진지하게 쓴다.

- **Jet.com**(현재 Walmart Labs 일부)은 2010년대 중반부터 가격 결정 엔진을 F#으로 짰고, 인수 뒤에도 코어 가격 모델 일부는 F#으로 남았다.

- **Microsoft** 본사 안에서는 컴파일러 팀과 Azure 일부 서비스(특히 비용 계산, 라이센스, 분석 도구)가 F#을 쓴다. F# 자체가 Microsoft Research Cambridge에서 Don Syme가 2005년부터 만든 언어다.

- **CitiBank**, **Credit Suisse**, **Standard Chartered**, **Bank of America** — 금융 도메인의 가격 결정·리스크 모델에서 F#은 꾸준한 한 자리를 차지한다. 도메인 모델링이 강하고, 부수효과를 타입으로 가두기 좋아서다.

- **AT&T**, **Demetrix**, **Indaba Music**, **GameSys**, **Tachyus**, **G-Research** — 데이터 파이프라인, 머신러닝, 게임 백엔드에서 F# 코드가 돈다.

- 일본의 **ユーザックシステム(Usac System)**은 도쿄·오사카에서 자동화·물류 솔루션을 F#과 .NET으로 만든다. MS Japan의 F# 에반젤리스트들이 이 회사를 자주 언급한다.

2010년대 F#의 적은 "쓰기 어렵다"가 아니었다. 진짜 적은 **"Mono 시절에는 비-Windows에서 빌드가 깨지고, Visual Studio for Mac은 절반만 동작하며, Paket인지 NuGet인지 결정하기 어렵다"**였다. 그게 2026년에는 어떻게 되어 있을까.

답: **.NET 9가 진짜로 크로스플랫폼이 되었고, F# 9는 nullable reference types를 완성했으며, Fantomas가 표준 포매터로 자리 잡았다**. 그래서 더 이상 "내 노트북에서는 안 빌드된다" 같은 일이 거의 없다. 그리고 dotnet CLI 하나로 Windows, macOS, Linux에서 동일하게 굴러간다.

이 글은 2026년의 F# 스택을 한 호흡으로 본다. 컴파일러부터 웹 프레임워크, 클라이언트 사이드, 데스크톱 UI, 빌드 도구, 데이터, 수치·ML, SQL, 파서, 그리고 사람들까지.

1장 · 2026년 모던 F# — .NET 9의 시대

먼저 한 장의 풍경.

모던 F# 2026 스택

[런타임] .NET 9 (2024.11 LTS) ── 크로스플랫폼 단일 SDK

[컴파일러] F# 9 (2024.11) / F# 10 preview (GitHub main)

[빌드] dotnet CLI / FAKE / Paket / MSBuild

[웹 백엔드] Saturn (Rails 스타일, opinionated)

Giraffe (ASP.NET Core 함수형 미들웨어)

Suave (구식, 자체 HTTP)

[웹 클라이언트] Fable (F# to JS) + Feliz (React) + Elmish (Elm pattern)

Bolero (Blazor WebAssembly + F#)

[데스크톱] Avalonia.FuncUI (선언적 크로스플랫폼 UI)

[도구] Fantomas (포매터) / Ionide (VS Code) / FsAutoComplete

Polyglot Notebooks (Jupyter on .NET)

[데이터] FSharp.Data (CSV/JSON/XML/SQL type providers)

Donald (얇은 SQL 클라이언트)

[수치·ML] MathNet.Numerics (선형대수)

DiffSharp (자동미분, PyTorch 스타일)

TorchSharp (libtorch 바인딩) + ML.NET

[병행성] Hopac (concurrent ML 스타일)

async / Task

[파서] FParsec (Parsec 포팅)

[클라우드] F# in Azure Functions / AWS Lambda

F# in Aspire (분산 .NET 워크플로)

[프로덕션 사용자] Jet.com (Walmart) / Microsoft / CitiBank /

Credit Suisse / GameSys / Tachyus / Usac

이게 2026년의 F# 지형도다. 박스 하나하나 들어가 보자.

2장 · F# 9 (2024.11, .NET 9 동시 출시) — nullable + DU 개선

F# 9는 2024년 11월, .NET 9와 함께 정식 출시되었다. .NET 9는 12개월 STS(Standard Term Support)이지만, F# 9 자체는 SDK에 묶여서 다음 .NET 10 LTS(2025년 11월 예정)까지 자연스럽게 따라간다.

핵심 변화는 셋이다.

Nullable reference types 완성

C#은 2019년 C# 8에서 `?`를 통한 nullable reference types를 도입했다. F#은 자체적으로 `Option<'T>`(`'T option`)를 가지고 있어서 한참 동안 "F# 코드에서는 null이 거의 없다"는 입장을 유지했다. 하지만 BCL(C#으로 짠 .NET 표준 라이브러리)과 상호운용할 때마다 null이 새어 들어왔다.

F# 9는 **interop 경계에서 nullable reference types를 1급 시민으로 만든다**.

// F# 9: nullable annotation

let processName (name: string | null) =

match name with

| null -> "(anonymous)"

| n -> n.ToUpper()

// C# 메서드를 호출할 때도 안전

let s: string | null = System.Environment.GetEnvironmentVariable("HOME")

match s with

| null -> printfn "HOME not set"

| home -> printfn "HOME = %s" home

`string | null`은 C# 9의 `string?`과 정확히 대응한다. 컴파일러는 이걸 검사해서 "null을 unwrap 하지 않은 채로 메서드 호출하면 경고"를 띄운다.

Discriminated union 개선

DU(discriminated union)는 F#의 영혼이다. F# 9는 두 가지를 개선했다.

1. **Struct DU의 박싱 비용 절감** — `[<Struct>]` DU를 더 적극적으로 stack에 머무르게 한다.

2. **Union case의 가시성 제어** — `private`/`internal` 가시성을 union의 각 case에도 적용할 수 있다.

[<Struct>]

type Result<'T, 'E> =

| Ok of value: 'T

| Error of error: 'E

// 가시성이 다른 case

type DbHandle =

private | Open of System.Data.IDbConnection

| Closed

표준 라이브러리 개선

- `List.randomShuffle`, `Array.randomChoice` 등 무작위성 헬퍼 추가.

- `Result` 모듈 확장: `Result.toList`, `Result.toOption`, `Result.toArray`.

- `Seq.tryExactlyOne` — 정확히 한 개의 요소만 있을 때 Some, 아니면 None.

let xs = [1; 2; 3]

let shuffled = xs |> List.randomShuffle

// e.g. [2; 1; 3]

let oneOnly = [42] |> Seq.tryExactlyOne

// Some 42

let twoElems = [1; 2] |> Seq.tryExactlyOne

// None

3장 · F# 10 preview — GitHub에서 굴러가는 중

F# 10은 GitHub `dotnet/fsharp` 메인 브랜치에서 활발히 개발 중이다. 2026년 5월 현재, 다음 후보 기능이 RFC(Request for Comments)에 올라와 있다.

tasks `let!` 분기 단축

`task { ... }` 안에서 여러 비동기 결과를 합칠 때 `let!` 패턴이 길어지던 문제. F# 10은 이걸 짧게 쓸 수 있는 표현식 빌더 확장을 검토 중이다.

// F# 9 스타일

task {

let! a = getUserAsync userId

let! b = getOrdersAsync userId

return (a, b)

}

// F# 10 preview에서 검토 중인 short form

task {

let! (a, b) = getUserAsync userId, getOrdersAsync userId

return (a, b)

}

Type provider 비동기화

`FSharp.Data`의 `JsonProvider`, `CsvProvider`는 컴파일 타임에 스키마를 가져와서 타입을 만든다. 큰 스키마에서 IDE가 멈추는 문제가 있었는데, F# 10은 type provider 호출을 비동기로 만드는 인프라를 도입하려 한다.

Resumable code 개선

F# 6에서 도입된 resumable code(`task { }`, `taskSeq { }`의 기반)는 컴파일러 내부 기능이지만, F# 10은 이걸 사용자에게도 더 안전하게 노출하려 한다. Hopac이나 자체 effect 라이브러리를 만들 때 도움이 된다.

Self-type constraints

C# 11의 `static abstract` 인터페이스 멤버에 대응하는 F# 측 문법. SRTP(Statically Resolved Type Parameters)를 더 자연스럽게 쓸 수 있게 한다.

F# 10은 .NET 10 LTS와 함께 2025년 11월 출시 예정이다.

4장 · Saturn — opinionated 웹 프레임워크 (Giraffe 기반)

Saturn은 Krzysztof Cieslak(SAFE Stack 메인테이너, Ionide 만든 사람)이 만든 풀스택 웹 프레임워크다. **Giraffe 위에 깔린 Rails 같은 레이어**라고 보면 된다.

핵심 컨셉

Saturn은 **application builder DSL**을 제공한다. ASP.NET Core의 미들웨어 파이프라인을 F# 빌더 구문으로 깔끔하게 정리한 것.

open Saturn

let app =

application {

use_router topRouter

url "http://0.0.0.0:8085/"

use_gzip

use_static "public"

use_developer_exceptions

}

run app

이게 전부다. `application { }` 안의 각 토큰은 사실 함수다. Saturn은 `application` computation expression을 정의하고, 각 키워드(`use_router`, `url`, ...)는 `ApplicationBuilder` 상에서 작동한다.

Controller — MVC 스타일

Saturn은 controller도 builder로 제공한다.

let userController = controller {

index (fun ctx -> "Listing all users" |> Controller.text ctx)

show (fun ctx id -> sprintf "Showing user %i" id |> Controller.text ctx)

create (fun ctx -> "Creating new user" |> Controller.text ctx)

edit (fun ctx id -> sprintf "Editing user %i" id |> Controller.text ctx)

delete (fun ctx id -> sprintf "Deleting user %i" id |> Controller.text ctx)

}

let topRouter = router {

forward "/users" userController

}

REST 7개 액션이 한 builder에 다 들어간다. Rails 사용자에게는 친숙한 구조다.

SAFE Stack

Saturn은 단독으로 쓰일 수도 있지만, 보통 **SAFE Stack**의 일부로 쓰인다.

- **S** — Saturn (서버)

- **A** — Azure (호스팅)

- **F** — Fable (클라이언트, F# to JS)

- **E** — Elmish (Elm 패턴)

이 네 글자가 SAFE다. `dotnet new SAFE`로 풀스택 F# 프로젝트가 만들어진다. 클라이언트와 서버가 같은 F# 도메인 타입을 공유하는 것이 가장 큰 매력이다.

5장 · Giraffe — 함수형 ASP.NET Core

Giraffe는 Saturn의 아래쪽 절반이다. ASP.NET Core의 HttpContext 파이프라인을 함수형으로 감싼 라이브러리.

HttpHandler

Giraffe의 핵심 추상은 `HttpHandler`다.

type HttpHandler = HttpFunc -> HttpContext -> HttpFuncResult

// 여기서 HttpFunc = HttpContext -> HttpFuncResult

// HttpFuncResult = Task<HttpContext option>

즉, "다음 핸들러"와 "현재 컨텍스트"를 받아 "수정된 컨텍스트(또는 None)"를 비동기로 돌려주는 함수. 이게 ASP.NET Core 미들웨어 한 칸과 정확히 대응한다.

합성

`>=>` 연산자로 핸들러를 합성한다.

open Giraffe

let webApp =

choose [

route "/" >=> text "Hello, world"

route "/json" >=> json {| message = "hello" |}

route "/api/users" >=> requireAuth >=> getUsers

routef "/user/%i" (fun id -> sprintf "User %i" id |> text)

setStatusCode 404 >=> text "Not Found"

]

`choose`는 첫 번째로 매칭되는 핸들러를 실행한다. `>=>`는 "이 핸들러를 통과시키고 다음을 이어 붙여라"라는 뜻. 함수 합성과 정확히 같은 모양이지만, `Task<HttpContext option>`을 다루는 Kleisli composition이다.

View — GiraffeViewEngine

HTML을 F# 코드로 만들 수 있다.

open Giraffe.ViewEngine

let layout (content: XmlNode list) =

html [] [

head [] [

title [] [ str "Giraffe" ]

link [ _rel "stylesheet"; _href "/style.css" ]

]

body [] content

]

let indexView =

layout [

h1 [] [ str "Hello, Giraffe" ]

p [] [ str "Functional ASP.NET Core" ]

]

JSX와 비슷하지만, F# 함수와 리스트로 표현된다. 정적 타입이 보장된다.

6장 · Bolero — Blazor + F#

Bolero는 IntelliFactory에서 시작해 지금은 fsbolero 조직에서 유지하는 프로젝트로, **Blazor WebAssembly 위에서 F#으로 SPA를 만들게 해 준다**.

왜 Bolero인가

- Blazor는 C#으로 WebAssembly SPA를 만드는 Microsoft의 공식 프레임워크다.

- Bolero는 그 위에 F#과 Elmish(MVU) 패턴을 얹는다.

- 결과: **타입 안전 + 컴포넌트 + F# DSL로 만든 HTML + Elm 스타일 상태 관리**.

open Bolero

open Bolero.Html

open Elmish

type Model = { count: int }

type Message =

| Increment

| Decrement

let init () = { count = 0 }, Cmd.none

let update msg model =

match msg with

| Increment -> { model with count = model.count + 1 }, Cmd.none

| Decrement -> { model with count = model.count - 1 }, Cmd.none

let view model dispatch =

div {

h1 { "Bolero Counter" }

p { sprintf "Count: %d" model.count }

button {

on.click (fun _ -> dispatch Increment)

"+"

}

button {

on.click (fun _ -> dispatch Decrement)

"-"

}

}

Bolero의 `div { }`, `button { }`은 computation expression이다. 안에 자식 요소·속성·이벤트 핸들러를 자유롭게 섞을 수 있다.

Server-side vs WebAssembly

Bolero는 두 가지 호스팅 모델을 다 지원한다.

- **Server-side Blazor** — UI 업데이트가 SignalR을 통해 서버에서 일어남.

- **Blazor WebAssembly** — F# 코드가 .NET IL로 컴파일되고, WASM 런타임에서 직접 실행.

WebAssembly 모드는 서버 부하가 없지만 초기 다운로드가 큰 편. Bolero 3.x부터 AOT(Ahead Of Time) 컴파일을 지원해 시작 속도가 많이 좋아졌다.

7장 · Fable — F# to JavaScript

Fable은 Alfonso Garcia-Caro가 시작한 F# to JavaScript 컴파일러다. 지금은 Maxime Mangel을 비롯한 코어 팀이 유지한다.

Fable 5

2024년 출시된 Fable 5는 여러 백엔드를 지원한다.

- **JavaScript** — 기본 백엔드. Node.js, 브라우저에서 동작.

- **TypeScript** — `.ts` 파일로 출력. 다른 TS 코드와 자연스럽게 섞인다.

- **Python** — F#을 Python으로 변환. Jupyter 노트북, 파이썬 백엔드.

- **Rust** — 실험적. F#의 일부 안전성을 Rust로 옮겨 본다.

- **Dart** — Flutter 앱을 F#으로 짤 수 있다.

// F# 소스

module App

open Browser

let main () =

let body = document.body

body.innerHTML <- "<h1>Hello from F#</h1>"

main ()

이걸 `dotnet fable`로 컴파일하면 JavaScript ESM이 나온다.

동작 방식

Fable은 F# 컴파일러 서비스(`FSharp.Compiler.Service`)를 사용해 F# 소스를 AST로 파싱한 뒤, 그 AST를 JavaScript(또는 다른 타깃)로 변환한다. .NET BCL 함수는 Fable의 자체 JS 구현으로 매핑된다(`Map`, `Seq`, `List`, `Option` 등).

Fable.React / Feliz / Elmish와 함께

Fable 자체는 컴파일러일 뿐. UI 라이브러리는 별도로 깔아서 쓴다.

dotnet new -i Fable.Template

dotnet new fable-react

npm install

npm run start

기본 Fable React 템플릿이 시작점이다.

8장 · Feliz — F# React-like DSL

Feliz는 Zaid Ajaj가 만든 React DSL이다. Fable.React보다 짧고 깔끔하게 React 컴포넌트를 표현한다.

예제

open Feliz

let helloWorld = Html.div [

prop.className "container"

prop.children [

Html.h1 "Hello, Feliz"

Html.p "F# React without JSX"

]

]

[<ReactComponent>]

let Counter () =

let count, setCount = React.useState 0

Html.div [

Html.h2 (sprintf "Count: %d" count)

Html.button [

prop.onClick (fun _ -> setCount (count + 1))

prop.text "+"

]

]

- `Html.div [ ... ]` — div 태그.

- `prop.className`, `prop.onClick`, `prop.children` — 모든 prop이 강타입.

- `[<ReactComponent>]` — Feliz 컴파일 플러그인이 React 컴포넌트로 변환.

- `React.useState`, `React.useEffect` 등 모든 hook이 F# 시그니처로 노출.

JSX 없이 F# 문법만으로 React를 다 쓸 수 있다.

Feliz.Bulma / Feliz.MaterialUI

생태계가 두텁다.

- **Feliz.Bulma** — Bulma CSS 프레임워크 래퍼.

- **Feliz.MaterialUI** — Material-UI 컴포넌트의 F# 바인딩.

- **Feliz.Recharts** — Recharts 차트 라이브러리.

- **Feliz.Plotly** — Plotly.

거의 모든 인기 React 라이브러리에 Feliz 래퍼가 있다.

9장 · Elmish — Elm 패턴 in F#

Elmish는 Elm 언어의 MVU(Model-View-Update) 패턴을 F#으로 옮긴 라이브러리다. Bolero, Fable + React, SAFE Stack의 상태 관리 표준이다.

세 가지 함수

// 1. 초기 상태

let init () : Model * Cmd<Msg> = ...

// 2. 메시지 처리

let update (msg: Msg) (model: Model) : Model * Cmd<Msg> = ...

// 3. 렌더링

let view (model: Model) (dispatch: Msg -> unit) : ReactElement = ...

이게 전부다. Redux나 Vuex보다 훨씬 단순하다. Elm을 안다면 그대로 옮겨 적으면 된다.

예시

open Elmish

open Elmish.React

open Feliz

type Model = { Count: int }

type Msg =

| Increment

| Decrement

| Reset

let init () = { Count = 0 }, Cmd.none

let update msg model =

match msg with

| Increment -> { model with Count = model.Count + 1 }, Cmd.none

| Decrement -> { model with Count = model.Count - 1 }, Cmd.none

| Reset -> { Count = 0 }, Cmd.none

let view model dispatch =

Html.div [

Html.h1 (sprintf "Count: %d" model.Count)

Html.button [

prop.onClick (fun _ -> dispatch Increment)

prop.text "+"

]

Html.button [

prop.onClick (fun _ -> dispatch Decrement)

prop.text "-"

]

Html.button [

prop.onClick (fun _ -> dispatch Reset)

prop.text "Reset"

]

]

Program.mkProgram init update view

|> Program.withReactSynchronous "elmish-app"

|> Program.run

브라우저에 띄우는 코드는 마지막 4줄이 전부다. `Program.mkProgram`이 init/update/view를 받아 실행 루프를 만든다.

Cmd — 부수효과 격리

`Cmd<Msg>`는 "지금 일어나야 할 부수효과"를 표현하는 타입이다. HTTP 요청, 타이머, localStorage 접근 등이 다 Cmd로 표현된다.

let loadUserCmd userId =

Cmd.OfPromise.either

(fun () -> Fetch.fetchAs<User> (sprintf "/api/users/%d" userId))

()

UserLoaded

LoadFailed

update 함수는 순수하다. 부수효과는 Cmd로 빠져나가서 runtime이 실행한다. 테스트하기가 매우 쉽다.

10장 · Avalonia.FuncUI — 선언적 데스크톱 UI

Avalonia는 WPF의 정신을 이어받은 크로스플랫폼 .NET UI 프레임워크다. Windows, macOS, Linux, iOS, Android, WebAssembly에서 동일한 코드가 돈다.

Avalonia.FuncUI는 그 Avalonia 위에 **F# computation expression 기반의 함수형 DSL**을 얹은 것.

예시

open Avalonia.FuncUI.DSL

open Avalonia.Controls

open Avalonia.Layout

let view () =

Component (fun ctx ->

let count = ctx.useState 0

DockPanel.create [

DockPanel.children [

TextBlock.create [

TextBlock.text (sprintf "Count: %d" count.Current)

TextBlock.horizontalAlignment HorizontalAlignment.Center

]

Button.create [

Button.content "+"

Button.onClick (fun _ -> count.Set (count.Current + 1))

]

Button.create [

Button.content "-"

Button.onClick (fun _ -> count.Set (count.Current - 1))

]

]

]

)

XAML이 없다. 모든 UI가 F# 코드로 표현된다. React의 hook과 비슷한 `useState` 패턴이 있다.

누가 쓰나

- **JetBrains Rider**의 일부 UI는 Avalonia로 만들어진다(IntelliJ 플랫폼 자체는 Java/Kotlin이지만, 별도 도구는 Avalonia).

- **Sirius A**(F# 커뮤니티의 IRC/Matrix 클라이언트).

- 사내 도구를 F#으로 짜고 싶은 .NET 팀들. Visual Studio for Mac이 종료된 뒤로 macOS에서 .NET UI를 짤 수 있는 거의 유일한 옵션이다.

11장 · 도구 — Fantomas / Paket / FAKE / Polyglot Notebooks

Fantomas

Fantomas는 F#의 공식 포매터다. Florian Verdonck를 비롯한 코어 팀이 유지한다.

dotnet tool install -g fantomas

fantomas src/

- 컴파일러의 AST를 직접 사용해 포매팅한다. 따라서 결과가 의미적으로 동일함이 보장된다.

- `.editorconfig` 또는 `fantomas-config.fsharpsettings`로 스타일을 조정한다.

- VS Code(Ionide), Rider, Visual Studio 통합 지원.

2024년부터 Fantomas는 F# 컴파일러와 같은 저장소(`fsprojects/fantomas`)에서 관리되며, F# 코드 컨벤션의 사실상 표준이 되었다.

Paket

Paket은 NuGet의 대안 패키지 매니저다. Forki Steffen Forkmann이 만들었다.

장점:

- 트랜시티브 의존성을 `paket.lock` 한 파일에 명시적으로 고정한다(NuGet PackageReference는 SDK 스타일로 많이 좋아졌지만 lock은 여전히 미묘하다).

- GitHub repo, gist, HTTP URL을 직접 의존성으로 추가할 수 있다.

- F# 프로젝트에서 특히 인기.

source https://api.nuget.org/v3/index.json

nuget Giraffe ~> 6.0

nuget FSharp.Data ~> 6.0

github fsharp/FSharp.Core

NuGet이 충분히 좋아져서 Paket의 입지는 줄어들었지만, 큰 모노레포에서는 여전히 선호된다.

FAKE

FAKE(F# Make)는 F#으로 빌드 스크립트를 짜는 도구다.

#r "paket: nuget Fake.Core.Target //"

#load ".fake/build.fsx/intellisense.fsx"

open Fake.Core

open Fake.IO

Target.create "Clean" (fun _ -> Shell.cleanDirs [ "bin"; "obj" ])

Target.create "Build" (fun _ ->

DotNet.build id "src/MyApp.fsproj"

)

Target.create "Test" (fun _ ->

DotNet.test id "tests/MyApp.Tests.fsproj"

)

"Clean" ==> "Build" ==> "Test"

Target.runOrDefault "Test"

`==>` 연산자가 의존성 그래프를 만든다. Make, Rake, Gulp의 F# 버전이라고 보면 된다.

2026년에는 `dotnet` CLI와 GitHub Actions의 조합으로 FAKE 없이도 빌드 파이프라인을 짤 수 있어서 신규 프로젝트에서는 덜 쓰이지만, 기존 코드베이스에서는 여전히 표준이다.

Polyglot Notebooks

Polyglot Notebooks는 Microsoft의 노트북 환경이다. Jupyter와 같은 UX지만 .NET 위에서 돌고, **한 노트북 안에 F#, C#, PowerShell, JavaScript, SQL, KQL 셀을 섞을 수 있다**.

VS Code 확장 `Polyglot Notebooks`를 설치하면 끝.

// F# 셀

open Microsoft.DotNet.Interactive

#r "nuget: FSharp.Data, 6.4.0"

open FSharp.Data

let stocks = CsvProvider<"https://example.com/stocks.csv">.GetSample()

stocks.Rows |> Seq.take 5 |> Seq.iter (fun r -> printfn "%A" r)

데이터 분석, 교육, 리포트 작성에서 F#이 Python을 대체할 수 있는 거의 유일한 통로다.

12장 · FSharp.Data — Type Providers

Type provider는 F#의 킬러 피처다. **컴파일 타임에 외부 데이터 소스의 스키마를 가져와서, IDE의 자동완성을 통해 강타입으로 접근**하게 해 준다.

CsvProvider

open FSharp.Data

type Stocks = CsvProvider<"https://example.com/stocks.csv">

let stocks = Stocks.GetSample()

for row in stocks.Rows do

printfn "%s: open=%f, close=%f" row.Date row.Open row.Close

`row.Date`, `row.Open`, `row.Close`는 컴파일러가 CSV 헤더를 읽어서 만든 강타입 프로퍼티다. 컬럼명이 바뀌면 컴파일 에러로 즉시 발견된다.

JsonProvider

type GitHubRepo = JsonProvider<"https://api.github.com/repos/dotnet/fsharp">

let repo = GitHubRepo.GetSample()

printfn "Name: %s" repo.Name

printfn "Stars: %d" repo.StargazersCount

printfn "Default branch: %s" repo.DefaultBranch

JSON 응답을 타입으로 자동 매핑. 키 이름이 바뀌면 컴파일러가 잡아 준다.

SqlProvider / WorldBankProvider / FreebaseProvider

- **SqlProvider** — PostgreSQL, SQL Server, SQLite, MySQL에 접속해서 테이블/뷰/저장 프로시저를 타입으로 노출.

- **WorldBankProvider** — World Bank 통계 데이터에 강타입 접근.

- **FreebaseProvider** — (Freebase가 종료되어 지금은 잘 안 쓰이지만 type provider의 시연 예제로 유명했다.)

Type provider는 **F#만이 가진 기능**이다. C#, Java, Kotlin에는 이런 메타프로그래밍 면이 없다. 데이터 처리 프로젝트라면 이거 하나만으로도 F#을 쓸 가치가 있다.

13장 · MathNet.Numerics / DiffSharp — 수치 / 자동미분

MathNet.Numerics

MathNet.Numerics는 .NET용 수치 계산 라이브러리다. NumPy, SciPy의 .NET 버전이라고 보면 된다.

open MathNet.Numerics.LinearAlgebra

let m = matrix [[ 1.0; 2.0 ]

[ 3.0; 4.0 ]]

let v = vector [ 5.0; 6.0 ]

let result = m * v

printfn "%A" result

// DenseVector 2-Double

// 17

// 39

let inv = m.Inverse()

printfn "%A" inv

- Dense / Sparse 행렬.

- BLAS / LAPACK 가속 옵션(Intel MKL, OpenBLAS).

- 통계, 적분, 최적화, FFT, 분포 등.

DiffSharp

DiffSharp는 .NET용 자동미분 라이브러리다. Atılım Güneş Baydin 등이 만들었다. **PyTorch처럼 텐서 연산을 정의하면 그 미분을 자동으로 계산해 준다**.

open DiffSharp

let f (x: Tensor) = x ** 2.0 + 2.0 * x + 1.0

let x = dsharp.tensor [ 1.0; 2.0; 3.0 ]

let y = f x

let dy = dsharp.diff f x

printfn "y = %A" y // [4; 9; 16]

printfn "dy = %A" dy // [4; 6; 8] (즉 2x + 2)

DiffSharp는 백엔드로 TorchSharp(libtorch C++ 바인딩)나 자체 reference backend를 쓸 수 있다. GPU 가속도 지원.

연구 코드, 미분 가능 프로그래밍, 그래디언트 기반 최적화에 쓰인다.

14장 · TorchSharp + ML.NET — 머신러닝

TorchSharp

TorchSharp는 .NET용 PyTorch 바인딩이다. libtorch C++ 라이브러리를 P/Invoke로 부른다. **PyTorch와 거의 1:1 대응되는 API를 F#에서 쓸 수 있다**.

open TorchSharp

open type torch

let device = if cuda.is_available() then CUDA else CPU

let model =

Sequential(

("fc1", Linear(784L, 256L)),

("relu1", ReLU()),

("fc2", Linear(256L, 10L))

)

|> fun m -> m.``to``(device)

let x = randn([| 64L; 784L |]).``to``(device)

let y = model.forward(x)

printfn "Output shape: %A" y.shape

타입 안전한 텐서 연산, GPU 지원, 모델 저장/로드.

ML.NET

ML.NET은 Microsoft의 .NET 머신러닝 프레임워크다. F#에서도 매끄럽게 쓸 수 있다.

open Microsoft.ML

open Microsoft.ML.Data

[<CLIMutable>]

type HouseData = {

Size: float32

Price: float32

}

[<CLIMutable>]

type Prediction = {

[<ColumnName("Score")>]

Price: float32

}

let mlContext = MLContext()

let trainingData = [

{ Size = 1.1f; Price = 1.2f }

{ Size = 1.9f; Price = 2.3f }

{ Size = 2.8f; Price = 3.0f }

{ Size = 3.4f; Price = 3.7f }

]

let dataView = mlContext.Data.LoadFromEnumerable trainingData

let pipeline =

mlContext.Transforms

.Concatenate("Features", "Size")

.Append(mlContext.Regression.Trainers.Sdca(labelColumnName = "Price", maximumNumberOfIterations = 100))

let model = pipeline.Fit dataView

let predictor = mlContext.Model.CreatePredictionEngine<HouseData, Prediction>(model)

let size = { Size = 2.5f; Price = 0f }

let prediction = predictor.Predict size

printfn "Predicted price for size %f: %f" size.Size prediction.Price

ML.NET은 그래디언트 부스팅, 랜덤 포레스트, 로지스틱 회귀, 추천 시스템, 텍스트 분류, 이미지 분류 등 폭넓은 알고리즘을 지원한다. TensorFlow / ONNX 모델 임포트도 가능.

F#의 `[<CLIMutable>]` 어트리뷰트는 ML.NET이 요구하는 setter를 만들어 준다(F# 레코드는 기본적으로 immutable이라서).

15장 · F# in Azure Functions / AWS Lambda

Azure Functions

F# Isolated Worker model은 .NET 9에서 표준이다.

namespace MyApp

open System

open Microsoft.Azure.Functions.Worker

open Microsoft.Azure.Functions.Worker.Http

open Microsoft.Extensions.Logging

type HelloFunction(logger: ILogger<HelloFunction>) =

[<Function("Hello")>]

member _.Run

([<HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")>] req: HttpRequestData)

=

logger.LogInformation "F# HTTP trigger function processed a request"

let response = req.CreateResponse(System.Net.HttpStatusCode.OK)

response.WriteString "Hello from F# on Azure Functions"

response

Microsoft 자체가 F#을 Azure Functions의 1급 언어로 지원한다. `func init --worker-runtime dotnet-isolated --language fsharp`로 템플릿 생성.

AWS Lambda

AWS의 .NET 6/8 런타임에서 F# Lambda를 실행할 수 있다.

namespace MyLambda

open Amazon.Lambda.Core

[<assembly: LambdaSerializer(typeof<Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer>)>]

do ()

type Handler() =

member _.Hello (input: string) (_: ILambdaContext) : string =

sprintf "Hello %s from F# Lambda" input

`Amazon.Lambda.Tools` CLI로 배포한다. 큰 회사에서는 클라우드 자동화 스크립트를 F#으로 짜는 사례가 있다.

16장 · Donald / Suave / Hopac / FParsec — 그 외

Donald — 얇은 SQL 클라이언트

Donald는 ADO.NET 위에 깔린 가벼운 SQL 헬퍼다. EF Core 같은 ORM이 아니라, **SQL을 그대로 쓰고 결과를 강타입으로 매핑**하는 방식.

open Donald

let conn = new System.Data.SqlClient.SqlConnection(connStr)

let sql = "SELECT id, name, email FROM users WHERE active = 1"

type User = { Id: int; Name: string; Email: string }

let readUser (rd: System.Data.IDataReader) =

{ Id = rd.ReadInt32 "id"

Name = rd.ReadString "name"

Email = rd.ReadString "email" }

let users =

conn

|> Db.newCommand sql

|> Db.query readUser

LINQ도 ORM도 싫고 SQL 그대로 쓰고 싶을 때.

Suave

Suave는 Henrik Feldt가 만든 자체 HTTP 서버 + 라우팅 라이브러리. ASP.NET Core 이전 시대(2014~)부터 존재했다. **ASP.NET Core 위에 안 깔려 있는 독립 웹 서버**라는 게 특징이고, 작은 사이드 프로젝트에서 인기가 있었다.

open Suave

open Suave.Filters

open Suave.Operators

open Suave.Successful

let app =

choose

[ GET >=> path "/" >=> OK "Hello, Suave"

GET >=> pathScan "/user/%d" (fun id -> OK (sprintf "User %d" id)) ]

startWebServer defaultConfig app

2026년에는 신규 프로젝트에서 Giraffe/Saturn에 자리를 거의 다 내줬지만, 작은 도구·CLI에 HTTP 인터페이스를 붙일 때 가벼운 선택지로 남아 있다.

Hopac

Hopac은 Vesa Karvonen이 만든 동시성 라이브러리다. Concurrent ML / Reppy의 channels-and-jobs 모델을 F#으로 옮긴 것.

open Hopac

open Hopac.Infixes

let producer (ch: Ch<int>) =

Job.forUpToIgnore 0 9 (fun i -> Ch.give ch i)

let consumer (ch: Ch<int>) =

Job.forUpToIgnore 0 9 (fun _ ->

Ch.take ch >>= fun v ->

Job.unit (printfn "Received: %d" v))

job {

let ch = Ch<int>()

do! Job.start (producer ch)

do! consumer ch

}

|> run

`Job<'T>`는 lightweight thread다. 채널 기반 메시지 전달, 동기 통신, 선택(`Alt`) 같은 Concurrent ML 패턴을 그대로 쓸 수 있다.

`async`/`Task`보다 더 표현력 있는 동시성이 필요할 때, 고성능 메시지 패싱이 필요할 때 쓴다. Jet.com이 가격 결정 엔진의 일부에 Hopac을 썼다는 사례가 유명하다.

FParsec

FParsec은 Stephan Tolksdorf의 Parsec(Haskell 파서 콤비네이터) F# 포팅이다.

open FParsec

let pInteger : Parser<int, unit> = pint32

let pPlus = pchar '+' >>. spaces

let pSum =

pInteger .>>. (pPlus >>. pInteger)

|>> (fun (a, b) -> a + b)

let result = run pSum "12 + 30"

match result with

| Success (v, _, _) -> printfn "Sum = %d" v

| Failure (err, _, _) -> printfn "Parse error: %s" err

LL(1) 이상의 백트래킹 파서를 쉽게 만든다. DSL, 설정 파일 파서, 도메인 특화 언어를 만들 때 표준 도구.

17장 · 한국 / 일본 — 한국 .NET 엔터프라이즈, Usac, MS Japan

한국

한국의 F# 커뮤니티는 솔직히 작다. .NET 자체가 한국에서는 게임 서버(특히 유니티 백엔드), 일부 금융권, 공공기관 SI 정도에 집중된다. F#은 그 중 일부 회사에서 도메인 모델링이나 데이터 파이프라인 도구로 쓰인다.

- **카카오 / 라인의 일부 데이터 분석 스크립트** — Polyglot Notebooks를 통해 F#이 ad-hoc 분석에 쓰이는 경우가 있다(공식 발표는 없음, 컨퍼런스 사이드 토크에서 자주 나오는 이야기).

- **NHN, 넷마블, 펄어비스** 등 게임 회사의 일부 백오피스 도구.

- **금융권** — 일부 증권사·자산운용사에서 모델링 도구로 F#을 쓰는 사례가 있지만 공개된 케이스 스터디는 적다.

- **MSDN.kr / .NET Korea User Group** — 페이스북 그룹과 디스코드. F# 전용 한국 모임은 따로 없고 .NET 전체 모임에서 가끔 F# 이야기가 나온다.

한국에서 F# 책으로 한국어로 번역된 것은 거의 없다. Don Syme의 *Expert F#* 영문판이나 *Stylish F#* 영문판을 보는 것이 보통이다.

일본

일본은 한국보다 F# 커뮤니티가 두텁다.

- **ユーザックシステム(Usac System)** — 도쿄·오사카·나고야의 RPA / 물류 자동화 회사. 자체 제품 일부를 F#으로 짠다. Microsoft Japan의 F# 에반젤리스트 가와카미 산(@kos59125, Kazuya Kawakami)이 자주 인용한다.

- **F# Tokyo** — 매년 열리는 사용자 모임. 100명 단위로 모이는 해도 있다.

- **F# Online Meetup Japan** — 코로나 이후 온라인 위주로 전환되어 2022년부터 정기적으로 열린다.

- **Microsoft Japan의 F# evangelists** — Microsoft가 일본 .NET 커뮤니티에서 F#을 꾸준히 푸시했다. Kazuhisa Yokota, Kazuya Kawakami 등이 그 자리에 있었다.

- **凸版印刷 (Toppan Printing)**, **NTT Data 일부** — 사내 도구·분석 파이프라인에서 F# 사용 사례가 보고된 적이 있다.

일본어 F# 자료가 한국어보다 많다. Qiita의 fsharp 태그에는 수백 개 글이 있다. Don Syme의 책 일본어판도 존재한다.

18장 · 누가 F#을 배워야 하나

솔직하게.

**배우면 좋은 사람**

- **.NET 백엔드를 짜는 C# 개발자** — 같은 BCL, 같은 런타임, 같은 NuGet 패키지를 쓰면서 함수형 스타일과 도메인 모델링을 얻는다. C# 9에서 들어온 records, pattern matching, switch expressions는 사실상 F#에서 영감을 받았다. F#을 알면 C#이 어디로 가고 있는지 미리 안다.

- **금융·보험·로지스틱스·헬스케어 도메인의 모델러** — discriminated union으로 도메인을 표현하는 능력이 다른 언어와 차원이 다르다. "불가능한 상태를 표현 불가능하게 만든다(make illegal states unrepresentable)"는 Scott Wlaschin의 슬로건이 진짜로 성립한다.

- **OCaml / Haskell을 알지만 산업에서 쓸 회사를 찾지 못한 사람** — F#은 ML 계열의 친척이고, .NET이라는 거대한 산업 기반 위에서 돈다. "내 함수형 지식을 어디서 써먹지?"의 답이 될 수 있다.

- **데이터 분석을 강타입으로 하고 싶은 사람** — type provider는 정말 다른 차원의 도구다.

**안 배워도 되는 사람**

- **.NET을 절대 안 쓸 사람** — F#은 .NET 위에서 돈다. .NET을 안 쓸 거면 Haskell, OCaml, Scala가 더 합리적이다.

- **순수성에 집착하는 함수형 마니아** — F#은 멀티패러다임이다. 가변성도 허용하고, OOP 클래스도 쓸 수 있다. Haskell 같은 순수성을 원한다면 실망할 수 있다.

- **빠른 학습 곡선이 우선인 사람** — F# 자체는 어렵지 않지만, "C#과 BCL과 ASP.NET Core를 모르면서 F#만 배운다"는 것은 사실상 불가능하다. .NET 생태계 학습이 같이 따라온다.

F#의 진짜 가치는 **".NET이라는 거대한 산업 인프라 위에서 ML 스타일 함수형 도메인 모델링을 한다"**는 데 있다. 이게 매력으로 다가오면 배울 가치가 충분하다.

19장 · 참고 / References

- F# 9 발표 — `devblogs.microsoft.com/dotnet/announcing-fsharp-9`

- F# 언어 레퍼런스 — `learn.microsoft.com/dotnet/fsharp/language-reference`

- F# Foundation — `fsharp.org`

- .NET 9 발표 — `devblogs.microsoft.com/dotnet/announcing-dotnet-9`

- F# GitHub — `github.com/dotnet/fsharp`

- Saturn — `saturnframework.org`

- Giraffe — `giraffe.wiki`

- Bolero — `fsbolero.io`

- Fable — `fable.io`

- Feliz — `zaid-ajaj.github.io/Feliz`

- Elmish — `elmish.github.io`

- Avalonia.FuncUI — `funcui.avaloniaui.net`

- Avalonia — `avaloniaui.net`

- Fantomas — `fsprojects.github.io/fantomas`

- Paket — `fsprojects.github.io/Paket`

- FAKE — `fake.build`

- Polyglot Notebooks — `code.visualstudio.com/docs/polyglot`

- FSharp.Data — `fsprojects.github.io/FSharp.Data`

- MathNet.Numerics — `numerics.mathdotnet.com`

- DiffSharp — `diffsharp.github.io`

- TorchSharp — `github.com/dotnet/TorchSharp`

- ML.NET — `dotnet.microsoft.com/apps/machinelearning-ai/ml-dotnet`

- Donald — `github.com/pimbrouwers/Donald`

- Suave — `suave.io`

- Hopac — `github.com/Hopac/Hopac`

- FParsec — `www.quanttec.com/fparsec`

- F# in Azure Functions — `learn.microsoft.com/azure/azure-functions/functions-reference-fsharp`

- SAFE Stack — `safe-stack.github.io`

- F# Software Foundation Slack — `fsharp.org/guides/slack`

- F# Tokyo — `fsugjp.connpass.com`

- Don Syme 블로그 — `dsyme.github.io`

- Scott Wlaschin — Domain Modeling Made Functional — `fsharpforfunandprofit.com`

- Krzysztof Cieslak — Ionide / Saturn — `kcieslak.io`

현재 단락 (1/582)

매년 누군가는 묻는다. "F#, 아직도 써요?"

작성 글자: 0원문 글자: 21,620작성 단락: 0/582