我在编写一个简单的函数而没有太多重复自己时遇到问题,下面是一个简化的示例。我正在尝试编写的真正程序是来自 python 的 BI 服务器的内存数据库端口。实际上,有更多不同的类型(大约 8 种)和更多的逻辑,这主要可以表示为对多态类型(如 Vector a)进行操作的函数,但仍然有一些逻辑必须处理不同类型的值。
由于效率原因,单独包装每个值(使用 [(Int, WrappedValue)] 类型)不是一个选项 - 在实际代码中,我使用的是未装箱的向量。
type Vector a = [(Int, a)] -- always sorted by fst
data WrappedVector = -- in fact there are 8 of them
FloatVector (Vector Float)
| IntVector (Vector Int)
deriving (Eq, Show)
query :: [WrappedVector] -> [WrappedVector] -- equal length
query vectors = map (filterIndexW commonIndices) vectors
where
commonIndices = intersection [mapFstW vector | vector <- vectors]
intersection :: [[Int]] -> [Int]
intersection = head -- dummy impl. (intersection of sorted vectors)
filterIndex :: Eq a => [Int] -> Vector a -> Vector a
filterIndex indices vector = -- sample inefficient implementation
filter (\(idx, _) -> idx `elem` indices) vector
mapFst :: Vector a -> [Int]
mapFst = map fst
-- idealy I whould stop here, but I must write repeat for all possible types
-- and kinds of wrapped containers and function this:
filterIndexW :: [Int] -> WrappedVector -> WrappedVector
filterIndexW indices vw = case vw of
FloatVector v -> FloatVector $ filterIndex indices v
IntVector v -> IntVector $ filterIndex indices v
mapFstW :: WrappedVector -> [Int]
mapFstW vw = case vw of
FloatVector v -> map fst v
IntVector v -> map fst v
-- sample usage of query
main = putStrLn $ show $ query [FloatVector [(1, 12), (2, -2)],
IntVector [(2, 17), (3, -10)]]
如何在不像 mapFstW 和 filterIndexW 函数那样进行包装和展开的情况下表达这样的代码?