함수에 반환 유형이 ⊥ ( bottom type )이면 반환되지 않습니다. 예를 들어 상당히 일반적인 상황에서 나가거나 던질 수 있습니다.
함수에 ⊥ 유형의 매개 변수가있는 경우에는 (안전하게) 호출 할 수 없습니다. 그러한 함수를 정의 할 이유가 있습니까?
함수에 반환 유형이 ⊥ ( bottom type )이면 반환되지 않습니다. 예를 들어 상당히 일반적인 상황에서 나가거나 던질 수 있습니다.
함수에 ⊥ 유형의 매개 변수가있는 경우에는 (안전하게) 호출 할 수 없습니다. 그러한 함수를 정의 할 이유가 있습니까?
답변:
또는 빈 유형 의 정의 속성 중 하나는 모든 유형 A에 대해 기능이 있다는 것 입니다. 실제로는 고유 한 기능이 있습니다. 따라서이 기능이 표준 라이브러리의 일부로 제공되는 것이 상당히 합리적입니다. 종종 그것은 같은 것 입니다. (하위 유형을 가진 시스템에서, 이것은함으로써 간단하게 처리 할 수 ⊥ 모든 유형의 하위 유형합니다. 그런 다음 암시 적 변환입니다 . 또 다른 관련 접근 방식입니다 정의 ⊥ 로 ∀ α . α 간단하게 할 수 인스턴스화 모든 유형을.)absurd
absurd
당신이 생산하는 것이 기능을 활용할 수 있습니다 무엇 때문에 당신은 확실히 같은 기능 또는 동등한를 갖고 싶어 . 예를 들어, 합계 유형 가 있다고 가정 해 봅시다 . 나는 그것에 대한 사례 분석을하고 경우에는 사용하여 예외를 던질 것 입니다. 에서 경우, 내가 사용합니다 . 전반적으로 유형의 값을 원 하므로 를 로 바꾸려면 무언가를해야합니다 . 그것이 내가 absurd
할 수있는 일입니다.
즉, 의 기능을 직접 정의해야 할 이유는 많지 않습니다 . 정의에 따르면 반드시의 인스턴스 일 것입니다 absurd
. 그러나 absurd
표준 라이브러리에서 제공하지 않거나 형식 검사 / 추론을 지원하는 형식 특수 버전을 원할 경우 그렇게 할 수 있습니다 . 그러나 ⊥ → A 와 같은 유형으로 인스턴스화 되는 함수를 쉽게 생성 할 수 있습니다 .
그러한 함수를 작성할 이유가 많지는 않지만 일반적으로 여전히 허용 되어야합니다 . 한 가지 이유는 코드 생성 도구 / 매크로를 단순화하기 때문입니다.
absurd
absurd
throw
함수에 대해 말한 것을 추가하기 absurd: ⊥ -> a
위해이 함수가 실제로 유용한 위치에 대한 구체적인 예가 있습니다.
s를 포함하는 모양의 노드와 잎이 Free f a
있는 일반적인 트리 구조를 나타내는 Haskell 데이터 유형 을 고려하십시오 .f
a
data Free f a = Op (f (Free f a)) | Var a
이 나무는 다음 기능으로 접을 수 있습니다.
fold :: Functor f => (a -> b) -> (f b -> b) -> Free f a -> b
fold gen alg (Var x) = gen x
fold gen alg (Op x) = alg (fmap (fold gen alg) x)
간단히,이 작업 alg
은 노드와 gen
나뭇잎에 배치됩니다.
이제 요점 : 모든 재귀 데이터 구조는 고정 소수점 데이터 유형을 사용하여 표현할 수 있습니다. Haskell에서 이것은 (예 를 들어 functor 외부에 잎이없는 모양의 노드가있는 나무)로 Fix f
정의 할 수 있습니다 . 전통적으로이 구조는 다음과 같이 접 힙니다 .type Fix f = Free f ⊥
f
f
cata
cata :: Functor f => (f a -> a) -> Fix f -> a
cata alg x = fold absurd alg x
나무에 어떤 잎도 가질 수 없기 때문에 (⊥ 외에 다른 주민이 없기 때문에 undefined
) gen
이 접힘에 대해 사용할 수 없으며 그것을 absurd
보여줍니다!
하단 유형은 다른 모든 유형의 하위 유형이므로 실제로 매우 유용 할 수 있습니다. 예를 들어, NULL
이론적 인 형식 안전 버전 C의 형식은 다른 모든 포인터 형식의 하위 형식이어야합니다. 그렇지 않으면 예상 한 NULL
위치를 반환 할 수 없습니다 char*
. 마찬가지로 undefined
이론적 인 형식 안전 JavaScript의 유형은 언어에서 다른 모든 유형의 하위 유형이어야합니다.
exit()
throw()
Int
Int
exit()
NULL
빈 유형 인 ⊥과는 다른 단위 유형이 아닌가?
void*
모든 포인터 유형에 사용할 수있는 특정 유형이 필요합니다.
내가 생각할 수있는 용도가 하나 있는데, 이는 Swift 프로그래밍 언어의 개선으로 간주 된 것입니다.
Swift에는 maybe
Monad, Optional<T>
또는 철자가 T?
있습니다. 상호 작용하는 방법에는 여러 가지가 있습니다.
다음과 같은 조건부 언 래핑을 사용할 수 있습니다.
if let nonOptional = someOptional {
print(nonOptional)
}
else {
print("someOptional was nil")
}
당신은 사용할 수 있습니다 map
, flatMap
값을 변환
!
유형의 (T?) -> T
)가 컨텐츠를 강제로 랩 해제합니다. 그렇지 않으면 충돌이 발생합니다.nil-coalescing 연산자 ( ??
유형의 (T?, T) -> T
)는 값을 가져 오거나 그렇지 않으면 기본값을 사용합니다.
let someI = Optional(100)
print(someI ?? 123) => 100 // "left operand is non-nil, unwrap it.
let noneI: Int? = nil
print(noneI ?? 123) // => 123 // left operand is nil, take right operand, acts like a "default" value
불행히도 "unwrap or throw an error"또는 "custom wrap with a custom error message"라는 간결한 방법은 없었습니다. 같은 것
let someI: Int? = Optional(123)
let nonOptionalI: Int = someI ?? fatalError("Expected a non-nil value")
fatalError
유형이 있기 때문에 컴파일되지 않습니다 () -> Never
( ()
is Void
, Swift '단위 유형, Never
Swift의 하단 유형). 그것을 호출하면 의 올바른 피연산자로 예상되는 것과 Never
호환되지 않습니다 .T
??
이 문제를 해결하기 위해 Swift Evolution propsoal- SE-0217
"Unwrap or Die"연산자 가 작성되었습니다. 그것은했다 궁극적으로 거부 하지만, 제작에 관심을 제기 Never
모든 유형의 하위 유형해야합니다.
Never
모든 유형의 하위 유형이 되었으면 이전 예제를 컴파일 할 수 있습니다.
let someI: Int? = Optional(123)
let nonOptionalI: Int = someI ?? fatalError("Expected a non-nil value")
의 호출 사이트에 ??
유형 (T?, Never) -> T
이 있으며의 (T?, T) -> T
서명 과 호환 되기 때문 입니다 ??
.
Swift는 "Never"유형을 가지고 있으며 이는 아래 유형과 매우 유사합니다.
이것은 클래스와 함께 특정 함수를 가져야하는 언어의 유형 시스템으로 인해 제한이있을 수 있지만이 함수를 호출 할 필요가없고 인수 유형이 무엇인지에 대한 요구가없는 프로토콜과 관련하여 유용합니다. 될 것입니다.
자세한 내용은 swift-evolution 메일 링리스트의 최신 게시물을 확인하십시오.
(x ? 3 : throw new Exception())
분석 목적으로 비슷한 것이 대체 더 유사한 것으로 대체 됨을 의미합니다(x ? 3 : absurd(throw new Exception()))
.