class Listy a b where
fromList :: [b] -> a
toList :: a -> [b]
lifted :: ([b] -> [b]) -> (a -> a)
lifted f = fromList . f . toList
data MyString = MyString { getString :: String } deriving Show
instance Listy MyString Char where
toList = getString
fromList = MyString
Now I need to write e.g. lifted (reverse::(String -> String)) (MyString "Foobar")
. Is there a trick to avoid the need for the type signatures?
Essentially the problem is that setting the type of a
does not tell the compiler what the type of b
is. You might think that since there is only one instance of the class (where a
is MyString
and b
is Char
), but anybody can add new instances at any time. So the fact that there's only one instance now doesn't help the compiler decide what types you want.
The solution to this is either to use Functional Dependencies, or Type Families. The latter is the newer solution and is intended to eventually "replace" the former, but right now both are still fully supported. Whether FDs ever go away remains to be seen. Anyway, with FDs:
class Listy a b | a -> b where ...
Essentially this says "there can only ever be one class instance for each a
". In other words, once you know a
, you can always determine b
. (But not the reverse.) The rest of the class looks like it did before.
The alternative is TFs:
class Listy a where
type Element a :: *
...
instance Listy MyString where
type Element MyString = Char
...
Now instead of the second type being called b
, it's called Element a
. The word Element
acts like a class method that takes a listy type and returns the corresponding element type. You can then do
instance Listy ByteString where
type Element ByteString = Word8
...
instance Listy [x] where
type Element [x] = x
...
instance Ord x => Listy (Set x) where
type Element (Set x) = x
...
and so on. (Not that Listy
necessarily makes sense for all the types above; these are just examples of how to define the class.)
You can try -XFunctionalDependencies
class Listy a b | a -> b where
fromList :: [b] -> a
toList :: a -> [b]
lifted :: ([b] -> [b]) -> (a -> a)
lifted f = fromList . f . toList
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