The basic idea is that I have a range of functions that work on any types from a particular class, but at runtime the program is supposed to read a configuration file and extract an element of one of the types in the class.
For instance, I have a 'Coefficient' class, various instances of it, and functions of various types that are polymorphic over types of that class; at runtime one particular type of that class is to be determined, and passed around.
I'm unsure how to properly address this; I tried making up 'compound' types, doing something like:
data CompoundCoeff = CompoundInt Int | CompoundDouble Double | ...
where Int, Double, ... are instances of the class 'Coefficient'.
However, it started to become a big effort to adapt all the functions involved in the code to work with these compound types (and it's not a nice solution either, really). It would be OK if all functions had the same, easy type, e.g.
Coefficient a => a -> (stuff not involving a anymore)
but that's unfortunately not the case.
Another issue I ran into, is that I'm using type families, and have something like
class (Monoid (ColourData c), Coordinate (InputData c)) => ColourScheme c where
type ColourData c :: *
type InputData c :: *
colouriseData :: c -> (ColourData c) -> AlphaColour Double
processInput :: c -> InputData c -> ColourData c
This doesn't go through cleanly if I have to use some sort of compound ColourData datatype, like the previous one; in particular I can no longer guarantee that the data stream gives a consistent type (and not just different 'subtypes' of a compound type), and would (among other things) have to make up a bogus Monoid instance if I did make up a compound ColourData type.
I've also looked into Data.Dynamic, but again I can't see how it would properly address the issues; the exact same problems seem to appear (well, slightly worse even, given that there is only one 'generic' Dynamic type as I understand it).
Question: How can I implement dynamic datatypes subordinate to particular classes, without having to rewrite all the functions involving those data types? It would be best if I didn't have to sacrifice any type safety, but I'm not too optimistic.
The program is supposed to read a configuration file at runtime, and all the requisite functions, polymorphic over the relevant class, are to be applied.
The operations on these dynamic data types (add, subtract, compare) are usually implemented by a virtual method table, which is for each data type a number of pointers to functions that implement the desired functionality in a type-specific way.
Dynamic typing means that the type of the variable is determined only during runtime. Due to strong typing, types need to be compatible with respect to the operand when performing operations. For example Python allows one to add an integer and a floating point number, but adding an integer to a string produces error.
A language is dynamically-typed if the type of a variable is checked during run-time. Common examples of dynamically-typed languages includes JavaScript, Objective-C, PHP, Python, Ruby, Lisp, and Tcl.
Advantages of dynamically-typed languages:The absence of a separate compilation step (which is much more common) means that you don't have to wait for the compiler to finish before you can test changes that you've made to your code. This makes the debug cycle much shorter and less cumbersome.
The traditional way to provide an object that guarantees that it is an instance of typeclass Foo
, but makes no additional guarantees, is like so:
{-# LANGUAGE ExistentialTypes #-}
data SomeFoo = forall a . Foo a => SomeFoo a
instance Foo SomeFoo where
-- all operations just unwrap the SomeFoo straightforwardly
or, with GADTs, which might be more readable...
data SomeFoo where
SomeFoo :: Foo a => a -> SomeFoo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With