From: John L. <jw...@gm...> - 2009-08-24 16:15:25
|
Hello, For this, I don't think you'd need existentials. First of all, I would use different names for the GridWidget constructors since Label and TextView are already used by gtk. data GridWidget = GwLabel | GwTextView and I'd probably derive Eq, Read, and Enum as well. Next point, you can't have gridWidgetNew return a polymorphic type like this. See http://www.haskell.org/haskellwiki/OOP_vs_type_classes for more detail. Even if you use existential types, you'll still need to wrap it in another constructor. If you don't need the child other than simply adding it to the parent widget, I would use the following function: addGridWidget :: ContainerClass c => c -> GridWidget -> IO c addGridWidget self GwLabel = do child <- labelNew Nothing set self [ containerChild := child ] return self addGridWidget self GwTextView = do child <- textViewNew set self [ containerChild := child ] return self This will work without existential types because the type of the child widget doesn't escape the function. Cheers, John > From: Magicloud Magiclouds <mag...@gm...> > > I have read the wiki, and I think gtk2hs's way is enough for me. > The other part of my code would be like this: > > myWidgetNew gridWidget = do > self <- someWidgetNew > child <- gridWidgetNew gridWidget > set self [ containerChild := child ] > return self > > Well, it failed compiling on gridWidgetNew definition. > > On Mon, Aug 24, 2009 at 8:19 PM, Bulat > Ziganshin<bul...@gm...> wrote: >> Hello Magicloud, >> >> Monday, August 24, 2009, 1:39:48 PM, you wrote: >> >>> ? My total purpose is to create a widget with an argument that what >>> child widget the user wants to have. So I pass GridWidget to the >>> widget init function, and it calls gridWidgetNew to see what new >>> function it actually has to call. >> >> this depends on how you plan to use the widget later. Haskell provides >> existential types for such things, but Gtk2Hs own mechanisms may be >> also useful >> >> read about existentials here: http://haskell.org/haskellwiki/OOP_vs_type_classes >> |
From: Magicloud M. <mag...@gm...> - 2009-08-25 02:02:31
|
I thought about this before, in another case, but still, I cannot belive I should do it this ugly.... On Tue, Aug 25, 2009 at 12:15 AM, John Lato<jw...@gm...> wrote: > Hello, > > For this, I don't think you'd need existentials. First of all, I > would use different names for the GridWidget constructors since Label > and TextView are already used by gtk. > > data GridWidget = GwLabel > | GwTextView > > and I'd probably derive Eq, Read, and Enum as well. > > Next point, you can't have gridWidgetNew return a polymorphic type > like this. See http://www.haskell.org/haskellwiki/OOP_vs_type_classes > for more detail. Even if you use existential types, you'll still need > to wrap it in another constructor. If you don't need the child other > than simply adding it to the parent widget, I would use the following > function: > > addGridWidget :: ContainerClass c => c -> GridWidget -> IO c > addGridWidget self GwLabel = do > child <- labelNew Nothing > set self [ containerChild := child ] > return self > addGridWidget self GwTextView = do > child <- textViewNew > set self [ containerChild := child ] > return self > > This will work without existential types because the type of the child > widget doesn't escape the function. > > Cheers, > John > >> From: Magicloud Magiclouds <mag...@gm...> >> >> I have read the wiki, and I think gtk2hs's way is enough for me. >> The other part of my code would be like this: >> >> myWidgetNew gridWidget = do >> self <- someWidgetNew >> child <- gridWidgetNew gridWidget >> set self [ containerChild := child ] >> return self >> >> Well, it failed compiling on gridWidgetNew definition. >> >> On Mon, Aug 24, 2009 at 8:19 PM, Bulat >> Ziganshin<bul...@gm...> wrote: >>> Hello Magicloud, >>> >>> Monday, August 24, 2009, 1:39:48 PM, you wrote: >>> >>>> ? My total purpose is to create a widget with an argument that what >>>> child widget the user wants to have. So I pass GridWidget to the >>>> widget init function, and it calls gridWidgetNew to see what new >>>> function it actually has to call. >>> >>> this depends on how you plan to use the widget later. Haskell provides >>> existential types for such things, but Gtk2Hs own mechanisms may be >>> also useful >>> >>> read about existentials here: http://haskell.org/haskellwiki/OOP_vs_type_classes >>> > -- 竹密岂妨流水过 山高哪阻野云飞 |
From: John L. <jw...@gm...> - 2009-08-25 06:21:26
|
What do you find ugly about it? I think it's pretty elegant myself. Anyway, there is a third option, that isn't quite full existential types. data GridWidget = GwLabel Label | GwTextView TextView gridWidgetNew :: String -> IO GridWidget gridWidgetNew str = case str of "GwLabel" -> liftM GwLabel $ labelNew Nothing "GwTextView" -> liftM GwTextView textViewNew _ -> error "Invalid GridWidget" Rather than matching on strings, you could use another type to represent the names and pattern match on that. John On Mon, Aug 24, 2009 at 9:02 PM, Magicloud Magiclouds<mag...@gm...> wrote: > I thought about this before, in another case, but still, I cannot > belive I should do it this ugly.... > > On Tue, Aug 25, 2009 at 12:15 AM, John Lato<jw...@gm...> wrote: >> Hello, >> >> For this, I don't think you'd need existentials. First of all, I >> would use different names for the GridWidget constructors since Label >> and TextView are already used by gtk. >> >> data GridWidget = GwLabel >> | GwTextView >> >> and I'd probably derive Eq, Read, and Enum as well. >> >> Next point, you can't have gridWidgetNew return a polymorphic type >> like this. See http://www.haskell.org/haskellwiki/OOP_vs_type_classes >> for more detail. Even if you use existential types, you'll still need >> to wrap it in another constructor. If you don't need the child other >> than simply adding it to the parent widget, I would use the following >> function: >> >> addGridWidget :: ContainerClass c => c -> GridWidget -> IO c >> addGridWidget self GwLabel = do >> child <- labelNew Nothing >> set self [ containerChild := child ] >> return self >> addGridWidget self GwTextView = do >> child <- textViewNew >> set self [ containerChild := child ] >> return self >> >> This will work without existential types because the type of the child >> widget doesn't escape the function. >> >> Cheers, >> John >> >>> From: Magicloud Magiclouds <mag...@gm...> >>> >>> I have read the wiki, and I think gtk2hs's way is enough for me. >>> The other part of my code would be like this: >>> >>> myWidgetNew gridWidget = do >>> self <- someWidgetNew >>> child <- gridWidgetNew gridWidget >>> set self [ containerChild := child ] >>> return self >>> >>> Well, it failed compiling on gridWidgetNew definition. >>> >>> On Mon, Aug 24, 2009 at 8:19 PM, Bulat >>> Ziganshin<bul...@gm...> wrote: >>>> Hello Magicloud, >>>> >>>> Monday, August 24, 2009, 1:39:48 PM, you wrote: >>>> >>>>> ? My total purpose is to create a widget with an argument that what >>>>> child widget the user wants to have. So I pass GridWidget to the >>>>> widget init function, and it calls gridWidgetNew to see what new >>>>> function it actually has to call. >>>> >>>> this depends on how you plan to use the widget later. Haskell provides >>>> existential types for such things, but Gtk2Hs own mechanisms may be >>>> also useful >>>> >>>> read about existentials here: http://haskell.org/haskellwiki/OOP_vs_type_classes >>>> >> > > > > -- > 竹密岂妨流水过 > 山高哪阻野云飞 > |
From: Magicloud M. <mag...@gm...> - 2009-08-25 06:53:44
|
This is better. 8-) The last one, the reason I say it is ugly, because it has too much duplicated code. 2009/8/25 John Lato <jw...@gm...>: > What do you find ugly about it? I think it's pretty elegant myself. > Anyway, there is a third option, that isn't quite full existential > types. > > data GridWidget = GwLabel Label > | GwTextView TextView > > gridWidgetNew :: String -> IO GridWidget > gridWidgetNew str = case str of > "GwLabel" -> liftM GwLabel $ labelNew Nothing > "GwTextView" -> liftM GwTextView textViewNew > _ -> error "Invalid GridWidget" > > Rather than matching on strings, you could use another type to > represent the names and pattern match on that. > John > > On Mon, Aug 24, 2009 at 9:02 PM, Magicloud > Magiclouds<mag...@gm...> wrote: >> I thought about this before, in another case, but still, I cannot >> belive I should do it this ugly.... >> >> On Tue, Aug 25, 2009 at 12:15 AM, John Lato<jw...@gm...> wrote: >>> Hello, >>> >>> For this, I don't think you'd need existentials. First of all, I >>> would use different names for the GridWidget constructors since Label >>> and TextView are already used by gtk. >>> >>> data GridWidget = GwLabel >>> | GwTextView >>> >>> and I'd probably derive Eq, Read, and Enum as well. >>> >>> Next point, you can't have gridWidgetNew return a polymorphic type >>> like this. See http://www.haskell.org/haskellwiki/OOP_vs_type_classes >>> for more detail. Even if you use existential types, you'll still need >>> to wrap it in another constructor. If you don't need the child other >>> than simply adding it to the parent widget, I would use the following >>> function: >>> >>> addGridWidget :: ContainerClass c => c -> GridWidget -> IO c >>> addGridWidget self GwLabel = do >>> child <- labelNew Nothing >>> set self [ containerChild := child ] >>> return self >>> addGridWidget self GwTextView = do >>> child <- textViewNew >>> set self [ containerChild := child ] >>> return self >>> >>> This will work without existential types because the type of the child >>> widget doesn't escape the function. >>> >>> Cheers, >>> John >>> >>>> From: Magicloud Magiclouds <mag...@gm...> >>>> >>>> I have read the wiki, and I think gtk2hs's way is enough for me. >>>> The other part of my code would be like this: >>>> >>>> myWidgetNew gridWidget = do >>>> self <- someWidgetNew >>>> child <- gridWidgetNew gridWidget >>>> set self [ containerChild := child ] >>>> return self >>>> >>>> Well, it failed compiling on gridWidgetNew definition. >>>> >>>> On Mon, Aug 24, 2009 at 8:19 PM, Bulat >>>> Ziganshin<bul...@gm...> wrote: >>>>> Hello Magicloud, >>>>> >>>>> Monday, August 24, 2009, 1:39:48 PM, you wrote: >>>>> >>>>>> ? My total purpose is to create a widget with an argument that what >>>>>> child widget the user wants to have. So I pass GridWidget to the >>>>>> widget init function, and it calls gridWidgetNew to see what new >>>>>> function it actually has to call. >>>>> >>>>> this depends on how you plan to use the widget later. Haskell provides >>>>> existential types for such things, but Gtk2Hs own mechanisms may be >>>>> also useful >>>>> >>>>> read about existentials here: http://haskell.org/haskellwiki/OOP_vs_type_classes >>>>> >>> >> >> >> >> -- >> 竹密岂妨流水过 >> 山高哪阻野云飞 >> > -- 竹密岂妨流水过 山高哪阻野云飞 |
From: John L. <jw...@gm...> - 2009-08-25 12:35:57
|
This version will end up with more duplicated code than the other if you do any pattern matching on GridWidget. That's why I didn't mention it from the beginning. Using a real existential type will give you no duplicated code, but with the cost that you completely lose the type information (and possibly portability to other Haskell compilers). You can remove the duplicate code from the first version, but it's slightly less clear IMO: -- N.B. this uses the first definition of GridWidget, where it is solely an enum of acceptable types. addGridWidget :: ContainerClass c => c -> GridWidget -> IO c addGridWidget self gw = case gw of GwLabel -> labelNew Nothing >>= addChild GwTextView -> textViewNew >>= addChild where addChild child = set self [ containerChild := child ] >> return self That's 6 lines compared to 9, with all duplicated code wrapped up in the addChild function. You need to use a case rather than pattern matching on the LHS in order to share the addChild bound in the where clause. You also may need to add an explicit polymorphic type to addChild, but I'm pretty sure that GHC will infer it in this case. BTW if you later decide you need a string for the initial value of the label, you can just throw it in the GridWidget type as a parameter after the GwLabel constructor. John On Tue, Aug 25, 2009 at 7:47 AM, Magicloud Magiclouds<mag...@gm...> wrote: > This is better. 8-) > The last one, the reason I say it is ugly, because it has too much > duplicated code. > > 2009/8/25 John Lato <jw...@gm...>: >> What do you find ugly about it? I think it's pretty elegant myself. >> Anyway, there is a third option, that isn't quite full existential >> types. >> >> data GridWidget = GwLabel Label >> | GwTextView TextView >> >> gridWidgetNew :: String -> IO GridWidget >> gridWidgetNew str = case str of >> "GwLabel" -> liftM GwLabel $ labelNew Nothing >> "GwTextView" -> liftM GwTextView textViewNew >> _ -> error "Invalid GridWidget" >> >> Rather than matching on strings, you could use another type to >> represent the names and pattern match on that. >> John >> >> On Mon, Aug 24, 2009 at 9:02 PM, Magicloud >> Magiclouds<mag...@gm...> wrote: >>> I thought about this before, in another case, but still, I cannot >>> belive I should do it this ugly.... >>> >>> On Tue, Aug 25, 2009 at 12:15 AM, John Lato<jw...@gm...> wrote: >>>> Hello, >>>> >>>> For this, I don't think you'd need existentials. First of all, I >>>> would use different names for the GridWidget constructors since Label >>>> and TextView are already used by gtk. >>>> >>>> data GridWidget = GwLabel >>>> | GwTextView >>>> >>>> and I'd probably derive Eq, Read, and Enum as well. >>>> >>>> Next point, you can't have gridWidgetNew return a polymorphic type >>>> like this. See http://www.haskell.org/haskellwiki/OOP_vs_type_classes >>>> for more detail. Even if you use existential types, you'll still need >>>> to wrap it in another constructor. If you don't need the child other >>>> than simply adding it to the parent widget, I would use the following >>>> function: >>>> >>>> addGridWidget :: ContainerClass c => c -> GridWidget -> IO c >>>> addGridWidget self GwLabel = do >>>> child <- labelNew Nothing >>>> set self [ containerChild := child ] >>>> return self >>>> addGridWidget self GwTextView = do >>>> child <- textViewNew >>>> set self [ containerChild := child ] >>>> return self >>>> >>>> This will work without existential types because the type of the child >>>> widget doesn't escape the function. >>>> >>>> Cheers, >>>> John >>>> >>>>> From: Magicloud Magiclouds <mag...@gm...> >>>>> >>>>> I have read the wiki, and I think gtk2hs's way is enough for me. >>>>> The other part of my code would be like this: >>>>> >>>>> myWidgetNew gridWidget = do >>>>> self <- someWidgetNew >>>>> child <- gridWidgetNew gridWidget >>>>> set self [ containerChild := child ] >>>>> return self >>>>> >>>>> Well, it failed compiling on gridWidgetNew definition. >>>>> >>>>> On Mon, Aug 24, 2009 at 8:19 PM, Bulat >>>>> Ziganshin<bul...@gm...> wrote: >>>>>> Hello Magicloud, >>>>>> >>>>>> Monday, August 24, 2009, 1:39:48 PM, you wrote: >>>>>> >>>>>>> ? My total purpose is to create a widget with an argument that what >>>>>>> child widget the user wants to have. So I pass GridWidget to the >>>>>>> widget init function, and it calls gridWidgetNew to see what new >>>>>>> function it actually has to call. >>>>>> >>>>>> this depends on how you plan to use the widget later. Haskell provides >>>>>> existential types for such things, but Gtk2Hs own mechanisms may be >>>>>> also useful >>>>>> >>>>>> read about existentials here: http://haskell.org/haskellwiki/OOP_vs_type_classes >>>>>> >>>> >>> >>> >>> >>> -- >>> 竹密岂妨流水过 >>> 山高哪阻野云飞 >>> >> > > > > -- > 竹密岂妨流水过 > 山高哪阻野云飞 > |
From: Magicloud M. <mag...@gm...> - 2009-08-26 08:40:04
|
But if the thing is not as simple as just adding a widget, for example, adding ten widgets of the same type. Then the way of making a wraper (your second way) would be simpler than the others, I think. 8-) 2009/8/25 John Lato <jw...@gm...>: > This version will end up with more duplicated code than the other if > you do any pattern matching on GridWidget. That's why I didn't > mention it from the beginning. > > Using a real existential type will give you no duplicated code, but > with the cost that you completely lose the type information (and > possibly portability to other Haskell compilers). > > You can remove the duplicate code from the first version, but it's > slightly less clear IMO: > > -- N.B. this uses the first definition of GridWidget, where it is > solely an enum of acceptable types. > addGridWidget :: ContainerClass c => c -> GridWidget -> IO c > addGridWidget self gw = case gw of > GwLabel -> labelNew Nothing >>= addChild > GwTextView -> textViewNew >>= addChild > where > addChild child = set self [ containerChild := child ] >> return self > > That's 6 lines compared to 9, with all duplicated code wrapped up in > the addChild function. You need to use a case rather than pattern > matching on the LHS in order to share the addChild bound in the where > clause. You also may need to add an explicit polymorphic type to > addChild, but I'm pretty sure that GHC will infer it in this case. > > BTW if you later decide you need a string for the initial value of the > label, you can just throw it in the GridWidget type as a parameter > after the GwLabel constructor. > > John > > On Tue, Aug 25, 2009 at 7:47 AM, Magicloud > Magiclouds<mag...@gm...> wrote: >> This is better. 8-) >> The last one, the reason I say it is ugly, because it has too much >> duplicated code. >> >> 2009/8/25 John Lato <jw...@gm...>: >>> What do you find ugly about it? I think it's pretty elegant myself. >>> Anyway, there is a third option, that isn't quite full existential >>> types. >>> >>> data GridWidget = GwLabel Label >>> | GwTextView TextView >>> >>> gridWidgetNew :: String -> IO GridWidget >>> gridWidgetNew str = case str of >>> "GwLabel" -> liftM GwLabel $ labelNew Nothing >>> "GwTextView" -> liftM GwTextView textViewNew >>> _ -> error "Invalid GridWidget" >>> >>> Rather than matching on strings, you could use another type to >>> represent the names and pattern match on that. >>> John >>> >>> On Mon, Aug 24, 2009 at 9:02 PM, Magicloud >>> Magiclouds<mag...@gm...> wrote: >>>> I thought about this before, in another case, but still, I cannot >>>> belive I should do it this ugly.... >>>> >>>> On Tue, Aug 25, 2009 at 12:15 AM, John Lato<jw...@gm...> wrote: >>>>> Hello, >>>>> >>>>> For this, I don't think you'd need existentials. First of all, I >>>>> would use different names for the GridWidget constructors since Label >>>>> and TextView are already used by gtk. >>>>> >>>>> data GridWidget = GwLabel >>>>> | GwTextView >>>>> >>>>> and I'd probably derive Eq, Read, and Enum as well. >>>>> >>>>> Next point, you can't have gridWidgetNew return a polymorphic type >>>>> like this. See http://www.haskell.org/haskellwiki/OOP_vs_type_classes >>>>> for more detail. Even if you use existential types, you'll still need >>>>> to wrap it in another constructor. If you don't need the child other >>>>> than simply adding it to the parent widget, I would use the following >>>>> function: >>>>> >>>>> addGridWidget :: ContainerClass c => c -> GridWidget -> IO c >>>>> addGridWidget self GwLabel = do >>>>> child <- labelNew Nothing >>>>> set self [ containerChild := child ] >>>>> return self >>>>> addGridWidget self GwTextView = do >>>>> child <- textViewNew >>>>> set self [ containerChild := child ] >>>>> return self >>>>> >>>>> This will work without existential types because the type of the child >>>>> widget doesn't escape the function. >>>>> >>>>> Cheers, >>>>> John >>>>> >>>>>> From: Magicloud Magiclouds <mag...@gm...> >>>>>> >>>>>> I have read the wiki, and I think gtk2hs's way is enough for me. >>>>>> The other part of my code would be like this: >>>>>> >>>>>> myWidgetNew gridWidget = do >>>>>> self <- someWidgetNew >>>>>> child <- gridWidgetNew gridWidget >>>>>> set self [ containerChild := child ] >>>>>> return self >>>>>> >>>>>> Well, it failed compiling on gridWidgetNew definition. >>>>>> >>>>>> On Mon, Aug 24, 2009 at 8:19 PM, Bulat >>>>>> Ziganshin<bul...@gm...> wrote: >>>>>>> Hello Magicloud, >>>>>>> >>>>>>> Monday, August 24, 2009, 1:39:48 PM, you wrote: >>>>>>> >>>>>>>> ? My total purpose is to create a widget with an argument that what >>>>>>>> child widget the user wants to have. So I pass GridWidget to the >>>>>>>> widget init function, and it calls gridWidgetNew to see what new >>>>>>>> function it actually has to call. >>>>>>> >>>>>>> this depends on how you plan to use the widget later. Haskell provides >>>>>>> existential types for such things, but Gtk2Hs own mechanisms may be >>>>>>> also useful >>>>>>> >>>>>>> read about existentials here: http://haskell.org/haskellwiki/OOP_vs_type_classes >>>>>>> >>>>> >>>> >>>> >>>> >>>> -- >>>> 竹密岂妨流水过 >>>> 山高哪阻野云飞 >>>> >>> >> >> >> >> -- >> 竹密岂妨流水过 >> 山高哪阻野云飞 >> > -- 竹密岂妨流水过 山高哪阻野云飞 |
From: John L. <jw...@gm...> - 2009-08-26 09:21:52
|
You're right, but with the wrapper data type pattern matching can lead to a code explosion. If you end up in that situation, you may want a helper function like one of the following (compare to 'either' and 'maybe'): withGridWidget :: WidgetClass w => GridWidget -> (w -> r) -> r withGridWidget2 :: GridWidget -> (Label -> r) -> (TextView -> r) -> r The definitions of these are simple enough, and this way you can completely abstract out pattern matching on GridWidget for minimal code duplication. This actually has one big advantage over existential types: the type of each particular GridWidget is still known, so you can easily do Label- and TextView-specific operations using the 'withGridWidget2' function. Cheers, John On Wed, Aug 26, 2009 at 9:39 AM, Magicloud Magiclouds<mag...@gm...> wrote: > But if the thing is not as simple as just adding a widget, for > example, adding ten widgets of the same type. > Then the way of making a wraper (your second way) would be simpler > than the others, I think. 8-) > |