“我的大脑即将爆炸”告诉我ghc,感觉是相互的。
有一个聚合函数可以作为多态向量的魅力(内存列存储上下文) - 将第一个的唯一值取2个向量和组,同时将函数f应用于第二个值。因此,类似于SQL GROUP BY或mongo聚合。例子:
\> groupColumns creg (+) cint
fromList [("EMEA",345),("NA",681),("RoW",988)]
\> groupColumns cint (*) cdouble
fromList [(1,13.0),(2,46.0),(4,16.0),(23,5359.0),(24,528.0),(234,5475.599999999999),(43,18619.0),(12,14.399999999999999),(412,1697.44),(252,-6350.4)]
相关代码:
groupColumns :: (Eq k, G.Vector v k, G.Vector v2 a, Hashable k) =>
v k -> (a -> a -> a) -> v2 a -> Map.HashMap k a
groupColumns xxs f yys = ...
cint :: U.Vector Int64
cint = U.fromList [1,2,43,234,23,412,24,12,4,252,1,2,43,234,23,412,24,12,4,252]
cdouble :: U.Vector Double
cdouble = U.fromList [13,23,433,23.4,233,4.12,22,1.2,4,-25.2, 1,2,43,234,23,412,24,12,4,252]
creg :: V.Vector Text
creg = V.fromList ["EMEA", "NA", "EMEA", "RoW", "NA", "RoW", "EMEA", "EMEA", "NA", "RoW", "EMEA", "NA", "RoW", "NA", "RoW", "NA", "RoW", "EMEA", "NA", "EMEA"]
当我想解析用户的输入并运行动态构建的聚合函数时,会出现问题。假设有一个"Region" : Text, "Revenue" : Int, "Country" : Text, "Booking Date" : Int
的源数据表。用户可能想要做(伪代码):1)groupby "Region", "Country" sum "Revenue"
或2)groupby "Country", "Booking Date" sum "Revenue"
等等。问题是“区域”和“国家”向量是V.Vector Text
而“预订日期” “和”收入“是U.Vector Int64
- 所以我不能将它们存储在一个Hashtable或List中并做一个显而易见的事情:从这一个Hashtable或List中获取抽象(Vector a),将它们传递给{{1}函数(已经完全支持多态向量!!!)并得到一个结果。我不关心groupColumns的特定类型,我只关心我传递的任何东西都支持Vector接口(作为类型族的一部分)。
所以,归结为:我需要某种存储类型1)给定groupColumns
(向量名称)2)返回Text
或U.Vector a
没有明确的类型签名。在理想的世界中,它只是一行调用:V.Vector b
,其中groupColumns (extractVec col1 cms) func (extractVec col2 cms)
和col1
是从用户输入解析的文本,col2
是从解析动态设置的函数用户输入。
在现实世界中,我尝试过:
1)异构技巧(func
排序)但是我和ghc大脑都开始爆炸,因为各种类型变量都逃避了它们的范围(例如,在传递给groupColumns的f函数中) - 尽管从Data HV where HV :: (Vector v a) => v a -> HV
获取(HV U.Vector Int64)
非常简单。
2)键入的矢量存储,如下所示:
[(Text, HV a)]
具有多态data ColumnMemoryStore = ColumnMemoryStore {
intCols :: Map.HashMap Text (U.Vector Int64),
doubleCols :: Map.HashMap Text (U.Vector Double),
textCols :: Map.HashMap Text (V.Vector Text),
typeSchema :: Map.HashMap Text SupportedTypes -- helper map from column names to their types
}
函数,因此我可以执行extractVector
- 它会自动从intCols返回U.Vector Int64,并分别返回给其他人。这里的问题是,在解析用户输入后,我必须分析他想要聚合的向量的类型(通过咨询extractVector name cms :: U.Vector Int64
)并给typeSchema
个调用提供相应的类型签名 - 绝对的,令人恐惧的extractVector
陈述的丑陋意粉让我想用C写一切,因为它会缩短5倍。这是一个示例:
case
等等等。这编译和工作,但它是丑陋的,非功能性和样板。我的意思是,执行此操作的唯一原因是需要明确指定let t1 = checkColType' colname (cms gs)
case t1 of
PText -> let col = extractVec colname (cms gs) :: V.Vector T.Text
result = groupColumns col (+) aggCol
in outputStrLn $ show result
PInt -> let col = extractVec colname (cms gs) :: U.Vector Int64
result = groupColumns col (+) aggCol
in outputStrLn $ show result
的返回类型,而然后它是从不1>} extractVec
使用的只需要groupColumns
的任何内容!必须要有办法解决它...
3)我是否应该考虑Data.Reflection或类似的东西,但同样可怕?模板Haskell?
我很抱歉有一个很长的描述,但我花了大量的时间研究并感觉完全陷入困境 - 这可能(希望)意味着我错过了一些非常明显的东西(比如没有足够的抽象水平)和那些思考的人在Haskell中,至少可以指出解决这个问题的正确方法。非常感谢!