14

別のタイプをフィードするとData.Enumerator.List.map互換Iteratee性のあるものと同様の関数を作成しました。EnumeratorStream

import Data.Enumerator

test :: Monad m => (ao -> ai) -> Iteratee ai m b -> Iteratee ao m b
test f iter = go $$ iter
   where go (Continue k) = continue $
            \stream -> go $$ k (fmap f stream)
         go (Yield res _) = yield res EOF

の型署名を省略した場合go、これは問題なく機能します。しかし、それを含めたいのですが、正しい署名がどうあるべきかを判断できません。これが私がそうあるべきだと思うものです:

go :: Monad m => Step ai m b -> Iteratee ao m b

しかし、それは機能しません。
の正しい型アノテーションを見つけるためのアドバイスが必要ですgo

4

2 に答える 2

16

go型注釈をそのまま指定することはおそらくできません。

この理由は、によってバインドされた多態的な引数を利用するためですtest。これは、の内部goで、識別子f特定の、しかし未知のタイプとのタイプ(ao -> ai)を持っていることを意味します。aoai

型変数は通常、それらが導入された単一の型シグニチャのスコープ内にあるためgo、独自の型シグニチャを指定するaoai、新しいポリモーフィック型があり、もちろん、それらを組み合わせようとすると型エラーが発生します。同様の名前ですが、testの署名からの固定(および不明)型。

goその結果、タイプを明示的に記述できなくなり、満足のいくものではなくなります。これを解決するために、GHCはScopedTypeVariables拡張機能を提供します。これにより、型シグネチャで導入された変数をwhere、特に関数の句内のスコープに取り込むことができます。

where句を使用して定義の内部スコープを作成するだけで、外部関数への引数によってバインドされた識別子を使用しないwhere場合は、トップレベルのバインドの場合と同じように、句に型シグネチャを書き込むことができます。GHC拡張機能を使用したくない場合は、パラメーターを冗長に渡すだけです。その場合、このようなものが機能するはずです。

test :: Monad m => (ao -> ai) -> Iteratee ai m b -> Iteratee ao m b
test f iter = go f $$ iter
  where go :: Monad m => (ao -> ai) -> Step ai m b -> Iteratee ao m b
        go f (Continue k) = continue $
             \stream -> go f $$ k (fmap f stream)
        go _ (Yield res _) = yield res EOF
于 2011-08-03T15:32:16.477 に答える
9

おそらくその型が必要ですが、ScopedTypeVariables拡張機能が有効になっていてtest、スコープ内のの型シグネチャの変数があります。

{-# LANGUAGE ScopedTypeVariables #-}
import Data.Enumerator
test :: forall m ai ao b. Monad m => (ao -> ai) -> Iteratee ai m b -> Iteratee ao m b
test f iter = go $$ iter
   where go :: Step ai m b -> Iteratee ao m b
         go (Continue k) = continue $
            \stream -> go $$ k (fmap f stream)
         go (Yield res _) = yield res EOF

詳細については、GHCのドキュメントを参照してください。

于 2011-08-03T15:31:02.787 に答える