异构类型作为Data.Map的值

时间:2014-12-08 22:31:16

标签: haskell map

我希望能够做到这样的事情,这显然是不允许的。

import qualified Data.Map as Map
x = Map.fromList [ 
      ("Name",    ["John", "Steve", "Kelly", "Zoe"]), 
      ("Surname", ["Smith", "Lee", "Ng", "White"]), 
      ("Age",     [1, 2, 3, 4]) 
    ]

一种可能的解决方案是创建一个这样的类型:

data L = LInt [Int] | LString [String]

x = Map.fromList [ 
      ("Name",    LString ["John", "Steve", "Kelly", "Zoe"]),
      ("Surname", LString ["Smith", "Lee", "Ng", "White"]), 
      ("Age",     LInt    [1, 2, 3, 4]) 
    ]

这是不受欢迎的。有更好的方法吗?

我的实际使用案例:  非常广泛地说,我正在尝试实现dplyr(http://cran.r-project.org/web/packages/dplyr/vignettes/introduction.html)的部分,这可以被视为数据的语法"。 Dplyr具有表格数据的列和行选择以及行的分组和连接的表达式,其中行数可以是数百万,列数是数百。它不是我现在关注的数据大小,而是能够生成与该软件包类似的功能和工作流程

1 个答案:

答案 0 :(得分:3)

您可以使用存在量化

{-# LANGUAGE ExistentialQuantification, FlexibleInstances, TypeSynonymInstances #-}

import qualified Data.Map as Map

class ColumnData c
instance ColumnData Integer
instance ColumnData String

data Column = forall c . ColumnData c => Column [c]

x = Map.fromList [
        ("Name",    Column ["John", "Steve", "Kelly", "Zoe"]),
        ("Surname", Column ["Smith", "Lee", "Ng", "White"]),
        ("Age",     Column [1::Integer, 2, 3, 4])
    ]

(注意我们在最后一列中需要一个显式的类型注释,因为文字被重载,而存在不能完全解决这个问题。)

当然,x无法获得映射数据的真实类型。您只有forall a . a => Column a,而您唯一能做的就是调用class Column的方法。此示例定义none。你应该添加自己的方法,你必须明智地选择。

请注意,这项技术不受许多铁杆打击者的欢迎,原因我不太了解。如果有人能够对此有所了解,那就太好了。

相关问题