1

我正在为 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 数据类型,但这也不起作用。任何人都知道我可以如何优雅地解决这个问题?

4

1 回答 1

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 ()

于 2013-01-23T09:48:41.027 回答