関数の戻り値の型が⊥(bottom type)の場合、戻り値がないことを意味します。たとえば、どちらもかなり普通の状況で終了またはスローできます。
おそらく、関数にtype型のパラメーターがある場合、(安全に)呼び出すことはできません。そのような関数を定義する理由はありますか?
関数の戻り値の型が⊥(bottom type)の場合、戻り値がないことを意味します。たとえば、どちらもかなり普通の状況で終了またはスローできます。
おそらく、関数にtype型のパラメーターがある場合、(安全に)呼び出すことはできません。そのような関数を定義する理由はありますか?
回答:
または空の型の定義プロパティの1つは、すべての型Aに対して関数が存在することです。実際、そのような独自の機能が存在します。したがって、この関数を標準ライブラリの一部として提供することはかなり合理的です。多くの場合、それはのようなものと呼ばれます。(サブタイプを有するシステムでは、これが有することによって、単純に扱われるかもしれない⊥すべての型のサブタイプである。次に、暗黙的な変換である。他の関連アプローチはする定義⊥として∀ α 。α簡単にすることができ、インスタンス化の任意のタイプです。)absurd
absurd
を生成する関数を使用できるようにするため、このような関数または同等の関数が必要です。たとえば、合計タイプが与えられたとします。私はそれにケースの分析を行うとして場合、私は使用して例外をスローするつもりだ。で場合、私が使用します。全体的に、タイプ値が必要なので、をに変えるために何かをする必要があります。それabsurd
が私にできることです。
とはいえ独自の関数を定義する理由はそれほど多くありません。定義により、それらは必然的にのインスタンスになりますabsurd
。それでも、absurd
標準ライブラリによって提供されていない場合、または型チェック/推論を支援するために型に特化したバージョンが必要な場合は、それを行う可能性があります。あなたは、しかし、簡単に終わるだろうな機能を生成することができ、インスタンス化のようなタイプに。
このような関数を記述する理由はあまりありませんが、一般的には許可されます。1つの理由は、コード生成ツール/マクロを簡素化することです。
absurd
absurd
throw
関数について言われたことに追加するためabsurd: ⊥ -> a
に、この関数が実際に役立つ場所の具体例を示します。
Haskellデータ型Free f a
を考えます。これは、s 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では、これは(つまり、- 形のノードを持ち、ファンクターの外側に葉がないツリー)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
、a char*
が期待された場所に戻ることができません。同様に、undefined
理論的なタイプセーフJavaScriptの型は、言語の他のすべての型のサブタイプでなければなりません。
exit()
throw()
Int
Int
exit()
NULL
空のタイプである⊥とは異なり、ユニットタイプではありませんか?
void*
にキャストできない場合は、任意のポインタ型に使用できる特定の型が必要になると言っています。
私が考えることができる1つの用途があり、それはSwiftプログラミング言語の改善として考えられているものです。
スウィフトはありmaybe
モナドが、綴ら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
残念ながら、「アンラップまたはエラーをスロー」または「アンラップまたはカスタムエラーメッセージでクラッシュ」と言う簡潔な方法はありませんでした。何かのようなもの
let someI: Int? = Optional(123)
let nonOptionalI: Int = someI ?? fatalError("Expected a non-nil value")
はfatalError
型を持っているため、コンパイルしません() -> Never
(()
is Void
、Swift 'unit type、Never
is Swift's bottom type)。これを呼び出すと、の正しいオペランドとして期待されるものNever
と互換性がT
なくなり??
ます。
これを改善する試みとして、Swift Evolutionの提案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」という型があります。これは、ボトム型によく似ています。Neverを返すように宣言された関数は、決して戻りません。
これはプロトコルに関連して便利です。プロトコルには、クラスに特定の関数が必要であるという言語の型システムによる制限がある場合がありますが、この関数を呼び出す必要はなく、引数の型も必要ありませんだろう。
詳細については、swift-evolutionメーリングリストの新しい投稿をご覧ください。
(x ? 3 : throw new Exception())
、分析の目的で、次のようなものに置き換えられるようなものを意味し(x ? 3 : absurd(throw new Exception()))
ますか?