5

異なるシグネチャを持つ関数の部分適用が機能するのはなぜですか?

Control.Monad.joinとして:

GHCi> :t (=<<)
(=<<) :: Monad m => (a -> m b) -> m a -> m b
GHCi> :t id
id :: a -> a
GHCi> :t (=<<) id
(=<<) id :: Monad m => m (m b) -> m b

それらは明らかに異なるので、なぜそれは議論id :: a -> aの代わりに受け入れるのですか?(a -> m b)

4

3 に答える 3

11

=<<の型アノテーションは、最初の引数がa(何でも)からのモナドへの関数であることを示していbます。

ええと、m b何でも数えますよね?m bしたがって、すべての代わりに使用できますa

(=<<) :: Monad m => (m b -> m b) -> m (m b) -> m b

idsタイプは、それが何からでも同じものへの関数であることを示します。したがって、m b(モナド制約を忘れずに)サブインすると、次のようになります。

id :: Monad m => m b -> m b

次に、タイプが一致していることがわかります。

于 2012-08-13T16:29:25.103 に答える
3

ここで使用するいくつかの便利な概念:

  1. 変数を持つすべての型は、のすべてのインスタンスを他の型aに置き換えることで、別の型に変換できます。したがって、タイプがある場合は、それぞれにまたはで置き換えることにより、タイプまたはタイプを取得できます。ata -> b -> ca -> d -> ca -> b -> IntbdcInt
  2. 交換により相互に変換できる2つのタイプは同等です。たとえば、a -> bc -> dは同等です(acbd)。
  3. 型を型tに変換できるが、元に戻すことt't'できない場合t、それt'はの特殊化であると言えtます。たとえば、a -> aはの特殊化ですa -> b

さて、これらの非常に便利な概念により、質問への答えは非常に簡単です。関数の「ネイティブ」タイプが完全に一致しなくても、完全に一致するように書き直したり特殊化したりできるため、互換性があります。Matt Fenwickの回答は、この場合にそれを行う専門分野を示しています。

于 2012-08-13T20:55:46.813 に答える
2

と統合しようとaし、それがである必要がm bあると単純に決定するため、 (仮定の下で)のタイプはであり、に適用すると、が残ります。am b(=<<)a ~ m bMonad m => (mb -> m b) -> m (m b) -> m bidMonad m => m (m b) -> m b

于 2012-08-13T16:27:21.817 に答える