haskell polymorphism and lists

后端 未结 6 1001
温柔的废话
温柔的废话 2021-02-02 13:45

Suppose I have the following:

class Shape a where
    draw a :: a -> IO ()

data Rectangle = Rectangle Int Int

instance Shape Rectangle where
    draw (Recta         


        
6条回答
  •  情歌与酒
    2021-02-02 14:42

    As Ganesh said, you could indeed use GADTs to have more type safety. But if you don't want (or need) to, here's my take on this:

    As you already know, all elements of a list need to be of the same type. It isn't very useful to have a list of elements of different types, because then your throwing away your type information.

    In this case however, since you want throw away type information (you're just interested in the drawable part of the value), you would suggest to change the type of your values to something that is just drawable.

    type Drawable = IO ()
    
    shapes :: [Drawable]
    shapes = [draw (Circle 5 10), draw (Circle 20 30), draw (Rectangle 10 15)]
    

    Presumably, your actual Drawable will be something more interesting than just IO () (maybe something like: MaxWidth -> IO ()).

    And also, due to lazy evaluation, the actual value won't be drawn until you force the list with something like sequence_. So you don't have to worry about side effects (but you probably already saw that from the type of shapes).


    Just to be complete (and incorporate my comment into this answer): This is a more general implementation, useful if Shape has more functions:

    type MaxWith = Int
    
    class Shape a where
        draw :: a -> MaxWidth -> IO ()
        size :: a -> Int
    
    type ShapeResult = (MaxWidth -> IO (), Int)
    
    shape :: (Shape a) => a -> ShapeResult
    shape x = (draw x, size x)
    
    shapes :: [ShapeResult]
    shapes = [shape (Circle 5 10), shape (Circle 20 30), shape (Rectangle 10 15)]
    

    Here, the shape function transforms a Shape a value into a ShapeResult value, by simply calling all the functions in the Shape class. Due to laziness, none of the values are actually computed until you need them.

    To be honest, I don't think I would actually use a construct like this. I would either use the Drawable-method from above, or if a more general solution is needed, use GADTs. That being said, this is a fun exercise.

提交回复
热议问题