これら2つのシグネチャの違い:
withKnownNat :: Sing n -> (KnownNat n => r) -> r
withKnownNat' :: KnownNat n => Sing n -> r -> r
が制約KnownNat n
が保持しているという証拠を提供するために必要とされる人です。
フロントアップ制約を持つ仮説バージョンは(「::
(hasType)記号の後」)関数を呼び出すためにKnownNat n
を証明することができるようにwithKnownNat'
の発信者を必要とします。そのタイプシグネチャは、「KnownNat n
を証明できれば、私にSing n
とr
の両方を渡したら、私はr
を返すでしょう。
KnownNat n
という制約とSing n
という引数を無視して、それだけをr
に戻すことで実装できるため、特に便利なわけではありません。そしてr
が何であるか分からずに返すことが他にはあまりできませんでした。r
;それはn
でいくつかの操作を行う可能性があり、いくつかの条件の下でエラーを発生させるか、内部的に安全でない機能を使って厄介なハッキングを行うことがあります。
実際のバージョンでは、KnownNat n
制約の下にある関数はすべてwithKnownNat
ではなく、その引数の1つに制約があります。つまり、withKnownNat
の発信者はがKnownNat n
であることを証明できなければなりません。代わりに、呼び出し側はがの証明がKnownNat n
であることを必要とする引数を渡すことができます。ファンクションへの引数は、タイプKnownNat n => r
は、「 の値で、の場合、KnownNat n
が成立する」という値として読み取ることができます。あなたが私にSing n
と(2)の値を持っていると仮定すると、KnownNat n
の値を持っているなら、私はあなたにタイプr
の値を与えます。 。
これは、タイプからちょうどもっと有用であることがわかります。 r
のポリモーフィックなので、withKnownNat
のr
という唯一の方法は、私たちが与えたKnownNat n => r
からです。 KnownNat n
と表示される場合は、実際にKnownNat n => r
の値をr
の値として使用してに戻すことができます。したがって、基本的にwithKnownNat
のこのタイプは、Sing n
があるときはいつも、同じにはKnownNat n
が必要なものを使うことができるという約束をします。 withKnownNat
は、一方を他方に変換するために呼び出す必要があります。
それだけでなく、関数の戻り値と同じことを意味しますが、それは制約を必要とする戻り値を得ることが、全体の機能の場合とまったく同じものにうまくいくことが判明GHCは常にarg -> (constraints => result)
のような型をちょうどconstraints => args -> result
に変換します。
出典
2017-08-29 07:27:54
Ben
[補題]関数の一般的な型をどのように理解する必要がありますか?](https://stackoverflow.com/questions/30224796/how-should-the-general-type-of-a-lemma -function-be-understand) –
'withKnownNat'は2つの引数をとります。最初のものはシングルトンであり、2番目のものは 'KnownNat n'コンテキストでのみ有効な' r'型の値です。値「x :: Sing n」は、「KnownNat n」制約を放電するために、すなわち、「KnownNat n」が満たされていることを証明するために使用されている。この関数に代入可能な別の型は、 'Sing n - > Dict(KnownNat n)'です。ここで 'data Dict p where Dict :: p => Dict p'です。 'Dict p'のパターンマッチングによって、' p'という制約がスコープに持ち込まれます。実際の型は 'Dict'上のパターンマッチングの中間ステップを削除するだけです。 – user2407038
[補題]関数の一般的な型を理解するにはどうすればよいですか?](https://stackoverflow.com/questions/30224796/how-should-the-general-type-of-a-lemma-function - 理解された) –