Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type equality function

Tags:

haskell

Is there a way to define a function like so:

f :: (C a, C b) => a -> Maybe b

Such that:

f = Just

when type a = b, and

f _ = Nothing

when type a /= b?

Note that:

  • I don't want to use overlapping instances.
  • I'd prefer not to have a class constraint C, but I'm pretty sure it's necessary (particularly if I want to avoid overlapping instances).
  • I want to define only a single instance for each type I want to compare in this scheme, defining a class Equal a b makes this problem trivial but it then requires n^2 instances which I want to avoid.
like image 465
Clinton Avatar asked Jun 20 '17 07:06

Clinton


Video Answer


1 Answers

Just this

http://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Typeable.html#v:cast

cast :: (Typeable a, Typeable b) => a -> Maybe b

Example of use

Function cast can be a part of "type casting system like object-oriented languages". Bacteria and Fungus are Life. They can be upcasted to Life. And Life may be able to downcast to Bacteria or Fungus.

{-# LANGUAGE ExistentialQuantification, DeriveDataTypeable #-}

import Data.Typeable
import Data.Maybe

data SomeLife = forall l . Life l => SomeLife l
        deriving Typeable

instance Show SomeLife where
        show (SomeLife l) = "SomeLife " ++ show l

class (Typeable l, Show l) => Life l where
        toLife :: l -> SomeLife
        fromLife :: SomeLife -> Maybe l

        toLife = SomeLife
        fromLife (SomeLife l) = cast l

instance Life SomeLife where
        toLife = id
        fromLife = Just

data Bacteria = Bacteria deriving (Typeable, Show)

instance Life Bacteria

data Fungus = Fungus deriving (Typeable, Show)

instance Life Fungus

castLife :: (Life l1, Life l2) => l1 -> Maybe l2
castLife = fromLife . toLife

filterLife :: (Life l1, Life l2) => [l1] -> [l2]
filterLife = catMaybes . map castLife

withLifeIO :: (Life l1, Life l2) => l1 -> (l2 -> IO ()) -> IO ()
withLifeIO l f = maybe (return ()) f $ castLife l

withYourFavoriteLife :: Life l => (l -> IO ()) -> IO ()
withYourFavoriteLife act = do
        withLifeIO Bacteria act
        withLifeIO Fungus act

main :: IO ()
main = do
        let     sls :: Life l => [l]
                sls = filterLife [
                        SomeLife Bacteria,
                        SomeLife Fungus,
                        SomeLife Fungus ]
        print (sls :: [SomeLife])
        print (sls :: [Bacteria])
        print (sls :: [Fungus])
        withYourFavoriteLife (print :: SomeLife -> IO ())
        withYourFavoriteLife (print :: Bacteria -> IO ())
        withYourFavoriteLife (print :: Fungus -> IO ())

This technic extend to type hierarchy system. Whole Life module is here. https://github.com/YoshikuniJujo/test_haskell/blob/master/features/existential_quantifications/type_hierarchy/Life.hs

Exception system use this technic. https://hackage.haskell.org/package/base-4.9.1.0/docs/Control-Exception.html

like image 94
YoshikuniJujo Avatar answered Oct 15 '22 00:10

YoshikuniJujo