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 Dynamic
s.
import Data.Dynamic
import Data.Foldable
=
mixedList True
[ toDyn 5 :: Integer)
, toDyn ("hey"
, toDyn ]
This example program iterates over the list and prints a message describing each element. (We will define the message
function later below.)
=
main $ \d ->
for_ mixedList 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 Maybe
s.
=
recognizeType d
asum d :: Maybe Integer) >>= \x ->
[ (fromDynamicJust (show x ++ " is an integer")
d :: Maybe Bool) >>= \x ->
, (fromDynamicJust ("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