在where子句中键入签名

时间:2011-08-03 15:19:53

标签: haskell enumerator parametric-polymorphism

我编写了一个类似于Data.Enumerator.List.map的函数,它使IterateeEnumerator兼容,并提供不同的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找到正确类型签名的建议。

2 个答案:

答案 0 :(得分:14)

您可能无法按原样为go提供类型签名。

这样做的原因是它使用了test绑定的多态参数。这意味着,在go内,标识符f的类型为(ao -> ai) 某些特定但未知的类型aoai

类型变量通常仅在引入它们的单一类型签名的范围内,因此当您为go提供自己的类型签名时,aoai会有新的,多态类型,当尝试将它们与来自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