NonEmptyList · Nel

원소를 최소 하나는 담고 있다고 정적으로 보장되는 리스트 — 누적 API가 에러를 실어 나르는 그릇입니다. 제로 비용입니다: 런타임에 지워지는 확장 타입(extension type)입니다.

extension type NonEmptyList<T> implements Iterable<T> — typedef Nel<T> = NonEmptyList<T> factory NonEmptyList.of(T head, [Iterable<T> tail = const []]) static NonEmptyList<T>? orNull<T>(List<T> list) on Iterable<T>: NonEmptyList<T>? toNelOrNull()

강의

"검증 에러의 리스트"에는 어색한 경계 사례가 하나 있습니다. 비어 있는 에러 리스트는 대체 무슨 뜻일까요? NonEmptyList(별칭 Nel)는 그 질문 자체를 타입 시스템에서 지워 버립니다 — 이 값을 손에 쥐고 있다면 원소가 최소 하나는 있으므로, List.first와 달리 head는 전체 함수(total)이며 예외를 던질 수 없습니다. 에러 누적에 필요한 것이 정확히 이것입니다: EitherNel<E, A> = Either<Nel<E>, A>, 즉 Left는 언제나 최소 하나의 에러를 실어 나릅니다.

Arrow의 value class NonEmptyList에 대응하는 Dart 쪽 짝입니다. 확장 타입으로 List 위에 얹혀 있어 할당이 전혀 없고 런타임에 지워지며, implements Iterable이므로 모든 fxdart 파이프라인과 for 반복문이 이 값을 그대로 받습니다. 불변식은 컴파일 타임의 규율로 지켜집니다: 생성은 오직 NonEmptyList.of(head, [tail]) 또는 NonEmptyList.orNull(list)(빈 리스트에는 null을 반환합니다 — 비어 있는지 확인하는 일은 경계에서 딱 한 번만 일어납니다)를 통해서만 하세요. list as Nel<int> 같은 캐스트는 그 검사를 우회하며, 책임은 온전히 사용자 몫입니다.

데모 1 · of, orNull, head & tail

데모 2 · map, +, 그리고 파이프라인

데모 3 · toNelOrNull — 어떤 Iterable이든

Nel.orNullList를 받기 때문에, 누적 파이프라인은 오류를 패널로 만들기 전에 항상 .toList() 셔플로 끝나야 했습니다. toNelOrNull() 확장(Arrow의 toNonEmptyListOrNull)은 어떤 Iterable이든 — 지연 fx 체인 포함 — 받아 복사한 뒤 Nel?을 바로 돌려줍니다. "오류 없음"은 null, 아니면 비어 있지 않음이 보장된 목록입니다.

직접 해 보기

연습: summarize를 완성해 보세요 — null 경우가 이미 처리되어 있으므로 nel.lengthnel.head는 실패할 수 없습니다.

관련 항목: 에러 누적Nel이 모든 실패를 실어 나르는 곳 · EithertoEitherNel()은 실패 하나를 원소 하나짜리 Nel로 끌어올립니다 · firstOrNull — 이 타입이 전체 함수로 만들어 주는 nullable 우선 접근자 · 타입 있는 에러 — 전체 가이드