8

最近、私は Haskell、特にファンクタの概念全体をいじっています。飛び込むほど、a-haの瞬間が増え、ドーパミン受容体がかなりくすぐられます.

私が立ち往生している問題は次のとおりです。機能するコードは次のとおりです。関数を持ち上げて、最初に IO 値に適用し、次にリストに適用します。

replicator1 =
  fmap (replicate 3)

replicator2 =
  fmap (replicate 3)

main = do
  replicated <- replicator1 getLine
  print (replicator2 replicated)

より簡潔な方法でそれを書くことは非常に魅力的です。つまり:

replicator =
  fmap (replicate 3)

main = do
  replicated <- replicator getLine
  print (replicator replicated)

私の一部は、IO と List インスタンスの両方に適用できるはずなので、概念的に正しいと言っていreplicatorますが、強く型付けされた言語である Haskell ではそうすることができません。なぜこのようなことが起きているのか、おおむね理解できたと思います。

問題は、後者のバリアントに近づく方法はありますか? それとも前者と同居していいの?

ありがとうございました!

4

1 に答える 1

19

あなたのコードは実際には問題ありませんが、 Haskell がの最も一般的な可能な型を推測できないという恐ろしい単型性の制限に遭遇したことを除けば.replicator

本質的に、上の制限により、Haskell は関数のように見えないバインディングのポリモーフィック型を推論しません。これは、or[]IOような具象ファンクターを選択するreplicate必要があり、2 つの異なるコンテキストで使用しようとするとエラーが発生することを意味します。

コードを機能させるには、次の 3 つの方法があります。

  • モノモーフィズムの制限をオフにし{-# LANGUAGE NoMonomorphismRestriction #-}ます: モジュールの先頭に追加します。

  • 関数のようにreplicator 見せます:

    replicator x = fmap (replicate 3) x
    
  • コードに明示的な型シグネチャを追加する

    replicator :: Functor f => f a -> f [a]
    replicator = fmap (replicate 3)
    

3 番目のオプションは最も慣用的です。優れた Haskell スタイルには、トップレベルのすべての識別子に明示的な型シグネチャを追加することが含まれます。ただし、他の 2 つのオプションを知っておくと、何が起こっているのかを理解し、タイプ シグネチャを気にせずに Haskell で簡単な使い捨てスクリプトを作成できるようになります。

于 2015-08-19T05:34:52.307 に答える