Введите подпись в предложении where - PullRequest
13 голосов
/ 03 августа 2011

Я написал функцию, аналогичную 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 ]

14 голосов
/ 03 августа 2011

Вы, вероятно, не можете дать 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
9 голосов
/ 03 августа 2011

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

...