Pracuję nad implementacją HList i utknąłem próbując zaimplementować dla niej funkcję map
. Próbowałem wielu różnych podejść, ale z każdym z nich dochodzę do błędów kompilatora związanych z tą funkcją.Mapowanie heterogenicznej struktury danych z ogólną funkcją
Poniżej przedstawiono przykład użycia ogólnej funkcji Just
w celu zastosowania jej do wszystkich elementów struktury danych wejściowych.
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
-- | An input heterogenous data structure
recursivePairs :: (Int, (Char, (Bool,())))
recursivePairs = (1, ('a', (True,())))
-- | This is how I want to use it
recursivePairs' :: (Maybe Int, (Maybe Char, (Maybe Bool,())))
recursivePairs' = hMap Just recursivePairs
class HMap f input output where
hMap :: f -> input -> output
-- | A counterpart of a Nil pattern match for a list
instance HMap f()() where
hMap _ _ =()
-- | A counterpart of a Cons pattern match for a list
instance
(HMap f iTail oTail,
Apply f iHead oHead) =>
HMap f (iHead, iTail) (oHead, oTail)
where
hMap f (head, tail) = (apply f head, hMap f tail)
class Apply f input output where
apply :: f -> input -> output
instance Apply (input -> output) input output where
apply = id
Mając to ja otrzymuję następujący błąd kompilatora:
No instance for (Apply (a0 -> Maybe a0) Int (Maybe Int))
arising from a use of `hMap'
The type variable `a0' is ambiguous
Czy istnieje w ogóle taki sposób, aby rozwiązać ten problem, a jeśli nie, to dlaczego?
Myślę, że problemem jest to, że system typu nie zdaje sobie sprawy, że są instancji 'Just' z różnych rodzajów betonu na każdej kolejnej aplikacji, ponieważ definicja' hMap' utrzymuje ponowne wykorzystanie tego samego 'f'. Przy pierwszym zastosowaniu typem jest 'Int -> Maybe Int', po raz drugi stosuje się typ' Char -> Maybe Char'. Jednak nadal nie jestem pewien, jak to naprawić. –
@GabrielGonzalez Tak, to jest dokładnie problem. A jeśli dodasz fundusz "| dane wejściowe -> f' do klasy "Zastosuj", komunikaty o błędach powiedzą, że szukają instancji, takich jak '(Bool -> Maybe Bool) Char (Maybe Char)'. Myślałem o użyciu ['cast'] (http: //hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Typeable.html # v: cast), aby rozłączyć dwa zastosowania 'f' na poziomie typu, ale to nie było bardzo naturalne, i w zależności od 'Typeable' również nie było zbyt intrygujące. –