F 샤프
1. 개요
F#은 강력한 형식의 함수형 프로그래밍 언어로, 마이크로소프트에서 개발되었다. 다양한 버전으로 출시되었으며, 2005년에 처음 등장하여 .NET 프레임워크를 지원해왔다. F#은 함수형, 명령형, 객체 지향 프로그래밍을 지원하며, 람다 함수, 클로저, 패턴 매칭, 대수적 데이터 형식, 튜플, 리스트 컴프리헨션, 모나드 패턴 등 다양한 기능을 제공한다. 또한, 단위 측정, 메타프로그래밍, 에이전트 프로그래밍을 지원하며, 웹, 크로스 플랫폼 앱, 분석 프로그래밍, 스크립팅 등 다양한 분야에서 활용된다. F#은 OCaml과 호환되며, 오픈 소스 커뮤니티를 통해 지속적으로 발전하고 있다.
| 이름 | F# |
|---|---|
| 설계자 | 돈 사이미, 마이크로소프트 리서치 |
| 개발자 | 마이크로소프트, F# 소프트웨어 재단 |
| 출시일 | 2005년, 버전 1.0 |
| 최신 버전 | 9.0 |
| 최신 버전 출시일 | 2024년 11월 12일 |
| 형식 체계 | 정적, 강한, 추론 |
| 웹사이트 | F# 공식 웹사이트 |
| F# 마이크로소프트 공식 웹사이트 | |
| 위키책 | F# 프로그래밍 |
| 파일 확장자 | .fs, .fsi, .fsx, .fsscript |
| 프로그래밍 패러다임 | 다중 패러다임: 함수형, 명령형, 객체 지향, 에이전트 지향, 메타 프로그래밍, 반사, 병행 |
|---|---|
| 영향 받은 언어 | C#, Erlang, 하스켈, ML, OCaml, Python, Scala |
| 영향을 준 언어 | C#, Elm, F*, LiveScript |
| 플랫폼 | 크로스 플랫폼: .NET 프레임워크, Mono |
|---|
| 라이선스 | MIT |
|---|
-
2002년 개발된 프로그래밍 언어 -
시스템베릴로그
SystemVerilog는 Verilog를 확장한 하드웨어 기술 및 검증 언어로서, 객체 지향 프로그래밍, 제약 기반 난수 생성, 어설션 등의 고급 검증 기능을 제공하여 하드웨어 설계 및 검증의 효율성을 높인다. -
2002년 개발된 프로그래밍 언어 -
아이오 (프로그래밍 언어)
아이오는 스티브 데코르테가 2002년에 개발한 순수 객체 지향 및 프로토타입 기반의 프로그래밍 언어로서, 코드-애즈-데이터, 호모이코닉 특징과 액터 모델 기반의 동시성, 코루틴, 메타 프로그래밍 등의 고급 기능을 제공한다. -
ML 프로그래밍 언어 계열 -
OCaml
OCaml은 ML 계열의 함수형 프로그래밍 언어로서 클래스 기반 객체 지향 프로그래밍 기능을 지원하며, 강력한 타입 시스템, 타입 추론, 꼬리 재귀 최적화 등의 특징을 가진다. -
ML 프로그래밍 언어 계열 -
ML (프로그래밍 언어)
ML은 1970년대 초에 개발된 프로그래밍 언어로, 강력한 타입 시스템, 일급 함수, 가비지 컬렉션, 정적 타이핑 등의 기능을 제공하며 다양한 분야에서 활용된다. -
마이크로소프트 리서치 -
마이크로소프트 코그니티브 툴킷
-
마이크로소프트 리서치 -
Cω
2. 역사
마이크로소프트 리서치(Microsoft Research)의 Don Syme영어 등이 2002년부터 OCaml을 기반으로 F# 개발을 시작했다. F#의 F는 함수형 프로그래밍 언어(Functional programming language) 및 System F에서 유래했다. 앤드류 케네디(Andrew Kennedy)는 단위 측정 설계에 기여했다.
F#은 OCaml에서 많은 요소를 물려받은 함수형 및 객체 지향의 멀티 패러다임이다. 형 안전하며 형 추론 기능을 가진다. 하지만 오버로딩을 지원하기 때문에 OCaml이 가진 형 추론의 완전성을 잃었다. C# 및 Visual Basic .NET 등 .NET 언어와 상호 운용성이 있으며, .NET 클래스 라이브러리의 이용 및 개발이 가능하다. Mono 및 Xamarin을 이용한 Android 애플리케이션 개발도 지원된다. 이전에는 실버라이트를 이용한 Windows Phone 7 애플리케이션 개발도 지원되었다.
F#의 개발 환경은 Visual Studio의 유료 버전 제품 (또는 무료 Community 에디션)에 Visual F#으로 포함되어 있으며, Express 에디션에서 사용할 수 있는 무료 도구 배포도 이루어지고 있다. Visual F# Tools 4.1에서 Roslyn (compiler)영어를 지원하게 되었다. 또한, Mono 및 .NET Core 환경용으로 F# 컴파일러가 이식되었기 때문에, macOS나 리눅스 등에서도 F# 프로그램의 개발 및 실행이 가능하다.
OCaml 호환 표준 라이브러리를 갖추고 있으며, F#과 OCaml 모두에서 컴파일할 수 있는 코드를 작성하는 것도 가능하다. 그러나 클래스 구문 등은 F#과 OCaml에서 다르다.
2.1. 버전
| F# 버전 | 언어 명세 | 날짜 | 플랫폼 | 런타임 |
|---|---|---|---|---|
| 1.x | 2005년 5월 | Windows | .NET 1.0 - 3.5 | |
| 2.0 | [http://fsharp.org/specs/language-spec/index.html#f-20 2010년 8월] | 2010년 4월 | 리눅스, macOS, Windows | .NET 2.0 - 4.0, Mono |
| 3.0 | [http://fsharp.org/specs/language-spec/index.html#f-30 2012년 11월] | 2012년 8월 | 리눅스, macOS, Windows; 자바스크립트, GPU | .NET 2.0 - 4.5, Mono |
| 3.1 | [http://fsharp.org/specs/language-spec/index.html#f-31 2013년 11월] | 2013년 10월 | 리눅스, macOS, Windows; 자바스크립트, GPU | .NET 2.0 - 4.5, Mono |
| 4.0 | [http://fsharp.org/specs/language-spec/index.html#f-40 2016년 1월] | 2015년 7월 | ||
| 4.1 | [http://fsharp.org/specs/language-spec/index.html#f-41 2018년 5월] | 2017년 3월 | 리눅스, macOS, Windows, 자바스크립트, GPU | .NET 3.5 - 4.6.2, .NET, Mono |
| 4.5 | 2018년 8월 | 리눅스, macOS, Windows, 자바스크립트, GPU | .NET 4.5 - 4.7.2, .NET Core SDK 2.1.400 | |
| 4.6 | 2019년 3월 | 리눅스, macOS, Windows, 자바스크립트, GPU | .NET 4.5 - 4.7.2, .NET Core SDK 2.2.300 | |
| 4.7 | 2019년 9월 | 리눅스, macOS, Windows, 자바스크립트, GPU | .NET 4.5 - 4.8, .NET Core SDK 3.0.100 | |
| 5.0 | 2020년 11월 | 리눅스, macOS, Windows, 자바스크립트, GPU | .NET SDK 5.0.100 | |
| 6.0 | 2021년 11월 | 리눅스, macOS, Windows, 자바스크립트, GPU | .NET SDK 6.0.100 | |
| 7.0 | 2022년 11월 | 리눅스, macOS, Windows, 자바스크립트, GPU | .NET SDK 7.0.100 | |
| 8.0 | 2023년 11월 | 리눅스, macOS, Windows, 자바스크립트, GPU | .NET SDK 8.0.100 |
2.2. 언어 발전
F#는 개방형 개발 및 엔지니어링 프로세스를 사용한다. 언어 진화 과정은 F# 소프트웨어 재단과 함께 언어 설계를 위한 생각하는 독재자(BDFL)인 돈 심(Don Syme)이 마이크로소프트 리서치(Microsoft Research)에서 관리한다. 과거 F# 언어 버전은 마이크로소프트(Microsoft)와 마이크로소프트 리서치(Microsoft Research)에서 폐쇄형 개발 프로세스를 사용하여 설계했다.
F#는 2010 에디션에 Visual Basic (.NET) 및 C#과 동일한 수준(옵션)으로 처음 포함되었으며, 이후 모든 에디션에 남아 있어 언어의 광범위한 사용과 지원이 이루어지고 있다.
F#는 영국 케임브리지에 있는 마이크로소프트 리서치에서 시작되었다. 이 언어는 원래 돈 심에 의해 설계 및 구현되었으며, F# 팀에서는 F가 "Fun"(재미)을 의미한다고 한다. 앤드류 케네디(Andrew Kennedy)는 단위 측정 설계에 기여했다. Visual Studio용 Visual F# 도구는 마이크로소프트에서 개발했다. F# 소프트웨어 재단은 마이크로소프트 Visual F# 도구 팀에서 제공하는 오픈 소스 컴파일러 구현을 통합하여 F# 오픈 소스 컴파일러 및 도구를 개발했다.
3. 문법
F#은 OCaml을 계승한 언어로, OCaml과 호환되는 장황 구문 (verbose syntax영어)과 파이썬과 같은 오프사이드 규칙을 사용한 경량 구문 (lightweight syntax영어)의 두 종류 구문을 사용할 수 있다. 표준 설정에서는 경량 구문이 활성화되어 있다. F#은 타입을 자동으로 유추하는 강력한 형식 지정 언어이다.
3.1. F# 함수의 형태
함수형 프로그래밍의 "Hello World"라고 할 만한 것은 팩토리얼을 계산하는 코드이다. F#으로는 다음과 같이 표현할 수 있다.
let rec fact n =
match n with
| 0 -> 1
| _ -> n * fact (n-1);;
이 코드는 팩토리얼을 재귀 함수로 정의한 것이다. 일반적으로 함수를 정의할 때는 `let`을 쓰고, 재귀함수를 정의할 때는 `let rec`와 같이 명시한다. 함수의 마지막에는 두 개의 세미콜론으로 끝마침을 해 준다.
위 함수 정의는 수학 교과서에서 볼 수 있는 팩토리얼의 정의와 비슷하다. F# 코드는 문법과 계산 방식의 측면에서 수학적 언어와 닮았다.
F#은 자동으로 타입을 유추한다. 위의 `fact` 함수는 `(int -> int)` 타입, 즉 정수를 인자로 받아 또 다른 정수를 반환하는 함수이다.
두 번째 줄에서 F#의 또 다른 중요한 특성인 패턴 매칭을 볼 수 있다. 패턴 매칭은 `match ... with ...`와 같이 표현한다. 함수 `fact`는 인자가 0이면 1을 반환하고, 아니면 두 번째 케이스를 실행하여 0에 도달할 때까지 `fact`을 재귀적으로 계속 호출한다. 패턴 매칭에서 `_`는 디폴트 케이스를 의미한다.
3.2. 개선된 팩토리얼 함수
fsharp
#light
let factorial n =
let rec fac a x =
match x with
| k when k < 1 -> 1I
| k when k = 1 -> a
| v -> fac (a * (bigint x)) (x - 1)
fac 1I n
```
팩토리얼 함수는 지수 함수보다 훨씬 빠르게 커지므로 큰 정수 계산이 가능해야 하고, 재귀 호출 함수의 성능도 고려해야 한다. 큰 정수의 곱셈 계산을 위해 팩토리얼 값은 `bigint` 타입을 사용하고, 함수의 인자는 `int` 타입을 사용한다. `bigint` 타입 리터럴은 `int` 타입 리터럴 끝에 `I`를 붙여 표현한다. (예: `4`는 `int` 타입, `4I`는 `bigint` 타입). `int` 타입을 `bigint` 타입으로 변환하려면 `bigint x`와 같이 표현식 왼쪽에 `bigint`를 붙인다.
위의 `factorial` 함수는 `(int -> bigint)` 타입의 함수이다. 함수 안에서 재귀 호출 함수 `fac`을 정의하는 중첩 구조로 되어 있다. `fac` 함수의 첫 번째 인자 `a`는 재귀 호출 과정에서 계산된 이전 단계의 팩토리얼 값을 저장하는 상태 역할을 한다.
예를 들어 4! 계산 과정은 다음과 같다.
* fac 1I 4
* => fac (4I) 3
* => fac (12I) 2
* => fac (24I) 1
* => 24I
이 코드는 5000!을 계산할 때도 스택 오버플로우를 걱정할 필요가 없다. F# 언어는 패턴 매칭(match)에 의한 재귀 호출이 상태에 의한 호출이기 때문이다. 이러한 재귀 호출을 꼬리 재귀 호출이라고 한다.
4. 언어 개요
F#은 함수형 프로그래밍과 객체 지향 프로그래밍을 모두 지원하는 함수 우선 언어이다. C#에서 사용할 수 있는 객체 지향 기능을 지원하면서, 함수형 프로그래밍 언어에서 일반적으로 발견되는 많은 기능을 갖춘 강력한 형식 지정 언어이다. 이러한 기능을 통해 F# 프로그램은 완전한 함수형 스타일로 작성될 수 있으며, 함수형 스타일과 객체 지향 스타일을 혼합하여 사용할 수도 있다.
2002년부터 마이크로소프트 리서치(Microsoft Research)의 Don Syme영어 등이 OCaml을 기반으로 개발을 시작했다. OCaml에서 많은 요소를 물려받은 함수형 및 객체 지향의 멀티 패러다임 프로그래밍 언어이다. 형 안전성을 가지며, 형 추론 기능을 갖추고 있다. 하지만 오버로딩을 지원하기 때문에 OCaml이 가진 형 추론의 완전성은 잃었다.
C# 및 Visual Basic .NET 등 .NET 언어와 상호 운용성이 있으며, .NET 클래스 라이브러리의 이용 및 개발이 가능하다. Mono 및 Xamarin을 이용한 Android 애플리케이션 개발도 지원된다. F#의 F는 Functional programming language(함수형 프로그래밍 언어) 및 System F에서 유래했다.
4.1. 함수형 프로그래밍
F#은 객체 지향 프로그래밍 기능을 지원하는 동시에, 함수형 프로그래밍에서 주로 사용되는 여러 기능을 갖춘 강력한 형식 지정 언어이다. F# 프로그램을 완전한 함수형 스타일로 작성하거나, 함수형 스타일과 객체 지향 스타일을 혼합하여 사용할 수 있다.
F#에서 지원하는 함수형 기능은 다음과 같다.
* 모든 것은 표현식이다.
* 형식 추론(힌들리-밀너 형식 추론 사용)
* 일급 함수
* 포획 의미론(클로저 등)을 가진 익명 함수
* 불변 변수 및 객체
* 지연 평가 지원
* 고차 함수
* 중첩 함수
* 커링
* 패턴 매칭
* 대수적 데이터 형식
* 튜플
* 리스트 컴프리헨션
* 모나드 패턴 지원 (컴퓨테이션 표현식이라고 함)
* 꼬리 재귀 최적화
F#은 즉시 평가를 사용하며, 경우에 따라 지연 평가를 사용하는 표현식 기반 언어이다. `if` 표현식, `try` 표현식 및 루프를 포함한 F#의 모든 문은 정적 형식을 가진 구성 가능한 표현식이다. 값을 반환하지 않는 함수와 표현식은 `unit` 반환 형식을 갖는다. F#은 `let` 키워드를 사용하여 값을 이름에 바인딩한다. 예를 들어,
```fsharp
let x = 3 + 4
```
는 값 `7`을 이름 `x`에 바인딩한다.
새로운 형식은 `type` 키워드를 사용하여 정의된다. 함수형 프로그래밍을 위해 F#은 튜플, 레코드, 구별된 유니온, 리스트, 옵션 및 결과 형식을 제공한다. 튜플은 n개의 값 집합을 나타내며, 여기서 n ≥ 0이다. 값 n은 튜플의 항수라고 한다. 3-튜플은 `(A, B, C)`로 표시되며, 여기서 A, B, C는 서로 다른 형식의 값일 수 있다. 튜플은 실행 시에 값의 수가 설계 시점에 알려지고 일정하게 유지될 때만 값을 저장하는 데 사용할 수 있다.
레코드는 데이터 멤버의 이름이 지정된 형식이다. 레코드 정의의 예는 다음과 같다.
```fsharp
type R =
{ Name : string
Age : int }
```
레코드는 `let r = { Name="AB"; Age=42}`와 같이 생성할 수 있다. `with` 키워드는 `{ r with Name="CD"}`와 같이 레코드의 복사본을 만드는 데 사용되며, `r`을 복사하고 `Name` 필드의 값을 변경하여 새 레코드를 생성한다(마지막 예제에서 생성된 레코드가 `r`로 명명되었다고 가정).
구별된 유니온 형식은 형식 안전 버전의 C 유니온이다. 예를 들어,
```fsharp
type A =
| UnionCaseX of string
| UnionCaseY of int
```
유니온 형식의 값은 각 유니온 케이스에 해당할 수 있다. 각 유니온 케이스가 전달하는 값의 형식은 각 케이스의 정의에 포함된다.
리스트 형식은 `head::tail` 표기법(`::`는 cons 연산자) 또는 `[item1; item2; item3]`과 같은 약식을 사용하여 표현되는 불변의 연결 리스트이다. 빈 리스트는 `[]`로 작성된다. 옵션 형식은 `Some(x)` 또는 `None` 선택 항목이 있는 구별된 유니온 형식이다. F# 형식은 제네릭일 수 있으며, 제네릭 .NET 형식으로 구현된다.
F#은 람다 함수와 클로저를 지원한다. F#의 모든 함수는 일급 값이며 불변이다. 함수는 커리 될 수 있다. 일급 값이므로 함수는 다른 함수의 인수로 전달될 수 있다. 다른 함수형 프로그래밍 언어와 마찬가지로 F#은 `>>` 및 `<<` 연산자를 사용하여 함수 합성을 허용한다.
F#은 값을 생성하는 코드를 통해 시퀀스 `seq { ... }`, 리스트 `[ ... ]` 또는 배열 `[| ... |]`을 정의하는 시퀀스 표현식을 제공한다. 예를 들어,
```fsharp
seq { for b in 0 .. 25 do
if b < 15 then
yield b*b }
```
는 0에서 25까지의 숫자 범위에서 숫자를 필터링하여 0에서 14까지의 숫자의 제곱 시퀀스를 형성한다. 시퀀스는 생성기이다. 즉, 값은 필요에 따라 생성된다(즉, 지연 평가됨). 반면 리스트와 배열은 즉시 평가된다.
F#은 패턴 매칭을 사용하여 값을 이름에 바인딩한다. 패턴 매칭은 구별된 유니온에 액세스할 때도 사용된다. 유니온은 패턴 규칙에 대해 값 일치되며, 일치가 성공하면 규칙이 선택된다. F#은 또한 확장 가능한 패턴 매칭 형태인 액티브 패턴을 지원한다. 예를 들어, 형식에 대한 일치하는 여러 방법이 존재할 때 사용된다.
F#은 컴퓨테이션 표현식이라고 하는 구성 가능한 계산을 정의하기 위한 일반적인 구문을 지원한다. 시퀀스 표현식, 비동기 계산 및 쿼리는 특정 종류의 컴퓨테이션 표현식이다. 컴퓨테이션 표현식은 모나드 패턴의 구현이다.
4.2. 명령형 프로그래밍
F#은 다음과 같은 명령형 프로그래밍 기능을 지원한다.
* `let` 키워드를 사용한 값 바인딩.
* `unit` 반환 형식을 가진 함수 및 표현식.
* 튜플, 레코드, 구별된 유니온, 리스트, 옵션, 결과 형식.
* `::` (cons 연산자) 또는 `[item1; item2; item3]` 표기법을 사용한 불변 연결 리스트.
* `seq { ... }`, `[ ... ]`, `[| ... |]`를 사용한 시퀀스 표현식 (생성기는 지연 평가되고, 리스트와 배열은 즉시 평가됨).
* 패턴 매칭을 통한 값 바인딩 및 구별된 유니온 접근.
* 컴퓨테이션 표현식 (모나드 패턴 구현)을 통한 구성 가능한 계산 정의.
* `async{ ... }`를 사용한 비동기 프로그래밍 지원 (비동기 워크플로우).
* .NET 작업 직접 생성, 사용 및 반환 지원 (버전 6.0부터).
4.3. 객체 지향 프로그래밍
F#은 다른 공용 언어 기반 (CLI) 언어와 마찬가지로 객체 지향 프로그래밍을 통해 CLI 형식을 사용할 수 있다. F#은 C#에서 사용할 수 있는 객체 지향 기능을 지원한다.
2002년부터 마이크로소프트 리서치(Microsoft Research)의 Don Syme영어 등이 OCaml을 기반으로 개발을 시작했다.
4.4. 비동기 프로그래밍
F#은 비동기 워크플로우를 통해 비동기 프로그래밍을 지원한다. 비동기 워크플로우는 `async{ ... }` 내의 일련의 명령으로 정의된다. 다음은 그 예이다.
```fsharp
let asynctask =
async { let req = WebRequest.Create(url)
let! response = req.GetResponseAsync()
use stream = response.GetResponseStream()
use streamreader = new System.IO.StreamReader(stream)
return streamreader.ReadToEnd() }
```
`let!`은 오른쪽에 있는 표현식(응답 가져오기)이 비동기적으로 수행되어야 하지만 결과가 사용 가능할 때만 흐름이 계속되어야 함을 나타낸다. 즉, 코드 블록의 관점에서 볼 때 응답을 가져오는 것은 차단 호출과 같지만, 시스템의 관점에서 볼 때 스레드는 차단되지 않으며 이 스레드에 필요한 결과가 나올 때까지 다른 흐름을 처리하는 데 사용될 수 있다.
async 블록은 `Async.RunSynchronously` 함수를 사용하여 호출할 수 있다. 여러 async 블록은 `async` 객체 목록을 사용하는 `Async.Parallel` 함수를 사용하여 병렬로 실행할 수 있다. (예제에서 `asynctask`는 async 객체이다.) 이 함수는 목록의 작업을 병렬로 실행하기 위해 다른 async 객체를 생성한다. 결과 객체는 `Async.RunSynchronously`를 사용하여 호출된다.
F#의 제어 역전은 이 패턴을 따른다.
버전 6.0부터 F#은 .NET 작업을 직접 생성, 사용 및 반환하는 것을 지원한다.
```fsharp
open System.Net.Http
let fetchUrlAsync (url:string) = // string -> Task
task {
use client = new HttpClient()
let! response = client.GetAsync(url)
let! content = response.Content.ReadAsStringAsync()
do! Task.Delay 500
return content
}
// Usage
let fetchPrint() =
let task = task {
let! data = fetchUrlAsync "https://example.com"
printfn $"{data}"
}
task.Wait()
4.5. 병렬 프로그래밍
F#은 `Async.Parallel`, `Async.Start` 등의 함수를 통해 병렬 프로그래밍을 지원한다. F# 표준 라이브러리의 `Array.Parallel` 함수형 프로그래밍 연산자, `System.Threading.Tasks` 작업 프로그래밍 모델, .NET 스레드 풀 등을 사용할 수 있다. F# 코드를 GPU 코드와 같은 대체 병렬 실행 엔진으로 동적 변환하는 기능도 지원한다.
4.6. 단위 측정
F# 타입 시스템은 숫자 값에 대한 단위 검사를 지원한다.
F#에서는 미터나 킬로그램과 같은 단위(측정)를 부동 소수점, 부호 없는 정수 및 부호 있는 정수 값에 할당할 수 있다. 이를 통해 컴파일러는 이러한 값을 포함하는 산술 연산이 차원적으로 일치하는지 확인할 수 있으며, 예를 들어 길이를 시간에 실수로 더하는 것과 같은 일반적인 프로그래밍 실수를 방지할 수 있다.
단위(측정) 기능은 F# 타입 추론과 통합되어 사용자 코드에서 최소한의 타입 주석만 필요로 한다.
```fsharp
[
[
let distance = 100.0
let time = 5.0 // float
let speed = distance/time // float
[
[
[
[
let better_age = 3u
```
F# 정적 타입 검사기는 컴파일 시간에 이 기능을 제공하지만, 단위는 컴파일된 코드에서 지워진다. 결과적으로 런타임에 값의 단위를 결정하는 것은 불가능하다.
4.7. 메타프로그래밍
F#은 사용자 정의 도메인 특화 언어를 F# 언어 내에 임베딩하기 위해, 특히 계산식(computation expressions)을 통해 메타프로그래밍의 몇 가지 형태를 허용한다.
F#은 런타임 메타프로그래밍을 위한 기능인 쿼테이션(quotations)을 포함한다. 쿼테이션 표현식은 F# 표현식의 추상 구문 트리 표현으로 평가된다. 마찬가지로, `[<ReflectedDefinition>]` 특성으로 레이블된 정의도 쿼테이션 형태로 액세스할 수 있다. F# 쿼테이션은 F# 코드를 자바스크립트 및 GPU 코드로 컴파일하는 것을 포함하여 다양한 용도로 사용된다. 쿼테이션은 F# 코드 표현식을 프로그램의 다른 부분에서 사용할 데이터로 나타내면서도 구문적으로 올바른 F# 코드여야 한다.
F# 3.0은 F# 타입 공급자라고 불리는 정적으로 확장 가능한 타입 생성을 통해 컴파일 시점 메타 프로그래밍 형태를 도입했다. F# 타입 공급자는 F# 컴파일러와 도구가 컴파일 시간에 필요에 따라 컴파일러에 타입 정보를 제공하는 구성 요소로 확장될 수 있도록 한다. F# 타입 공급자는 Freebase 지식 그래프를 포함하여 확장 가능한 방식으로 연결된 정보 소스에 강력한 형식으로 액세스하는 데 사용되어 왔다.
F# 3.0에서 F# 쿼테이션 및 계산 표현식 기능이 결합되어 LINQ 쿼리를 구현한다. 타입 공급자, 쿼리 및 강력한 형식의 함수형 프로그래밍의 조합을 정보 풍부 프로그래밍이라고 한다.
4.8. 에이전트 프로그래밍
F#은 경량 비동기 에이전트의 메모리 내 구현을 통해 액터 프로그래밍 모델의 변형을 지원한다. 다음은 F# 코드로 에이전트를 정의하고 2개의 메시지를 게시하는 예시이다.
```fsharp
type Message =
| Enqueue of string
| Dequeue of AsyncReplyChannel
5. 개발 도구
* 비주얼 스튜디오는 마이크로소프트에서 제공하는 Visual F# 도구를 설치하여 F# 프로젝트를 만들고, 실행하고, 디버깅하는 데 사용할 수 있다. Visual F# 도구에는 F# 코드를 작성하면서 실행할 수 있는 비주얼 스튜디오에서 호스팅되는 대화형 콘솔이 포함되어 있다. 비주얼 스튜디오 for Mac 또한 F# 프로젝트를 완벽하게 지원한다.
* 비주얼 스튜디오 코드는 [http://ionide.io/ Ionide 확장]을 통해 F#을 완벽하게 지원한다.
* F#은 모든 텍스트 편집기로 개발할 수 있다. 이맥스와 같은 편집기에서 특별히 지원된다.
* JetBrains Rider는 2019.1 릴리스부터 F# 코드 개발에 최적화되었다.
* LINQPad는 버전 2.x부터 F#을 지원해 왔다.
6. 응용 분야
F#은 범용 프로그래밍 언어이다. 2010년대에 F#은 C#의 최적화된 대안으로 자리매김했으며, F#의 스크립팅 능력과 모든 마이크로소프트 제품과의 상호 언어 호환성은 개발자들 사이에서 인기를 얻게 했다.
6.1. 웹 프로그래밍
SAFE 스택(https://safe-stack.github.io/)은 웹 애플리케이션 개발을 위한 엔드투엔드 F# 스택이다. 서버 측에서는 ASP.NET Core를 사용하고, 클라이언트 측에서는 [https://fable.io Fable]을 사용한다.
또 다른 엔드투엔드 F# 옵션으로는 WebSharper 프레임워크가 있다.
6.2. 크로스 플랫폼 앱 개발
F#은 iOS 및 안드로이드용 앱을 개발하기 위해 https://visualstudio.microsoft.com/xamarin/ 비주얼 스튜디오 툴즈 포 자마린과 함께 사용할 수 있다. https://github.com/fsprojects/Fabulous Fabulous 라이브러리는 보다 편리한 함수형 인터페이스를 제공한다.
6.3. 분석 프로그래밍
F#은 특히 정량적 금융 프로그래밍, 에너지 거래 및 포트폴리오 최적화, 머신 러닝, 비즈니스 인텔리전스 및 페이스북에서의 소셜 게임 등에 사용된다.
2010년대에 F#은 C#의 최적화된 대안으로 자리매김했다. F#의 스크립팅 능력과 모든 마이크로소프트 제품과의 상호 언어 호환성은 개발자들 사이에서 인기를 얻게 했다.
7. 오픈 소스 커뮤니티
F# 오픈 소스 커뮤니티에는 F# 소프트웨어 재단과 깃허브의 F# 오픈 소스 그룹이 포함되어 있다. 주요 오픈 소스 F# 프로젝트는 다음과 같다.
* https://fable.io/ Fable - 바벨 기반의 F#에서 Javascript로 변환하는 컴파일러.
* https://fsprojects.github.io/Paket/ Paket - NuGet 저장소를 사용할 수 있지만 중앙 집중식 버전 관리가 가능한 .NET용 대체 패키지 관리자.
* https://fake.build/ FAKE - F# 친화적인 빌드 시스템.
* https://github.com/giraffe-fsharp/Giraffe Giraffe - ASP.NET Core용 기능 지향 미들웨어.
* https://suave.io/ Suave - 경량 웹 서버 및 웹 개발 라이브러리.
8. 호환성
F#은 펀터, 객체, 다형적 변형 등을 제외한 OCaml의 큰 하위 집합으로 작성된 프로그램을 직접 컴파일할 수 있는 "ML 호환 모드"를 지원한다. OCaml 호환 표준 라이브러리를 갖추고 있어 F#과 OCaml 양쪽에서 컴파일 가능한 코드를 작성할 수 있다. 그러나 클래스 구문 등은 F#과 OCaml에서 다르다.
9. 예제
fsharp
// 간단한 Hello World 프로그램
printfn "Hello World!"
```
```fsharp
// 레코드 형식 정의. 레코드는 기본적으로 변경할 수 없으며 구조적 동등성으로 비교
type Person = {
FirstName: string
LastName: string
Age: int
}
// 레코드의 인스턴스 생성
let person = { FirstName = "John"; LastName = "Doe"; Age = 30 }
```
```fsharp
// 이름과 나이, 그리고 두 개의 변경 불가능한 속성을 갖는 생성자를 가진 Person 클래스.
/// 형식 정의에 대한 문서화 주석
type Person(name : string, age : int) =
member x.Name = name
member x.Age = age
/// 클래스 인스턴스화
let mrSmith = Person("Smith", 42)
```
팩토리얼 함수 예제:
```fsharp
/// 패턴 일치 표현식 사용
let rec factorial n =
match n with
| 0 -> 1
| _ -> n * factorial (n - 1)
/// 단일 인수 함수의 경우 (패턴 일치 함수):
let rec factorial = function
| 0 -> 1
| n -> n * factorial (n - 1)
/// fold 및 범위 연산자 사용
let factorial n = [1..n] |> Seq.fold (*) 1
```
반복 예제:
```fsharp
/// 'for' 루프를 사용한 반복
let printList lst =
for x in lst do
printfn $"{x}"
/// 고차 함수를 사용한 반복
let printList2 lst =
List.iter (printfn "%d") lst
/// 재귀 함수 및 패턴 일치를 사용한 반복
let rec printList3 lst =
match lst with
| [] -> ()
| h :: t ->
printfn "%d" h
printList3 t
```
피보나치 수 예제:
```fsharp
/// 피보나치 수 공식
[
let fib n =
let rec g n f0 f1 =
match n with
| 0 -> f0
| 1 -> f1
| _ -> g (n - 1) f1 (f0 + f1)
g n 0 1
/// 다른 접근 방식 - 피보나치 수의 게으른 무한 시퀀스
let fibSeq = Seq.unfold (fun (a,b) -> Some(a+b, (b, a+b))) (0,1)
// 짝수 피보나치 출력
[1 .. 10]
|> List.map fib
|> List.filter (fun n -> (n % 2) = 0)
|> printList
// 동일한 내용, 목록 표현식 사용
[ for i in 1..10 do
let r = fib i
if r % 2 = 0 then yield r ]
|> printList
```
샘플 Windows Forms 프로그램:
```fsharp
// Windows Forms 라이브러리 열기
open System.Windows.Forms
// 창을 만들고 몇 가지 속성을 설정.
let form = new Form(Visible=true, TopMost=true, Text="Welcome to F#")
// 폼에 텍스트를 표시할 레이블 만들기
let label =
let x = 3 + (4 * 5)
new Label(Text = $"{x}")
// 폼에 레이블 추가
form.Controls.Add(label)
// 마지막으로 폼 실행
[
Application.Run(form)
```
비동기 병렬 프로그래밍 샘플 (병렬 CPU 및 I/O 작업):
```fsharp
/// 간단한 소수 감지기
let isPrime (n:int) =
let bound = int (sqrt (float n))
seq {2 .. bound} |> Seq.forall (fun x -> n % x <> 0)
// 비동기 워크플로우를 사용
let primeAsync n =
async { return (n, isPrime n) }
/// 여러 스레드를 사용하여 m과 n 사이의 소수 반환
let primes m n =
seq {m .. n}
|> Seq.map primeAsync
|> Async.Parallel
|> Async.RunSynchronously
|> Array.filter snd
|> Array.map fst
// 테스트 실행
primes 1000000 1002000
|> Array.iter (printfn "%d")