Введите подпись в предложении 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 для получения дополнительной информации.

Другие вопросы по тегам