How to model mixins / multiple interfaces in Haskell?

后端 未结 5 1684
闹比i
闹比i 2021-02-08 11:31

I came across this question on modeling inheritance in Haskell and it reminded me that I have a little more complicated version of the same problem. I\'ll adopt the example from

5条回答
  •  傲寒
    傲寒 (楼主)
    2021-02-08 11:59

    Though I still suspect we should think about the whole think about the whole thing another way, less OO-inspired, here's another possible solution. I shall keep to the Monsters example, though a 2D graphics program seems indeed a better example.

    {-# LANGUAGE TypeFamilies, MultiParamTypeClasses, DeriveFunctor, FlexibleContexts #-}
    
    import Control.Monad.Identity
    
    class (Functor f, Functor (PropT f p)) => AttachProp f p where
      type PropT f p :: * -> *
      attachProp :: p -> f o -> PropT f p o
      detachProp :: PropT f p o -> (p, f o)
    
    fmapProp :: (AttachProp f p, AttachProp f p')
      => f o -- dummy parameter (unevaluated), because type-functions aren't injective
             -> (p -> p') -> PropT f p o -> PropT f p' o
    fmapProp q f pt = let (p, fo) = detachProp pt
                      in attachProp (f p) $ fo `asTypeOf` q
    
    
    data R3Phys = R3Phys { position, momentum :: Vec3 }
    data Colour = Colour
    
    data Physical a = Physical R3Phys a deriving (Functor)
    data Coloured a = Coloured Colour a deriving (Functor)
    data PhysColoured a = PhysColoured Colour R3Phys a deriving (Functor)
    
    instance AttachProp Identity R3Phys where
      type PropT Identity R3Phys = Physical
      attachProp rp = Physical rp . runIdentity
      detachProp (Physical rp o) = (rp, Identity o)
    instance AttachProp Identity Colour where
      type PropT Identity Colour = Coloured
      attachProp c = Coloured c . runIdentity
      detachProp (Coloured c o) = (c, Identity o)
    instance AttachProp Coloured R3Phys where
      type PropT Coloured R3Phys = PhysColoured
      attachProp rp (Coloured c o) = PhysColoured c rp o
      detachProp (PhysColoured c rp o) = (rp, Coloured c o)
    instance AttachProp Physical Colour where
      type PropT Physical Colour = PhysColoured
      attachProp c (Physical rp o) = PhysColoured c rp o
      detachProp (PhysColoured c rp o) = (c, Physical rp o)
    

    Note that PropT (PropT Identity R3Phys) Colour a and PropT (PropT Identity Colour) R3Phys a are the same type, namely PhysColoured a. Of course, we need again O () instances for n mixins. Could easily be done with Template Haskell, though obviously you should think twice if you want that.

提交回复
热议问题