サーチ…


備考

Haskellの強みの1つは、タイプシステムで問題のドメインの一部をモデル化するためにタイプシステムを活用する能力です。そうすることで、非常に複雑なタイプに遭遇することがよくあります。これらの型(つまり、これらの型を持つ値)を持つプログラムを書くとき、時にはすべての型を「ジャグリング」することがほぼ不可能になります。 GHC 7.8以降、型付き穴という新しい構文上の特徴があります。型付きの穴は、コア言語のセマンティクスを変更しません。彼らはプログラムを書くための援助として純粋に意図されています。

型付き穴の詳細な説明と、型付き穴の設計については、 Haskell wikiを参照してください。


入力れた穴に関するGHCユーザーガイドのセクション。

タイプされた穴の構文

型付きの穴は、単一のアンダースコア( _ )または有効なHaskell識別子であり、式コンテキストではスコープ内にありません。型付きの穴が存在する前に、これらの両方がエラーを引き起こすので、新しい構文は古い構文を妨げません。

型付き穴の動作を制御する

型付き穴のデフォルトの動作は、型付き穴に遭遇したときにコンパイル時エラーを生成することです。ただし、動作を微調整するためのフラグがいくつかあります。これらのフラグは次のように要約されています( GHC trac )。

デフォルトでは、GHCは型付き穴を使用可能にし、型付き穴に遭遇するとコンパイル・エラーを生成します。

-fdefer-type-errors または -fdefer-typed-holesを有効にすると、穴のエラーは警告に変換され、評価されるとランタイムエラーが発生します。

-fwarn-typed-holesという警告フラグは、デフォルトでオンになっています。 -fdefer-type-errorsまたは-fdefer-typed-holesなければ、これらの条件では型付きの穴がエラーになるため、このフラグはno-opです。いずれかの遅延フラグが有効な場合(型付きのホール・エラーを警告に変換する)、- -fno-warn-typed-holesフラグは警告を無効にします。つまり、コンパイルが正常に終了し、穴を評価するとランタイムエラーが発生します。

型付き穴のセマンティクス

型の穴の値は、 undefinedれていundefinedと簡単に言うことができますが、型付きの穴はコンパイル時のエラーを引き起こすため、厳密に値を割り当てる必要はありません。しかし、型付きの穴(有効にすると)は、型付き穴の名前、推論された最も一般的な型、およびすべてのローカルバインディングの種類を示すコンパイル時エラー(または遅延型エラーの警告)を生成します。例えば:

Prelude> \x -> _var + length (drop 1 x)

<interactive>:19:7: Warning:
    Found hole `_var' with type: Int
    Relevant bindings include
      x :: [a] (bound at <interactive>:19:2)
      it :: [a] -> Int (bound at <interactive>:19:1)
    In the first argument of `(+)', namely `_var'
    In the expression: _var + length (drop 1 x)
    In the expression: \ x -> _var + length (drop 1 x)

上記のようにGHCi replに入力された式に型付きの穴がある場合、入力された式のタイプも報告されit (ここでは[a] -> Int )。

タイプされた穴を使用してクラスインスタンスを定義する

型付きの穴は、対話型のプロセスを通じて、関数を簡単に定義することができます。

Fooインスタンスが必要な多相ライブラリ関数で使用するために、カスタムのBar型のFoo Barクラスインスタンスを定義したいとします。伝統的に、 Fooのドキュメントを調べ、定義する必要のあるメソッドを特定し、型を調べます。型付きの穴を使用すると、実際にはスキップすることができます。

最初にダミーインスタンスを定義します。

instance Foo Bar where

コンパイラは今すぐ文句を言うでしょう

Bar.hs:13:10: Warning:
No explicit implementation for
  ‘foom’ and ‘quun’
In the instance declaration for ‘Foo Bar’

foomBarためにfoomを定義する必要があります。しかしそれは何あるべきであろう?やはりドキュメントを見るのが面倒すぎて、コンパイラに尋ねるだけです。

instance Foo Bar where
  foom = _

ここでは、単純な「ドキュメント照会」として型付きの穴を使用しました。コンパイラの出力

Bar.hs:14:10:
    Found hole ‘_’ with type: Bar -> Gronk Bar
    Relevant bindings include
      foom :: Bar -> Gronk Bar (bound at Foo.hs:4:28)
    In the expression: _
    In an equation for ‘foom’: foom = _
    In the instance declaration for ‘Foo Bar’

コンパイラがすでにクラス型変数に、具体化する型のBarを埋め込み、それをインスタンス化する方法に注目してください。これにより、クラスのドキュメントにある多型よりもシグネチャを理解しやすくなります。特に、マルチパラメータ型のクラスなどのより複雑なメソッドを扱う場合は、シグネチャをもっと理解しやすくなります。

しかし、 GronkGronk何ですか?この時点で、 Hayooに聞くことはおそらく良い考えです。しかし、私たちはそれがなくてもまだ逃げるかもしれません。盲目的な推測として、これは型コンストラクタだけでなく、単一値コンストラクタでもあるとGronk aます。 Gronk a何らかの形でGronk a値を生成する関数として使用できます。私たちは試してみる

instance Foo Bar where
  foom bar = _ Gronk

運がGronkば、 Gronkは実際には価値があり、コンパイラは

    Found hole ‘_’
      with type: (Int -> [(Int, b0)] -> Gronk b0) -> Gronk Bar
    Where: ‘b0’ is an ambiguous type variable

GronkGronkは2つの議論があることに注意してください。私たちはその試みを洗練することができます:

instance Foo Bar where
  foom bar = Gronk _ _

これは今かなり明確です:

    Found hole ‘_’ with type: [(Int, Bar)]
    Relevant bindings include
      bar :: Bar (bound at Bar.hs:14:29)
      foom :: Bar -> Gronk Bar (bound at Foo.hs:15:24)
    In the second argument of ‘Gronk’, namely ‘_’
    In the expression: Gronk _ _
    In an equation for ‘foom’: foom bar = Gronk _ _

たとえば、 bar値を分解することによってさらに進歩することができます( Relevant bindingsセクションでは、コンポーネントがタイプとともに表示されRelevant bindings )。多くの場合、正しい定義が何であるかはっきりとはっきりしています。なぜなら、使用可能なすべての引数とタイプがジグソーパズルのようにまとまっているからです。あるいは、定義が不可能であり、その理由がわかるかもしれません。

これらのすべてはインタラクティブなコンパイルのエディタ、例えばhaskell-modeを使ったEmacsでうまく動作します。 IDEのマウスオーバー値クエリと同じように、入力された穴を、解釈された動的命令言語のために使用できますが、すべての制限はありません。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow