私が読んでいるHaskellを学ぶ、そしてモナドの章では、()
あらゆる型に対して が一種の「null」として扱われているように私には思えます。GHCi()
で の型を調べると、
>> :t ()
() :: ()
これは非常に紛らわしい記述です。それ()
自体が型のようです。それが言語にどのように適合するのか、またそれがどのような型を表すことができるのか、私にはわかりません。
ベストアンサー1
要約 ()
すべての型に「null」値を追加するわけではありません。絶対にそうではありません。()
独自の型では「dull」値になります()
。
少し質問から離れて、よくある混乱の原因についてお話ししましょう。Haskellを学ぶときに覚えておくべき重要なことは、表現言語とそのタイプ言語。おそらく、この 2 つが別々に保持されていることに気付いているでしょう。しかし、これにより、同じシンボルを両方で使用できます。これがここで起こっていることです。どの言語を見ているのかを示す簡単なテキストの手がかりがあります。これらの手がかりを検出するために、言語全体を解析する必要はありません。
Haskellモジュールのトップレベルは、デフォルトでは式言語で表現されます。関数は式の間に等式を書くことで定義されます。しかし、フー::バー表現言語では、それはフーは表現であり、バーはその型です。したがって、 を読むと、式言語の と型言語の() :: ()
を関連付けるステートメントが表示されます。2 つのシンボルは、同じ言語ではないため、異なる意味を持ちます。この重複により、初心者は混乱することがよくありますが、式言語と型言語の分離が潜在意識にインストールされると、便利な記憶法になります。()
()
()
このキーワードはdata
、新しいデータ型宣言を導入します。この宣言では、まず新しい型が何であるか、次にその値が何であるかが示されるため、式言語と型言語が慎重に混在します。
データタイコン タイバー ... タイバー=ValCon1 タイプ...タイプ... |ValConnタイプ...タイプ
このような宣言では、型コンストラクタタイコン型言語に追加され、ヴァルコン値コンストラクタが式言語(およびそのパターンサブ言語)に追加されています。宣言ではdata
、ヴァルコンsは引数に与えられた型を示しますヴァルコンは式の中で使用されます。例えば、
data Tree a = Leaf | Node (Tree a) a (Tree a)
は、ノードに要素Tree
を格納するバイナリツリー型の型コンストラクタを宣言します。その値は、値コンストラクタとによって与えられます。私は、型コンストラクタ ( ) を青、値コンストラクタ ( 、 ) を赤で色付けするのが好きです。式には青は使用すべきではなく、(高度な機能を使用していない限り) 型には赤は使用すべきではありません。組み込み型は、次のように宣言できます。a
Leaf
Node
Tree
Leaf
Node
Bool
data Bool = True | False
Bool
入力言語に青、表現言語に赤を追加しますTrue
。False
残念ながら、私のマークダウンスキルはこの投稿に色を追加するには不十分なので、頭の中で色を追加する方法を学ぶ必要があります。
「ユニット」型は()
特別なシンボルとして使用されますが、宣言されているかのように動作します。
data () = () -- the left () is blue; the right () is red
これは、概念的に青いは()
型言語では型コンストラクタであるが、概念的に赤いは()
式言語では値コンストラクタであり、実際、であることを意味します() :: ()
。[これは、このようなしゃれの例だけではありません。より大きなタプルの型も同じパターンに従います。ペア構文は、次のように与えられるかのようです。
data (a, b) = (a, b)
(,)
型言語と式言語の両方に追加します。しかし、話がそれてしまいました。
型は()
「ユニット」と発音されることが多いが、言及する価値のある1つの値を含む型である。その値は次の()
ようにも記述されるが、表現言語では「void」と発音されることもあります。値が 1 つしかない型はあまり興味深いものではありません。型の値は()
情報をまったく提供しません。つまり、その値が何であるかはすでにわかっています。したがって、()
副作用を示すために型に特別なことは何もないのですが、モナド型の値コンポーネントとして現れることがよくあります。モナド演算は、次のような型になる傾向があります。
val-in-type-1-> ... ->val-in-type-n->エフェクトモナド val-out 型
戻り値の型は型適用です。(type)関数は、効果可能であり、(type)引数はどのような種類の価値操作によって生成されます。たとえば
put :: s -> State s ()
これは(アプリケーションが左に関連付けるため[「60年代に私たち全員がやったように」、ロジャー・ヒンドリー])次のように読みます。
put :: s -> (State s) ()
には、1つの値入力型s
、エフェクトモナドState s
、および値出力型があります()
。値出力型として見ると()
、それは単に「この操作は、その目的のためだけに使用されます」という意味です。効果; 提供される価値は面白くない」同様に
putStr :: String -> IO ()
に文字列を渡しますstdout
が、何も返しません。
この()
型は、次のような要素型としても役立ちます。容器のような構造で、データが単なる形、興味深いペイロードはありません。たとえば、Tree
が上記のように宣言されている場合、はTree ()
バイナリツリーシェイプの型であり、ノードには興味深いものは何も格納されません。同様に、は[()]
退屈な要素のリストの型であり、リストの要素に興味深いものが何もない場合、提供される唯一の情報は長さです。
まとめると、()
は型です。その 1 つの値()
はたまたま同じ名前を持っていますが、型言語と式言語は別々なので問題ありません。コンテキスト (たとえば、モナドまたはコンテナ) では、コンテキストのみが重要であることがわかるため、「情報なし」を表す型があると便利です。