Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell MultiParamTypeClasses and UndecidableInstances

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. Could this code be improved, preserving ease of use and 1 to N relations between instance and class data types as well as between interface and class?
  2. Could be the similar logic implemented with Single Param Type Classes?
like image 920
Odomontois Avatar asked Nov 10 '22 14:11

Odomontois


1 Answers

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...

like image 183
sclv Avatar answered Nov 15 '22 07:11

sclv