본문으로 건너뛰기

LanguageExt 주요 타입 참조

LanguageExt 라이브러리의 핵심 타입들을 빠르게 참조할 수 있는 가이드입니다.


// 성공 생성
Fin<int> success = 42;
Fin<int> success2 = FinSucc(42);
// 실패 생성
Fin<int> failure = Error.New("오류 발생");
Fin<int> failure2 = FinFail<int>(Error.New("오류"));
// 결과 확인
if (result.IsSucc) { /* 성공 */ }
if (result.IsFail) { /* 실패 */ }
var message = result.Match(
Succ: value => $"성공: {value}",
Fail: error => $"실패: {error.Message}"
);
Fin<int> number = 10;
Fin<string> text = number.Map(n => n.ToString());
// 결과: "10"
Fin<int> Parse(string s) =>
int.TryParse(s, out var n) ? n : Error.New("파싱 실패");
Fin<int> result = Fin<string>.Succ("42")
.Bind(Parse)
.Map(n => n * 2);
// 결과: 84
int value = result.IfFail(0);
int value2 = result.IfFail(error => -1);

// 성공 생성
Validation<Error, string> valid = Success<Error, string>("");
// 실패 생성
Validation<Error, string> invalid = Fail<Error, string>(Error.New("오류"));
var result = (
ValidateName(name),
ValidateAge(age),
ValidateEmail(email)
).Apply((n, a, e) => new User(n, a, e));
// 모든 검증 오류가 수집됨
Validation<Error, string> ValidateName(string name) =>
string.IsNullOrEmpty(name)
? Fail<Error, string>(Error.New("이름은 필수입니다"))
: Success<Error, string>(name);
result.Match(
Succ: value => Console.WriteLine($"성공: {value}"),
Fail: errors =>
{
foreach (var error in errors)
Console.WriteLine($"오류: {error.Message}");
}
);

// 값이 있는 경우
Option<int> some = Some(42);
Option<int> some2 = 42; // 암시적 변환
// 값이 없는 경우
Option<int> none = None;
string message = option.Match(
Some: value => $"값: {value}",
None: () => "값 없음"
);
Option<int> result = Some(10)
.Map(n => n * 2)
.Bind(n => n > 0 ? Some(n) : None);
int value = option.IfNone(0);
int value2 = option.IfNone(() => GetDefaultValue());

// Right (성공 값)
Either<string, int> right = Right<string, int>(42);
// Left (오류 값)
Either<string, int> left = Left<string, int>("오류");
string result = either.Match(
Right: value => $"성공: {value}",
Left: error => $"실패: {error}"
);

// 기본 오류
var error = Error.New("오류 메시지");
// 코드와 메시지
var error2 = Error.New("ERR001", "오류 메시지");
// 예외로부터
var error3 = Error.New(exception);
// 내부 오류 포함
var error4 = Error.New("외부 오류", Error.New("내부 오류"));
string code = error.Code;
string message = error.Message;
Option<Error> inner = error.Inner;
Option<Exception> exception = error.Exception;

// 반환값이 없는 함수의 결과 타입
Fin<Unit> SaveToDatabase(Data data)
{
// 저장 로직
return unit; // 성공
}
// 검증 함수
Fin<Unit> ValidateNotEmpty(string value) =>
string.IsNullOrEmpty(value)
? Error.New("값이 비어있습니다")
: unit;

using static LanguageExt.Prelude;
// Option 생성
Some(42)
None
// Either 생성
Right<L, R>(value)
Left<L, R>(value)
// Validation 생성
Success<Error, T>(value)
Fail<Error, T>(error)
// Fin 생성
FinSucc<T>(value)
FinFail<T>(error)
// Unit 값
unit

var result =
from x in Fin<int>.Succ(10)
from y in Fin<int>.Succ(20)
select x + y;
// 결과: 30
var result =
from x in Some(10)
select x * 2;
// 결과: Some(20)
var result =
from x in Some(10)
where x > 5
select x;
// 결과: Some(10)

// 불변 시퀀스
var seq = Seq(1, 2, 3, 4, 5);
var head = seq.Head; // Some(1)
var tail = seq.Tail; // Seq(2, 3, 4, 5)
// 불변 배열
var arr = Array(1, 2, 3);
var added = arr.Add(4); // 새 배열 반환
// 불변 딕셔너리
var map = Map(("a", 1), ("b", 2));
var value = map.Find("a"); // Some(1)
var updated = map.Add("c", 3);

var result = GetUser(id)
.Bind(ValidateUser)
.Bind(UpdateUser)
.Map(ToResponse);

방법 1: 튜플 기반 Apply (권장)

var result = (
ValidateField1(input.Field1),
ValidateField2(input.Field2),
ValidateField3(input.Field3)
).Apply((f1, f2, f3) => new Output(f1, f2, f3));

방법 2: fun 기반 개별 Apply

fun 함수는 람다의 타입 추론을 돕는 헬퍼로, Currying을 통해 단계적으로 Apply를 적용합니다.

// fun으로 생성자/팩토리를 감싸고 개별 Apply 호출
var result = fun((string f1, string f2, string f3) => new Output(f1, f2, f3))
.Map(f => Success<Error, Func<string, string, string, Output>>(f))
.Apply(ValidateField1(input.Field1))
.Apply(ValidateField2(input.Field2))
.Apply(ValidateField3(input.Field3));

또는 Pure를 사용하여 더 간결하게:

var result = Pure<Validation<Error>, Output>(
fun((string f1, string f2, string f3) => new Output(f1, f2, f3)))
.Apply(ValidateField1(input.Field1))
.Apply(ValidateField2(input.Field2))
.Apply(ValidateField3(input.Field3));

두 가지 Apply 방식의 차이를 비교합니다.

방법특징사용 시기
튜플 Apply간결하고 직관적대부분의 경우 권장
fun 개별 ApplyCurrying 기반, 단계적 적용동적 파라미터 개수, 고급 합성
var result = user
.Map(u => u.Address)
.Bind(a => a.City)
.Map(c => c.Name)
.IfNone("Unknown");

ValidationRules - 타입 안전 검증 시작점

섹션 제목: “ValidationRules - 타입 안전 검증 시작점”

ValidationRules<T>는 값 객체 타입 파라미터를 한 번만 지정하여 검증 체인을 시작하는 정적 클래스입니다. 에러 코드에 값 객체 타입 이름이 자동으로 포함됩니다.

using Functorium.Domains.ValueObjects.Validations.Typed;
// 체이닝 검증: NotNull → ThenNotEmpty → ThenMaxLength
ValidationRules<Email>.NotNull(value)
.ThenNotEmpty()
.ThenMaxLength(255);
// 시작 메서드: NotNull, NotEmpty, MinLength, MaxLength, ExactLength 등
// 체이닝 메서드: ThenNotEmpty, ThenMinLength, ThenMaxLength, ThenExactLength, ThenNormalize 등

TypedValidation<TValueObject, T> - 타입 정보 전달 래퍼

섹션 제목: “TypedValidation<TValueObject, T> - 타입 정보 전달 래퍼”

ValidationRules<T>의 반환 타입으로, 체이닝 중 값 객체 타입 정보를 전달합니다. Validation<Error, T>로 암시적 변환됩니다.

// TypedValidation은 Validation<Error, T>로 암시적 변환
TypedValidation<Email, string> typed = ValidationRules<Email>.NotNull(value);
Validation<Error, string> validation = typed; // 암시적 변환
// CreateFromValidation에 직접 전달 가능
public static Fin<Email> Create(string? value) =>
CreateFromValidation(
ValidationRules<Email>.NotNull(value)
.ThenNotEmpty()
.ThenMaxLength(255),
v => new Email(v));

ValidationApplyExtensions - 튜플 Apply 확장

섹션 제목: “ValidationApplyExtensions - 튜플 Apply 확장”

ValidationApplyExtensionsValidation<Error, T> 튜플에 대한 Apply 오버로드를 제공하여, LanguageExt의 제네릭 Apply가 반환하는 K<Validation<Error>, T>를 내부에서 .As()로 변환합니다. 호출 측에서 .As()를 직접 호출할 필요가 없습니다.

using Functorium.Domains.ValueObjects.Validations;
// .As() 없이 concrete Validation<Error, R> 반환
var result = (
ValidateAmount(amount),
ValidateCurrency(currency)
).Apply((a, c) => new Money(a, c));
// result 타입: Validation<Error, Money> (K<> 아님)
// 2~5 튜플까지 지원

프레임워크 타입 선택 가이드를 확인합니다.

B. 프레임워크 타입 선택 가이드