Haskell has a type called Dynamic which resembles a dynamically-typed variable in some other languages. Dynamic is a sort of wrapper that can hold a value of any type.
We might use this, for example, to construct a heterogeneous list – that is, a list containing elements of different types.
The function toDyn creates a Dynamic. Here we apply it to arguments of three different types – a Bool, an Integer, and a String – to construct a list of three Dynamics.
import Data.Dynamic
import Data.Foldable
mixedList =
[ toDyn True
, toDyn (5 :: Integer)
, toDyn "hey"
]This example program iterates over the list and prints a message describing each element. (We will define the message function later below.)
main =
for_ mixedList $ \d ->
putStrLn (message d)The only thing we can do with a Dynamic is use the fromDynamic function to attempt to cast it back to its original type. If the cast succeeds, it returns Just the original value; otherwise it returns Nothing.
We have written the recognizeType function to generate two kinds of messages: one if the dynamic type is Integer, and another if the type is Bool. The asum function chooses the first Just among the list of Maybes.
recognizeType d =
asum
[ (fromDynamic d :: Maybe Integer) >>= \x ->
Just (show x ++ " is an integer")
, (fromDynamic d :: Maybe Bool) >>= \x ->
Just ("The answer is " ++ (if x then "yes" else "no"))
]It is possible that neither of the possibilities above succeeded. A Dynamic can hold a value of any type, and since there is an unlimited number of types in the world, we cannot check them all. So we have a last resort: if all else fails and the asum produces Nothing, we return an apologetic message that contains the name of the type.
message d =
case (recognizeType d) of
Just x -> x
Nothing -> "Unrecognized type: " ++ show (dynTypeRep d)Since we neglected to write a case to handle the String type, the third message says “unrecognized type”.
$ runhaskell dynamic.hs
The answer is yes
5 is an integer
Unrecognized type: [Char]Next: Monitoring

