1. ホーム
  2. haskell

Haskellの()って、そもそも何?

2023-09-28 02:52:29

質問

今読んでいる本 ハスケルを学ぶ を読んでいて、モナドの章では、どうやら () は、すべての型に対して一種の "null" として扱われているようです。の型をチェックすると () の型をGHCiでチェックすると

>> :t ()
() :: ()

というのは、非常にわかりにくい文です。どうやら () はそれ自体がひとつの型です。私は、それがどのように言語に適合し、どのような型を表すことができるように見えるかについて混乱しています。

どのように解決するのですか?

tl;dr () はすべての型に "null" 値を追加しません、全く違います。 () はそれ自身の型の中の "dull"値です。 () .

少し質問から離れ、よくある混乱の原因を取り上げてみましょう。Haskellを学習する際に吸収すべき重要なことは、その 言語と タイプ という言語があります。この2つが別々になっていることはご存じでしょう。しかし、そのおかげで、同じ記号を両方で使うことができるのです。どちらの言語を見ているかは、簡単なテキストによる合図があります。これらの手がかりを検出するために、言語全体を解析する必要はないのです。

Haskellモジュールのトップレベルは、デフォルトでは式言語に住んでいます。式と式の間に方程式を書くことによって、関数を定義します。しかし foo :: バー を式言語で表現すると、次のようになります。 foo は式であり bar がその型です。ですから、あなたが () :: () を関連付けるステートメントが表示されます。 () を式言語の () を型言語では この二つの () の記号は同じ言語ではないので、異なることを意味します。この複製はしばしば初心者を混乱させますが、式言語と型言語の分離が潜在意識にインストールされるまでは、その時点で役に立つニモニックになります。

キーワード data は新しいデータ型宣言を導入します。これは式言語と型言語の注意深い混合を必要とします。

データ 

TyCon tyvar ... tyvar

 = 

ValCon1 type ... type

 | ...  | 

ValConnタイプ ... タイプ

このような宣言では、タイプ・コンストラクタ TyCon が型言語に追加され ValCon の値のコンストラクタが式言語(とそのパターンサブ言語)に追加されている。また data 宣言において,引数の場所に立っているものは ValCon の引数の場所に立っているものは、そのときに引数に与えられた型を教えてくれます。 ValCon が式の中で使われたときに、引数に与えられる型を教えてくれます。例えば

data Tree a = Leaf | Node (Tree a) a (Tree a)

型コンストラクタを宣言する Tree を格納する2進木型のための a 要素をノードに格納し、その値は値のコンストラクタである LeafNode . 私はタイプコンストラクタに色をつけるのが好きです ( Tree ) を青に、 値のコンストラクタ ( Leaf , Node ) の赤。式には青を、型には(高度な機能を使っていない限り)赤を入れるべきではありません。組み込みの型である Bool を宣言することができます。

data Bool = True | False

青色を加える Bool を型言語に追加し、赤の TrueFalse を式言語に追加しました。悲しいかな、私のマークダウン技術はこの記事に色をつけるというタスクには不十分なので、頭の中で色をつけることを学ぶしかないでしょう。

unit"型では () を特殊記号として使用しますが、あたかも

data () = ()  -- the left () is blue; the right () is red

というのは、概念的に青い () は型言語の型構成子であるが、概念的には赤の () は式言語の値構成子であり、実際に () :: () . [このような洒落の例はこれだけではありません。より大きなタプルの型も同じパターンに従っています。ペアの構文は、あたかも次のように与えられます。

data (a, b) = (a, b)

追加 (,) を型言語と式言語の両方に追加しています。しかし、私は脱線した]。

では、型の () と発音されることが多いこの型は、話す価値のある 1 つの値を含む型です。 () と書かれますが 言語で、"void" と発音されることがあります。値が1つしかない型はあまり面白くありません。型の値 () 型の値は0ビットの情報しか提供しません。なぜなら、あなたはそれが何でなければならないかをすでに知っているからです。つまり、この型は特別なものではないのですが () は副作用を示す特別なものではありませんが、モナド型の値の構成要素として表示されることがよくあります。モナド演算は次のような型を持っていることが多いようです。


バルインタイプ-1

 -> ... -> 

バルインタイプ-N

 -> 

効果モナド val-out-type

ここで、戻り値の型は型アプリケーションです:(型)関数は、どの の効果 が可能で、(type)引数はどのような がその操作によって生成されるかを示します。例えば

put :: s -> State s ()

は、(アプリケーションが左側に関連するため、"as we all did in the sixties", Roger Hindley)次のように読み取れます。

put :: s -> (State s) ()

は1つの値入力タイプ s を持つ場合、エフェクトモナド State s と、値出力タイプ () . と表示された場合 () とあるのは、この操作が 効果 のためにのみ使用され、提供される値は面白くないということを意味します。同様に

putStr :: String -> IO ()

に文字列を渡す。 stdout に文字列を送りますが、何もエキサイティングなことは返しません。

() 型の要素型としても有用です。 コンテナ -のような構造で、データが単に 形状 であり、興味深いペイロードがないことを示します。例えば、もし Tree が上記のように宣言されている場合 Tree () は二分木の形であり、ノードには何も保存されない。同様に [()] は鈍い要素のリストの型であり、リストの要素に興味のあるものがない場合、寄与する唯一の情報はその長さです。

まとめると () は型です。その一つの値 () は同じ名前ですが、型言語と式言語は別物なので大丈夫です。なぜなら、コンテキスト (たとえば、モナドやコンテナの) において、コンテキストのみが興味深いものであることを教えてくれるからです。