I'm new to Haskell and just playing around awhile.
I have written a lightweight OOP simulation:
--OOP.hs
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances, ScopedTypeVariables, FunctionalDependencies #-}
module OOP where
class Provides obj iface where
provide::obj->iface
(#>)::obj->(iface->a)->a
o #> meth = meth $ provide o
class Instance cls obj | obj -> cls where
classOf::obj->cls
class Implements cls iface where
implement::(Instance cls obj)=>cls->obj->iface
instance (Instance cls obj, Implements cls iface)=>Provides obj iface where
provide x = implement (classOf x::cls) x
using it like:
--main.hs
{-# LANGUAGE MultiParamTypeClasses #-}
import OOP
data I1 = I1
getI1::I1->String
getI1 i1 = "Interface 1"
data I2 = I2
getI2::I2->String
getI2 i2 = "Interface 2"
data C = C
instance Implements C I1 where
implement C o = I1
instance Implements C I2 where
implement C o = I2
data O = O
instance Instance C O where
classOf o = C
main = do
putStrLn (O #> getI1)
putStrLn (O #> getI2)
I read that UndecidableInstances
feature is pretty inconvenient and can lead to stack overflows in the compiler. So I have two questions.
1 to N
relations between instance and class data types as well as between interface and class?Your use of undecidable instances in this case is fine.
instance (Instance cls obj, Implements cls iface)=>Provides obj iface where
is undecidable because you might have an instance for Instance
or Implements
that in turn relies on Provides
causing a loop.
However, in this case, you don't need the Provides
class at all, because you only give an implementation of it in terms of methods from your other two classes!
You could instead pull provides
and #>
out to be top level functions with the appropriate Instance
and Implements
constraints and you would lose nothing, and avoid the need for the undecidable instance.
You do need/want MPTCs for this however, and that's fine...
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