我编写了一个类似于Data.Enumerator.List.map
的函数,它使Iteratee
与Enumerator
兼容,并提供不同的Stream
类型。
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
找到正确类型签名的建议。
答案 0 :(得分:14)
您可能无法按原样为go
提供类型签名。
这样做的原因是它使用了test
绑定的多态参数。这意味着,在go
内,标识符f
的类型为(ao -> ai)
某些特定但未知的类型ao
和ai
类型变量通常仅在引入它们的单一类型签名的范围内,因此当您为go
提供自己的类型签名时,ao
和ai
会有新的,多态类型,当尝试将它们与来自test
签名的类似命名但固定(和不可知)的类型组合时,当然会导致类型错误。
最终结果是你不能明确地写出go
的类型,这不是很令人满意。为了解决这个问题,GHC提供了the ScopedTypeVariables extension,它允许在函数的where
子句中的范围内引入类型签名中引入的变量,等等。
请注意,如果仅使用where
子句为定义创建内部作用域,并且不使用由外部函数的参数绑定的标识符,则可以在{{1}中编写类型签名就像你可以用于顶级绑定一样。如果您不想使用GHC扩展,则只需冗余地传递参数即可。在这种情况下,这样的事情应该有效:
where
答案 1 :(得分:8)
您可能需要该类型,但启用了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。