我已经编写了一个类似于Data.Enumerator.List.map的函数,它使Iteratee与提供不同Stream类型的Enumerator兼容。
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找到正确的类型签名的建议。
发布于 2011-08-03 23:32:16
您可能不能按原样为go提供类型签名。
这样做的原因是它使用了test绑定的多态参数。这意味着,在go中,标识符f的类型为(ao -> ai),表示某些特定但未知的类型ao和ai。
类型变量通常只在引入它们的单个类型签名的作用域中,所以当您为go提供它自己的类型签名时,ao和ai有新的、多态的类型,这在试图将它们与test签名中命名相似但固定(和未知)的类型组合时,当然会导致类型错误。
最终的结果是您不能显式地编写go的类型,这并不是很令人满意。为了解决这个问题,GHC提供了the ScopedTypeVariables extension,它允许在函数的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-03 23:31:03
您可能需要该类型,但要启用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 documentation。
https://stackoverflow.com/questions/6928884
复制相似问题