Subtype polymorphism in Haskell

后端 未结 3 2019
不思量自难忘°
不思量自难忘° 2021-01-31 15:56

Building a hierarchy of GUI widget classes is pretty much a standard exercise in object-oriented programming. You have some sort of abstract Widget class, with an a

3条回答
  •  攒了一身酷
    2021-01-31 16:38

    The wxHaskell GUI library makes excellent use of phantom types to model a widget hierarchy.

    The idea is the following: all widgets share the same implementation, namely they are foreign pointers to C++ objects. However, this doesn't mean that all widgets need to have the same type. Instead, we can build a hierarchy like this:

    type Object a = ForeignPtr a
    
    data CWindow a
    data CControl a
    data CButton a
    
    type Window  a = Object  (CWindow a)
    type Control a = Window  (CControl a)
    type Button  a = Control (CButton a)
    

    This way, a value of the type Control A also matches the type Window b, so you can use controls as windows, but not the other way round. As you can see, subtyping is implemented via a nested type parameter.

    For more on this technique, see section 5 in Dan Leijen's paper on wxHaskell.


    Note that this technique appears to be limited to the case where the actual representation of widgets is uniform, i.e. always the same. However, I am confident that with some thought, it can be extended to the case where widgets have different representations.

    In particular, the observation is that object-orientation can be modeled by including the methods in the data type, like this

    data CWindow a = CWindow
        { close   :: IO ()
        , ...
        }
    data CButton a = CButton
        { onClick :: (Mouse -> IO ()) -> IO ()
        , ...
        }
    

    Subtyping may save some boilerplate here, but it's not required.

提交回复
热议问题