Введите подпись в предложении where
Я написал функцию, похожую на 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
,
2 ответа
Вы, вероятно, не можете дать go
подпись типа как есть.
Причина этого заключается в том, что он использует полиморфные аргументы, связанные с test
, Это означает, что внутри go
, идентификатор f
имеет тип (ao -> ai)
для некоторых конкретных, но неизвестных типов ao
а также ai
,
Переменные типа, как правило, только в области видимости для сигнатуры одного типа, где они представлены, поэтому, когда вы даете go
его собственный тип подписи, ao
а также ai
Есть новые полиморфные типы, которые, конечно, вызывают ошибку типов при попытке объединить их с одноименными, но фиксированными (и непознаваемыми) типами из 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
Вы, вероятно, хотите этот тип, но с 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 для получения дополнительной информации.