Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Closed type families and strange function types

Sorry, I couldn't imagine any better title for the question, so please read ahead. Imagine that we have a closed type family that maps every type to it's corresponding Maybe except maybes themselves:

type family Family x where
  Family (Maybe x) = Maybe x
  Family x = Maybe x

We can even declare a function using that type family:

doMagic :: a -> Family a
doMagic = undefined

exampleA = doMagic $ Just ()
exampleB = doMagic $ ()

Playing with it in GHCi shows that it is ok to evaluate the type of this function application:

*Strange> :t exampleA      
exampleA :: Maybe ()       
*Strange> :t exampleB      
exampleB :: Maybe ()       

The question is if it is possible to provide any implementation of the doMagic function except undefined? Let's for example say that I would like to wrap every value into a Just constructor, except Maybes which should remain intact, how could I do that? I tried using typeclasses, but failed to write a compileable signature for doMagic function if not using closed type families, could somebody please help me?

like image 490
Anton Avatar asked Oct 29 '14 22:10

Anton


1 Answers

You can use another closed type family to distinguish Maybe x from x and then you can use another typeclass to provide separate implementations of doMagic for these two cases. Quick and dirty version:

{-# LANGUAGE TypeFamilies, MultiParamTypeClasses,
    FlexibleInstances, UndecidableInstances, ScopedTypeVariables #-}

type family Family x where
  Family (Maybe x) = Maybe x
  Family x = Maybe x

data True
data False

type family IsMaybe x where
  IsMaybe (Maybe x) = True
  IsMaybe x = False


class DoMagic a where
  doMagic :: a -> Family a

instance (DoMagic' (IsMaybe a) a (Family a)) => DoMagic a where
  doMagic = doMagic' (undefined :: IsMaybe a)   


class DoMagic' i a r where
  doMagic' :: i -> a -> r

instance DoMagic' True (Maybe a) (Maybe a) where
  doMagic' _ = id

instance DoMagic' False a (Maybe a) where
  doMagic' _ = Just


exampleA = doMagic $ Just ()
exampleB = doMagic $ ()
like image 84
Ed'ka Avatar answered Oct 15 '22 06:10

Ed'ka