2013-11-19 2 views
3

Этого вопрос использует понятия/импорт из http://hackage.haskell.org/package/recursion-schemes-4.0/docs/Data-Functor-Foldable.htmlИмея вопрос простирающегося Data.Functor.Foldable

Я пытаюсь распространить эту нить заданных монад через катаморфизм. Вот код, который я пытаюсь скомпилировать:

class (Monad m, Foldable t) => FoldableM m t where 
    distM :: Base t (m a) -> m (Base t a) 

    cataM :: (Base t a -> m a) -> t -> m a 
    cataM f = join . liftM f . distM . fmap (cataM f) . project 

Но призыв к distM в cataM по какой-то причине не могу понять, чтобы использовать один и тот же t.

Ошибки я получаю:

Expected type: Base t (m a) -> m (Base t a) 
Actual type: Base t0 (m a) -> m (Base t0 a) 

Я сделал код немного менее сексуально и немного легче для отладки здесь:

cataM :: forall a . (Base t a -> m a) -> t -> m a 
cataM f t = join d 
    where 
    a :: Base t t 
    a = project t 

    b :: Base t (m a) 
    b = fmap (cataM f) a 

    g :: Base t (m a) -> m (Base t a) 
    g = distM 

    c :: m (Base t a) 
    c = g b 

    d :: m (m a) 
    d = liftM f c 

Определение g является то, что вызывает проблему.

EDIT: Проблема, поскольку я понимаю, что когда она называет distM, она имеет только Base t, чтобы вывести тип, поэтому он не может работать t. Это разочаровывает, так как я знаю, что t Я хочу использовать. На самом деле, я думаю, что если я могу предоставить аргументы типа distM вручную, это исправит проблему, но я не думаю, что это возможно.

Вот решение, но я не доволен этим:

class (Monad m, Foldable t) => FoldableM m t where 
    distM :: t -> Base t (m a) -> m (Base t a) 

    cataM :: forall a . (Base t a -> m a) -> t -> m a 
    cataM f = join . liftM f . distM (undefined :: t) . fmap (cataM f) . project 

EDIT 2: Прохладный, чтобы узнать о Proxy (спасибо Антал). Я уже много лет занимаюсь Haskelling и только что узнал еще одну новую вещь. Мне нравится этот язык. Решение я использую:

class (Monad m, Foldable t) => FoldableM m t where 
    distM :: proxy t -> Base t (m a) -> m (Base t a) 

    cataM :: forall a . (Base t a -> m a) -> t -> m a 
    cataM f = join . liftM f . distM (Proxy :: Proxy t) . fmap (cataM f) . project 
+0

Может быть, вам нужны 'ScopedTypeVariables'? – chaosmasttter

+0

К сожалению, нет :(переменная типа 't' уже определена, потому что мы находимся в определении типа класса. – Will

ответ

3

Base t тип семьи, поэтому GHC не может знать t от Base t. Невозможно получить distM для работы без упоминания t.

+0

Нет вообще? :( Я думаю, мне придется добавить' t' в 'distM' как ghost parameter. – Will

+1

@Will: проблема в том, что 'Base' может не быть инъективным, подумайте, что произойдет, если' Base S1 T1 ~ A' и 'Base S2 T2 ~ A'. Также вы можете использовать' Proxy 'чтобы сделать его явным, что параметр предназначен только для ввода (возможно, с' -XKindPolymorphism'): 'data Proxy t = Proxy', а затем' distM :: Proxy t -> ... '. –

+0

Если вы используете прокси, возможно, используйте подпись 'distM :: gt -> ...' вместо 'Proxy t'? Существует несколько разных прокси-серверов, и это будет работать со всеми из них, а не ограничиваться одним конкретным прокси-сервером. –

Смежные вопросы