수색…
옵션의 정의
Option
은 차별화 된 노조이며 None
또는 Some
두 가지 경우가 있습니다.
type Option<'T> = Some of 'T | None
Null 값에 대해 Option < 'T> 사용
F#
과 같은 함수형 프로그래밍 언어에서는 null
값이 잠재적으로 위험하고 가난한 스타일 (비 관용적)으로 간주됩니다.
이 C#
코드를 살펴 보겠습니다.
string x = SomeFunction ();
int l = x.Length;
x
가 null
이면 x.Length
가 throw됩니다. 보호를 추가합니다.
string x = SomeFunction ();
int l = x != null ? x.Length : 0;
또는:
string x = SomeFunction () ?? "";
int l = x.Length;
또는:
string x = SomeFunction ();
int l = x?.Length;
관용적 인 F#
에서는 null
값을 사용하지 않으므로 코드는 다음과 같습니다.
let x = SomeFunction ()
let l = x.Length
그러나 때로는 빈 값이나 유효하지 않은 값을 나타낼 필요가 있습니다. 그런 다음 Option<'T>
사용할 수 있습니다.
let SomeFunction () : string option = ...
SomeFunction
은 Some
string
값 또는 None
반환합니다. 패턴 매칭을 사용하여 string
값을 추출합니다.
let v =
match SomeFunction () with
| Some x -> x.Length
| None -> 0
이 코드가 다음보다 취약하지 않은 이유 :
string x = SomeFunction ();
int l = x.Length;
string option
에서 Length
를 호출 할 수 없기 때문입니다. 우리는 추출 할 필요가 string
패턴 매칭을 사용하여 값을하고 그렇게함으로써 우리는 보장되는 string
값을 사용하는 것이 안전합니다.
옵션 모듈을 통해 철도 방향 프로그래밍 가능
오류 처리는 중요하지만 엉망으로 우아한 알고리즘을 만들 수 있습니다. ROP
( Railway Oriented Programming )는 오류 처리를 우아하고 구성 가능하게 만드는 데 사용됩니다.
간단한 함수 f
생각해보십시오.
let tryParse s =
let b, v = System.Int32.TryParse s
if b then Some v else None
let f (g : string option) : float option =
match g with
| None -> None
| Some s ->
match tryParse s with // Parses string to int
| None -> None
| Some v when v < 0 -> None // Checks that int is greater than 0
| Some v -> v |> float |> Some // Maps int to float
f
의 목적은 입력 string
값 ( Some
가있는 경우)을 int
로 구문 분석하는 것입니다. int
가 0
보다 큰 경우, float
캐스트합니다. 다른 모든 경우에 우리는 None
구제합니다.
중첩 된 match
기능은 매우 간단한 기능이지만 가독성을 크게 떨어 뜨립니다.
ROP
는 프로그램에서 두 가지 종류의 실행 경로가 있음을 확인합니다.
- 해피 경로 - 결국 계산됩니다
Some
값 - 오류 경로 - 다른 모든 경로 생성
None
오류 경로가 더 자주 발생하기 때문에 코드를 인계하는 경향이 있습니다. 행복한 패스 코드가 가장 눈에 띄는 코드 경로라고 생각합니다.
ROP
사용하는 동등한 함수 g
는 다음과 같습니다.
let g (v : string option) : float option =
v
|> Option.bind tryParse // Parses string to int
|> Option.filter ((<) 0) // Checks that int is greater than 0
|> Option.map float // Maps int to float
F#
에서 목록과 시퀀스를 처리하는 경향이 매우 비슷합니다.
하나는 볼 수있는 Option<'T>
유사한 List<'T>
만을 포함 할 수 0
또는 1
곳 요소를 Option.bind
처럼 동작 List.pick
(개념적으로 Option.bind
에게 더 나은지도 List.collect
하지만 List.pick
수 있습니다 이해하기 쉽다).
bind
, filter
및 map
은 오류 경로를 처리하고 g
는 해피 경로 코드 만 포함합니다.
직접 받아 모든 기능 Option<_>
반환합니다 Option<_>
직접 작성 가능하다 |>
및 >>
.
따라서 ROP
는 가독성과 조합 가능성을 높입니다.
C #의 옵션 유형 사용
C #에는 옵션 유형을 처리 할 수있는 방법이 없기 때문에 Option 유형을 C # 코드에 표시하는 것은 좋지 않습니다. 옵션은 FSharp.Core
를 C # 프로젝트 (C #으로 interop 용으로 설계 되지 않은 F # 라이브러리를 사용하는 경우 수행 FSharp.Core
)에서 종속성으로 도입하거나 None
값을 null
로 변경하는 것입니다.
Pre-F # 4.0
이렇게하는 방법은 자신의 변환 함수를 만드는 것입니다.
let OptionToObject opt =
match opt with
| Some x -> x
| None -> null
값 유형의 경우 boxing하거나 System.Nullable
을 사용해야합니다.
let OptionToNullable x =
match x with
| Some i -> System.Nullable i
| None -> System.Nullable ()
F # 4.0
F # 4.0에서 ofObj
, toObj
, ofNullable
및 toNullable
의 함수는 Option
모듈에 도입되었습니다. F # 대화식에서는 다음과 같이 사용할 수 있습니다.
let l1 = [ Some 1 ; None ; Some 2]
let l2 = l1 |> List.map Option.toNullable;;
// val l1 : int option list = [Some 1; null; Some 2]
// val l2 : System.Nullable<int> list = [1; null; 2]
let l3 = l2 |> List.map Option.ofNullable;;
// val l3 : int option list = [Some 1; null; Some 2]
// Equality
l1 = l2 // fails to compile: different types
l1 = l3 // true
None
내부적으로 null
컴파일됩니다. 그러나 F #에 관한 한 그것은 None
입니다.
let lA = [Some "a"; None; Some "b"]
let lB = lA |> List.map Option.toObj
// val lA : string option list = [Some "a"; null; Some "b"]
// val lB : string list = ["a"; null; "b"]
let lC = lB |> List.map Option.ofObj
// val lC : string option list = [Some "a"; null; Some "b"]
// Equality
lA = lB // fails to compile: different types
lA = lC // true