确定 Haskell 中序列化数据类型的类型

时间:2021-04-15 17:49:02

标签: haskell

我正在用 Haskell 编写两个程序,readFoo.hswriteFoo.hs

Foo 是这样定义的数据类型:

data Structure = ListStruct | TreeStruct

data Foo t = Foo {
    struct  :: Structure
  , content :: t Int
}

其中 t 是列表或树。

writeFoo.hs 写入 Foo t 类型的值,其中 t 由选项确定:

main = case option of
    ListStruct -> writeListFoo
    TreeStruct -> writeTreeFoo

现在我想让 readFoo.hs 读取写入的文件并根据 Foo 的结构运行一个函数:

main = do
    foo <- readFoo
    case struct foo of
        ListStruct -> runListFoo
        TreeStruct -> runTreeFoo

runListFunction :: Foo [] -> IO ()
runTreeFunction :: Foo Tree -> IO ()

但这失败了,因为显然 foo 不能同时属于 Foo []Foo Tree 类型。

有没有办法做我想做的事?

1 个答案:

答案 0 :(得分:2)

您的表述似乎有误。您定义的类型 Foo 允许您编写“标签”与预期数据类型不匹配的术语:

-- Claims to be a "ListStruct" but the type is actually completely unrelated
badVal1 :: Foo Maybe
badVal1 = Foo ListStruct Nothing

-- Claims to be a "TreeStruct" but the type is actually list
badVal2 :: Foo []
badVal2 = Foo TreeStruct []

您可以如下定义您的类型以禁止上述错误值:

data Structure x where
  ListStruct :: Structure []
  TreeStruct :: Structure Tree

data Foo s where
  Foo :: Structure s -> s Int -> Foo s

请注意,通过此更改,Structure 显式编码了它所需的数据类型。

如果你有一个 Foo,但不知道是哪种类型,你也可以表达:

data SomeFoo where
  SomeFoo :: Foo s -> SomeFoo

并且您可以通过对 Structure 参数进行模式匹配来对这些值进行操作,这样您就可以发现数据的类型:

readFooAndDoSomething :: IO ()
readFooAndDoSomething = do
    SomeFoo (Foo struct datum) <- readFoo
    case struct of
        ListStruct -> runListFunction datum
        TreeStruct -> runTreeFunction datum


-- Left to the reader...
readFoo :: IO SomeFoo
runListFunction :: [Int] -> IO ()
runTreeFunction :: Tree Int -> IO ()
相关问题