Reputation: 137
I am writing two programs in Haskell, readFoo.hs
and writeFoo.hs
.
Foo
is a datatype defined like this:
data Structure = ListStruct | TreeStruct
data Foo t = Foo {
struct :: Structure
, content :: t Int
}
where t
is either a list or a tree.
writeFoo.hs
writes a value of type Foo t
, where t
gets determined by an option:
main = case option of
ListStruct -> writeListFoo
TreeStruct -> writeTreeFoo
Now i want readFoo.hs
to read the written file and run a function depending on the structure of Foo
:
main = do
foo <- readFoo
case struct foo of
ListStruct -> runListFoo
TreeStruct -> runTreeFoo
runListFunction :: Foo [] -> IO ()
runTreeFunction :: Foo Tree -> IO ()
but this fails, because obviously foo
can't be of type Foo []
and Foo Tree
at the same time.
Is there a way to do what i want?
Upvotes: 0
Views: 66
Reputation: 14598
It would appear that you have a mistake in your formulation. The type Foo
you've defined allows you write terms whose "tag" doesn't match the intended type of data:
-- 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 []
You can define your type as follows to disallow the above bad values:
data Structure x where
ListStruct :: Structure []
TreeStruct :: Structure Tree
data Foo s where
Foo :: Structure s -> s Int -> Foo s
Note that with this change, Structure
explicitly encodes the type of data which it requires.
If you have a Foo
, but don't know of which type, you can express that as well:
data SomeFoo where
SomeFoo :: Foo s -> SomeFoo
and you can operate on such values by pattern matching on the Structure
argument, which allows you to discover the type of the data:
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 ()
Upvotes: 2