Agdaのような総合的な言語から始めましょう。次に、ガレーが述べるように、これは、「空のタイプ」によって単位タイプ、つまり0-aryタプルが正確に1つの値を持つことを意味する場合にのみ意味があります。空の型は0ケースの合計型と考えることができ、値はまったくありません。Agdaでは、Unit -> A
が同型であることを簡単に証明できますA
。その意味では、それらは同じであると見なすことができますが、文字通り同じではありません。たとえば、aのケース分析はできません。また、関数として何にもUnit -> Bool
適用できませんTrue : Bool
。
Haskellの話はかなり異なります。() -> A
そして、A
意味的に非同型タイプです。具体的には、() -> ()
ながら、四つの値を持つ()
4つのだけ有する2 observationally別個の値はundefined
、\_ -> undefined
、\x -> x
、\_ -> ()
。つまり()
、には関数が1つしかないという意味で、実際にはユニットタイプではありません()
。(一方、Agdaでは、との場合x : Unit
、y : Unit
それらが等しいことを証明できます。つまりUnit
、record
構文とは対照的に、data
構文で定義すると、Unit
値が1つだけであることを証明できます。さらに、Unit
そして、A -> Unit
すべての同型ですA
。)
実際、「空」タイプのVoid
定義data Void
は、この意味ではユニットタイプに近いです。Void
値は1つだけですが、Void -> Void
まだ2つあります。実際、すべての関数型A -> B
には、少なくとも2つの観測的に異なる値がundefined
あり\_ -> undefined
ます。したがって、Haskellには真のユニットまたはvoidタイプはありません。
これの多くは、Haskellが厳密でない言語であることが原因であり、Haskell seq
(およびその同等物)の存在によって苛立たされています。たとえば、との違いはundefined
で\_ -> undefined
のみ確認できseq
ます。seq
Haskellからその同等物を削除した場合Void
、皮肉なことに、ユニットタイプとして機能しますが、それでも空のタイプではありません。
通常、人々がHaskellでそのようなことについて話すとき、彼らはHaskellがそれよりもよりふるまいた言語であると暗黙のうちに偽っています。つまり、彼らはボトムズが彼らの目的のために存在しない、すなわちあなたがAgdaのような総合的な言語で働いていると想定しています。コードを設計するためには、通常これで十分です。ボトムスを気にしたり期待したりすることは一般的ではありません。これらの区別は、循環プログラミングなどを行っている場合、またはプログラムの安全性の保証がこれらのプロパティに依存している場合に重要になる可能性があります。たとえば、ドメインに空の型がある場合、関数を呼び出すことはできません。