我正在用 Haskell 编写两个程序,readFoo.hs
和 writeFoo.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
类型。
有没有办法做我想做的事?
答案 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 ()