How to improve below code?

Hi all, I have below source code, i use Dynamic for `pageBuffer`. In implement of function `pageClone`, after `case pt of`, i need write like this, and this code looks ugly, if `PageTyep` have 100 type, i need write those ugly code 100 times. case pt of TStringBuffer -> pageBufferClone (x :: StringBuffer) TImageBuffer -> pageBufferClone (x :: ImageBuffer) TVideoBuffer -> pageBufferClone (x :: TVideoBuffer) TMixBuffer -> pageBufferClone (x :: TMixBuffer) So have a better solution to avoid write above ugly code? Someone suggestion me use GADTs instead, but i don't know how to write correct GADTs code replace current version, if GADTs is best way, someone can explain it detail? It's better if someone give me demo code. ------------------------------> Source Code start <------------------------------ data PageType = TStringBuffer | TImageBuffer | TVideoBuffer | TMixBuffer deriving (Eq, Show, Read) data Page = Page {pageName :: IORef String ,pageId :: Int ,pageType :: PageType ,pageBuffer :: Dynamic ,pageBox :: VBox } class PageBuffer a where pageBufferClone :: a -> IO (Dynamic, VBox) -- | Page clone interface. pageClone :: Page -> IO Page pageClone page = do -- Get common information for clone page. name <- pageGetName page let id = pageId page pt = pageType page pb = pageBuffer page -- Get clone information for dynamic interface. (pBuffer, pBox) <- case fromDynamic pb of Just x -> case pt of TStringBuffer -> pageBufferClone (x :: StringBuffer) TImageBuffer -> pageBufferClone (x :: ImageBuffer) TVideoBuffer -> pageBufferClone (x :: TVideoBuffer) TMixBuffer -> pageBufferClone (x :: TMixBuffer) Nothing -> pageCloneEmpty -- Return clone page. pageNewInternal name id pt pBuffer pBox ------------------------------> Source Code end <------------------------------ Thanks! -- Andy

Andy Stewart wrote:
So have a better solution to avoid write above ugly code How about:
==== data Page a = Page {pageName :: IORef String ,pageId :: Int ,pageBuffer :: a ,pageBox :: VBox } class PageBuffer a where pageBufferClone :: a -> IO (a, VBox) pageClone :: PageBuffer a => Page a -> IO (Page a) pageClone page = do -- Get common information for clone page. name <- pageGetName page let id = pageId page pb = pageBuffer page -- Get clone information for dynamic interface. (pBuffer, pBox) <- pageBufferClone pb -- Return clone page. pageNewInternal name id pBuffer pBox ==== I'm not totally sure if that will work without seeing the rest of your code. But it seems neater, and no GADTs in sight. If you need to store Page StringBuffer in a list with Page ImageBuffer you will have a problem, so perhaps you could spell out what else you need to do with these Page items in your application? Thanks, Neil.

On Tue, Jun 9, 2009 at 7:21 AM, Neil Brown
data Page a = Page {pageName :: IORef String ,pageId :: Int ,pageBuffer :: a ,pageBox :: VBox }
class PageBuffer a where pageBufferClone :: a -> IO (a, VBox)
pageClone :: PageBuffer a => Page a -> IO (Page a) pageClone page = do -- Get common information for clone page. name <- pageGetName page let id = pageId page pb = pageBuffer page
-- Get clone information for dynamic interface. (pBuffer, pBox) <- pageBufferClone pb
-- Return clone page. pageNewInternal name id pBuffer pBox
Actually you can avoid the type parameter on "a" using an existential:
{-# LANGUAGE ExistentialQuantification #-} data Page = forall a. PageBuffer a => Page {pageName :: IORef String ,pageId :: Int ,pageBuffer :: a ,pageBox :: VBox }
Now you can still use [Page]. You can't do "pageBuffer p", though, you'll get this fun error message: Cannot use record selector `pageBuffer' as a function due to escaped type variables Probable fix: use pattern-matching syntax instead Instead you need to do case p of Page{pageBuffer = x} -> ...something with x... This will bring the PageBuffer context into scope, inside of the case statement. -- ryan
participants (3)
-
Andy Stewart
-
Neil Brown
-
Ryan Ingram