Haskell 基本型有限域容器上的动态类型化
我在编写一个简单函数时遇到了一个问题,没有太多的重复,下面是一个简化的例子。我试图编写的真正程序是python中BI服务器的内存数据库端口。实际上,有更多不同的类型(大约8种)和更多的逻辑,它们大多可以表示为在多态类型上操作的函数,如向量a,但仍有一些逻辑必须处理不同类型的值 由于效率原因,单独包装每个值(使用[(Int,WrappedValue)]类型)不是一个选项-在实际代码中,我使用的是非固定向量Haskell 基本型有限域容器上的动态类型化,haskell,dynamic-typing,Haskell,Dynamic Typing,我在编写一个简单函数时遇到了一个问题,没有太多的重复,下面是一个简化的例子。我试图编写的真正程序是python中BI服务器的内存数据库端口。实际上,有更多不同的类型(大约8种)和更多的逻辑,它们大多可以表示为在多态类型上操作的函数,如向量a,但仍有一些逻辑必须处理不同类型的值 由于效率原因,单独包装每个值(使用[(Int,WrappedValue)]类型)不是一个选项-在实际代码中,我使用的是非固定向量 type Vector a = [(Int, a)] -- always sorted by
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)]]
type Vector a=[(Int,a)]--始终按fst排序
data WrappedVector=--实际上有8个
浮动向量(向量浮动)
|IntVector(向量Int)
推导(等式,显示)
查询::[WrappedVector]->[WrappedVector]——等长
查询向量=映射(filterIndexW CommonIndexs)向量
哪里
CommonIndex=交点[mapFstW向量|向量[Int]
交叉点=头部--虚拟输入(排序向量的交叉点)
filterIndex::Eq a=>[Int]->向量a->向量a
filterIndex Indexes vector=--示例实现
过滤器(\(idx,\)->idx`elem`index)向量
mapFst::向量a->[Int]
mapFst=map fst
--理想情况下,我可以到此为止,但我必须为所有可能的类型编写repeat
--包装容器的种类和功能如下:
filterIndexW::[Int]->WrappedVector->WrappedVector
filterIndexW指数vw=情况vw
FloatVector v->FloatVector$filterIndex v
IntVector v->IntVector$filterIndex索引v
mapFstW::WrappedVector->[Int]
mapFstW vw=案例vw
浮动向量v->映射fst v
IntVector v->映射fst v
--查询的示例用法
main=putStrLn$show$query[FloatVector[(1,12),(2,-2)],
IntVector[(2,17),(3,-10)]]
如何在没有像mapFstW和filterIndexW函数那样包装和展开的情况下表达这样的代码?包装单个类型而不影响性能的标准选项是
{-# LANGUAGE GeneralizedNewtypeDeriving #-} -- so we can derive Num
newtype MyInt = My Int deriving (Eq,Ord,Show,Num)
newtype AType a = An a deriving (Show, Eq)
因为它只在类型级别上产生差异-数据表示是相同的,因为它都被编译掉了。您甚至可以指定值是未绑定的,但是…这对您没有帮助,因为您正在包装多个类型
真正的问题是,您试图用静态类型化语言表示动态类型化的解决方案。动态类型化的性能必然会受到影响,动态类型化在动态语言中是隐藏的,但在标记中是显式的
您有两种解决方案:
我觉得2是目前为止最好的解决方案,你应该放弃尝试列出你想要使用的所有类型的程序,而不是使用任何类型的程序。它简洁、清晰、高效。你检查有效性并处理一次,然后就不用担心了。如果你愿意使用一些编译器扩展,请解决这个问题这是你的问题
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE StandaloneDeriving #-}
module VectorTest where
type PrimVector a = [(Int, a)]
data Vector = forall a . Show a => Vector (PrimVector a)
deriving instance Show Vector
query :: [Vector] -> [Vector] -- equal length
query vectors = map (filterIndex commonIndices) vectors
where
commonIndices = intersection [mapFst vector | vector <- vectors]
intersection :: [[Int]] -> [Int]
intersection = head -- dummy impl. (intersection of sorted vectors)
filterIndex :: [Int] -> Vector -> Vector
filterIndex indices (Vector vector) = -- sample inefficient implementation
Vector $ filter (\(idx, _) -> idx `elem` indices) vector
mapFst :: Vector -> [Int]
mapFst (Vector l) = map fst l
-- sample usage of query
main = putStrLn $ show $ query [Vector [(1, 12), (2, -2)],
Vector [(2, 17), (3, -10)]]
这很好地概括了实际问题(有一点Data.Typeable的帮助),谢谢!很高兴听到这很有帮助!
instance Show Vector where
show (Vector v) = show v