存在类型和类型类实例

时间:2013-01-22 22:39:56

标签: haskell

我正在为Haskell开发一个Hadoop库,但遇到了一些我无法解决的存在类型和类型类的问题。我的代码如下:

type Mapper k1 v1 k2 v2 = k1 -> v1 -> IO [(k2,v2)]

type Reducer k1 v1 k2 v2 = k1 -> [v1] -> IO [(k2,v2)]

data Iteration k1 v1 k3 v3 = forall k2 v2 . Iteration (Mapper k1 v1 k2 v2) (Reducer k2 v2 k3 v3)

data Job k1 v1 k3 v3 = EmptyJob | forall k2 v2 . ConsJob (Iteration k1 v1 k2 v2) (Job k2 v2 k3 v3)

type IterationNumber = Int
data IterationPhase = IterationMapper | IterationReducer

runJobIteration :: Job k1 v1 k2 v2 -> IterationNumber -> IterationPhase -> IO ()
runJobIteration EmptyJob _ _ = return ()
runJobIteration (ConsJob (Iteration m r) _) 0 IterationMapper = runMapper m
runJobIteration (ConsJob (Iteration m r) _) 0 IterationReducer = runReducer r
runJobIteration (ConsJob (Iteration m r) j) i p = runJobIteration j (i-1) p

runMapper :: (Parsable k1, Parsable v1, Showable v2, Showable k2) => Mapper k1 v1 k2 v2 ->   IO ()
runMapper mapper = do
    contents <- getContents
    mapOutput <- mapM (uncurry mapper . parseKeyValue) $ lines contents
    mapM_ putStrLn $ map showKeyValue $ concat mapOutput


runReducer :: (Parsable k1, Parsable v1, Eq k1, Eq v1, Showable v2, Showable k2) =>    Reducer k1 v1 k2 v2 -> IO ()
runReducer reducer = do
    contents <- getContents
    reduceOutput <- mapM (uncurry reducer) $ groupMapOutput $ map parseKeyValue $ lines contents
    mapM_ putStrLn $ map showKeyValue $ concat reduceOutput

parseKeyValue :: (Parsable k, Parsable v) => String -> (k,v)
parseKeyValue = (parse *** parse) . split (== '\t')


split :: (a -> Bool) -> [a] -> ([a], [a])
split p xs = let (group, rest) = break p xs
             in (group, tail rest)

showKeyValue :: (Showable k, Showable v) => (k,v) -> String
showKeyValue (k,v) = showit k ++ "\t" ++ showit v

groupMapOutput :: (Eq k, Eq v) => [(k,v)] -> [(k,[v])]
groupMapOutput kvs = groupMapOutput' kvs []
groupMapOutput' kvs gs
    | kvs == [] = gs
    | otherwise = groupMapOutput' rest (gs ++ [(k, map snd group)])
        where 
            k = fst (head kvs)
            (group, rest) = span ((== k) . fst) kvs

当我尝试加载上面的代码时,我总是会收到以下错误:

No instances for (Showable k4,
                    Showable v4,
                    Parsable v1,
                    Parsable k1)
    arising from a use of `runMapper'
  In the expression: runMapper m
  In an equation for `runJobIteration':
      runJobIteration (ConsJob (Iteration m r) _) 0 IterationMapper
        = runMapper m

我尝试将类型类添加到数据构造函数中,但这似乎不起作用。我还尝试创建隐藏类型的AnyMapper数据类型,但这也没有用。任何人都知道如何优雅地解决这个问题?

1 个答案:

答案 0 :(得分:1)

好的,我设法通过遍历所有函数和数据类型并添加必要的类型约束来解决它,直到它编译完成。主要问题似乎是我需要为不存在的部分中的类型包含类型约束。编译器以不同的方式命名这些类型,使其有点混乱。作为参考,以下是最重要的变化。我打算切换到类型类而不是这些长类型约束列表,因为它们非常难以管理。


data Iteration k1 v1 k3 v3 = forall k2 v2 . (Eq k2, Eq v2, Showable k2, Showable v2, Parsable k2, Parsable v2) => Iteration (Mapper k1 v1 k2 v2) (Reducer k2 v2 k3 v3)
data Job k1 v1 k3 v3 = EmptyJob | forall k2 v2 . (Eq k2, Eq v2, Showable k2, Showable v2, Parsable k2, Parsable v2) => ConsJob (Iteration k1 v1 k2 v2) (Job k2 v2 k3 v3)
runJobIteration :: (Parsable k1, Parsable v1, Parsable k2, Parsable v2, Showable k1, Showable v1, Showable k2, Showable v2) => Job k1 v1 k2 v2 -> IterationNumber -> IterationPhase -> IO ()