2013-10-04 2 views
2

유형이 [*] 인 유형 수준 목록이있는 공통 패턴이 있으며 목록의 각 요소에 유형이 * -> * 인 유형 생성자를 적용하고 싶습니다. 예를 들어 '[Int, Double, Integer]'[Maybe Int, Maybe Double, Maybe Integer]으로 변경하고 싶습니다.데이터 킨이있는 유형 수준 맵

여기 입력 수준 map을 구현하려는 시도입니다.

{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, TypeOperators, DataKinds, ScopedTypeVariables, GADTs #-} 

-- turns a type list '[b1, b2, b3] 
-- into the type list '[a b1, a b2, a b3] 
class TypeMap (a :: * -> *) (bs :: [*]) where 
    type Map a bs :: [*] 

instance TypeMap a '[b] where 
    type Map a '[b] = '[a b] 

instance TypeMap a (b1 ': b2 ': bs) where 
    type Map a (b1 ': b2 ': bs) = ((a b1) ': (Map a (b2 ': bs))) 


data HList :: [*] -> * where 
       HNil :: HList '[] 
       HCons :: a -> HList as -> HList (a ': as) 

class Foo as where 
    toLists :: HList as -> HList (Map [] as) 

instance Foo '[a] where 
    toLists (HCons a HNil) = HCons [a] HNil 

instance (Foo (a2 ': as)) => Foo (a1 ': a2 ': as) where 
    toLists (HCons a as) = 
     let as' = case (toLists as) of 
        (HCons a2 as'') -> HCons [head a2] as'' -- ERROR 
     in HCons [a] as' 

Could not deduce (a3 ~ [t0]) 
    from the context (Foo ((':) * a2 as)) 
     bound by the instance declaration at Test.hs:35:10-50 
    or from ((':) * a1 ((':) * a2 as) ~ (':) * a as1) 
     bound by a pattern with constructor 
       HCons :: forall a (as :: [*]). 
          a -> HList as -> HList ((':) * a as), 
       in an equation for `toLists' 
     at Test.hs:36:14-23 
    or from (Map [] as1 ~ (':) * a3 as2) 
     bound by a pattern with constructor 
       HCons :: forall a (as :: [*]). 
          a -> HList as -> HList ((':) * a as), 
       in a case alternative 
     at Test.hs:38:22-34 
     `a3' is a rigid type variable bound by 
      a pattern with constructor 
      HCons :: forall a (as :: [*]). 
         a -> HList as -> HList ((':) * a as), 
      in a case alternative 
      at Test.hs:38:22 
    Expected type: HList (Map [] ((':) * a2 as)) 
     Actual type: HList ((':) * [t0] as2) 
    In the return type of a call of `HCons' 
    In the expression: HCons [head a2] as'' 
    In a case alternative: (HCons a2 as'') -> HCons [head a2] as'' 

내가 풍부한 유형 약어를 추가 해봤 오류가 발생하지만 오류가 더 많거나 적은 동일한 나오는 : GHC도 추측 할 수없는의 첫 번째 요소 HList는 (정상적인) 목록입니다. 내가 바보 같은 짓을하고 있니? 뭔가 불법인가? 아니면 주위에 어떤 방법이 있습니까?

+1

왜 TypeMap [] 인스턴스가 없습니까? –

+0

@DanielWagner 동의합니다. 해당 인스턴스는 '[]와 (a': as)에 대한 것일 것입니다. – crockeea

답변

6

TypeMap a (b1 ': b2 ': bs)을 작성하면 Map ...을 정의하는 재귀와 일치하지 않으므로 1 또는 2 개의 요소가 아닌 TypeMap 목록을 만들 때 오류가 발생합니다. 또한, 귀하의 경우에는이 유형의 가족이있는 것이 더 깔끔합니다. 코드 컴파일이 []b:bs에 대한 인스턴스로 [a]b1:b2:bs에 대한 인스턴스를 변경하는 것입니다 수

map f [] = [] 
map f (x:xs) = f x : map f xs 
+0

타입 패밀리 솔루션을 지적 해 주셔서 감사합니다. 수업보다 훨씬 깨끗합니다. – crockeea

4

최소한의 변화 :

type family TypeMap (a :: * -> *) (xs :: [*]) :: [*] 
type instance TypeMap t '[] = '[] 
type instance TypeMap t (x ': xs) = t x ': TypeMap t xs 

참고이 거의의 직접 번역 한 것입니다.

instance TypeMap a '[] where 
    type Map a '[] = '[] 

instance TypeMap a (b ': bs) where 
    type Map a (b ': bs) = a b ': Map a bs 
+0

@ Eric 나는이 문제가 이렇게 될 것이라고 생각한다 : 재귀 호출이'HCons'에 부합한다. 다시 말해서, 재귀 적 타입 레벨 호출이 또한 cons 셀을 쉽게 보이게 할 것이라는 것을 의미한다. 그러나 선택할 수있는 두 가지 인스턴스가 있기 때문에 쉽게 알 수 없습니다. GHC가 수행하지 않는 (아마도 시도해서는 안되는) 유형 클래스의 폐쇄에 대한 몇 가지 추론이 필요합니다. 이 수정으로'TypeMap'에 대한 인수로 쉽게 볼 수있는 단락 셀이있는 경우 GHC에서 선택할 수있는 인스턴스가 하나뿐이므로 선택할 수 있습니다. –