Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Don't think the "Haskell's Overlooked Object System" paper has been posted to this thread yet: http://homepages.cwi.nl/~ralf/OOHaskell/paper.pdf --s On 12/18/07, Lutz Donnerhacke <[EMAIL PROTECTED]> wrote: > > * Tillmann Rendel wrote: > > My conclusion: To make Haskell a better OO language > > Haskell is not an OO language and never should be. > > > (Since it's not the goal of Haskell to be any OO language at all this > > may not be a problem) > > Ack. > ___ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe > ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
* Tillmann Rendel wrote: > My conclusion: To make Haskell a better OO language Haskell is not an OO language and never should be. > (Since it's not the goal of Haskell to be any OO language at all this > may not be a problem) Ack. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Felipe Lessa wrote: class Shape a where whatever class (Shape a, Shape b) => Intersectable a b where intersect :: a -> b -> Bool This looks nice at first sight, but is it usefull in practice? I can somehow express the type "any shape wich is intersectable with a given other shape", but it is a pain: data Intersectable a = forall b . Intersectable a b => Intersectable b instance Intersectable a (Intersectable b) where intersect a (Intersectable b) = intersect a b Now consider I write another binary function as a type class: class (Shape a, Shape b) => Containment a b where contains :: a -> b -> Bool data Containment a = forall b . Containment a b => Containment b instance Containment a (Containment b) where contains a (Containment b) = contains a b I cannot combine these types to express "any shape wich is intersectable and can be united with a given other shape" without writing another existiential wrapper. I cannot express "a list of pairwise intersectable shapes" either. Things get even worse if we consider a different definition of intersect: class (Shape a, Shape b, Shape c) => Intersect a b c | a b -> c where intersect :: a -> b -> c My conclusion: To make Haskell a better OO language then current OO languages, we need either first-class typeclasses (to quantify over the classes an existential wrapped value supports) or inference of existential wrappers (to infer complicated wrappers automatically). (Since it's not the goal of Haskell to be any OO language at all this may not be a problem) Tillmann ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
> If however, you *really* want to keep your shapes as being seperate > types, then you'll want to invoke the class system (note, not the same > as OO classes). > > class Shape a where >area :: a -> Int > > newtype Circle = C Int > > instance Shape Circle where >area (C r) = pi * r^2 > > newtype Rectangle = R Int Int > > instance Shape Rectangle where >area (R h w) = h * w > > newtype Square = Sq Int > > instance Shape Square where >area (Sq l) = l * l > > -- Now we can do something with our shapes > doubleArea :: Shape a => a -> Int > doubleArea s = (area s) * 2 Perhaps introduce an existensial quantification? data Shape = forall a. Sh a => Shape a class Sh a where area :: a -> Float data Circle = Circle Float instance Sh Circle area (Circle r) = pi*r*2 data Rect = Rect Float Float instance Sh Rect area (Rect h w) = h * w doubleArea :: Shape -> Float doubleArea (Shape x) = (area x) * 2 I think this is more in the traditional OOP sense. But this way or Tom's: one would have to convert functions like equality over Values of type Shape into equality over different types (Circle and Rect). This can be done using case analysis over the types with something like read. Kind regards, Chris. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Felipe Lessa wrote: On Dec 18, 2007 7:51 AM, Jules Bean <[EMAIL PROTECTED]> wrote: class Shape a where { intersect :: Shape b => a -> b -> Bool } Shouldn't this be class Shape a where whatever class (Shape a, Shape b) => Intersectable a b where intersect :: a -> b -> Bool With your definition I don't see how you could make it work, as you would have to write a function that takes care of this shape intersecting with any other shape, but this is exactly the problem the classes should solve! Yes, that's a better solution, certainly. MPTCs are not haskell though :P I'm half joking, but there are solutions which don't involve non-standard extensions even ones as popular as MPTCs. I didn't really think mine was particularly useful, just pointing out the design space, and in particular the precise parallel between the classes approach and the explicit dictionary approach. Jules ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
On Dec 18, 2007 7:51 AM, Jules Bean <[EMAIL PROTECTED]> wrote: > class Shape a where { >intersect :: Shape b => a -> b -> Bool > } Shouldn't this be class Shape a where whatever class (Shape a, Shape b) => Intersectable a b where intersect :: a -> b -> Bool With your definition I don't see how you could make it work, as you would have to write a function that takes care of this shape intersecting with any other shape, but this is exactly the problem the classes should solve! Cheers, -- Felipe. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Miguel Mitrofanov wrote: class Shape a where { intersect :: Shape b => a -> b -> Bool } data Shape a = { intersect :: Shape b => a -> b -> Bool } in fact, the syntax is rather similar, too! :) Um, well, and how are you going to implement it? Yes, exactly. My only point is There is no difference! There is no difference between the manual dictionary approach and the typeclass approach, in terms of ease of implementing a binary function. Each one has the same fundamental problem: binary functions are much easier with the ADT approach. Incidentally, my type sig was wrong, sorry: data Shape a = { intersect :: a -> Shape b -> Bool } Jules ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
> class Shape a where { >intersect :: Shape b => a -> b -> Bool > } > data Shape a = { intersect :: Shape b => a -> b -> Bool } > in fact, the syntax is rather similar, too! :) Um, well, and how are you going to implement it? ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Miguel Mitrofanov wrote: There's a third way, too, and I haven't seen anybody mention it yet I've noticed it, but there are some problems with this representation, so I decided not to mention it. It's OK as far as we don't want functions working on two areas - I don't see, how we can implement, say, intersect :: Shape -> Shape -> Bool in this way. However, it's a useful pattern. The problem is no better or worse for this third way than for type classes. class Shape a where { intersect :: Shape b => a -> b -> Bool } data Shape a = { intersect :: Shape b => a -> b -> Bool } in fact, the syntax is rather similar, too! :) Jules ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Miguel Mitrofanov <[EMAIL PROTECTED]> writes: > I've noticed it, but there are some problems with this > representation, so I decided not to mention it. It's OK as far as we > don't want functions working on two areas - I don't see, how we can > implement, say, intersect :: Shape -> Shape -> Bool in this way. > However, it's a useful pattern. Yes, there are different trade offs, it depends what you want to do. The AlgDT makes intersect simple: intersect :: Shape -> Shape -> Bool intersect (Circle x) (Circle y) = ... intersect (Circle x) (Rectangle x y) = ... : As Derek hints at, this isn't so nice in C++ and friends, you probably will end up with // Apologies for any mistakes in the code, it's been a while. class Circle : public Shape { : bool intersect(s){ if(dynamic_cast(s)){...} else if (dynamic_cast(s)){...} : } } etc. In addition to being very verbose and tedious code to write, you will have no idea if you have managed to cover all cases. Your 'intersect' function is spread all over the place. -k -- If I haven't seen further, it is by standing in the footprints of giants ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
On Mon, 2007-12-17 at 22:12 +0300, Miguel Mitrofanov wrote: > > There's a third way, too, and I haven't seen anybody mention it yet > > I've noticed it, but there are some problems with this > representation, so I decided not to mention it. It's OK as far as we > don't want functions working on two areas - I don't see, how we can > implement, say, intersect :: Shape -> Shape -> Bool in this way. > However, it's a useful pattern. And how do you do it in a "typical" OO language like Java or C# or Smalltalk? ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
> I interpreted Evan's question as "why can't you have newtypes with > multiple fields?" -- i.e., newtype X = X A B C -- and that's the > question I was answering. But maybe I misunderstood. Well, the question was both, and "strictness" answers both. Thanks for the clarification. I should have realized that of course (,) is an ADT just like all the rest. I guess that means that 'data X = X Y Z' is always preferable to 'newtype X = X (Y, Z)' since the latter is just like the former but with some extra typing. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
On 12/17/07, Wolfgang Jeltsch <[EMAIL PROTECTED]> wrote: > This is not a generalization of what you talked about. Why should the tuple > type be unboxed? Tuple types are boxed, meaning there is a difference > between _|_ and (_|_,…,_|_). If you write > > newtype X = X (A, B, C) > > then X doesn't add another level of indirection but the level of indirection > introduced by the tuple constructor remains, of course. So you could write > the above newtype declaration instead of > > data X = X A B C. > I interpreted Evan's question as "why can't you have newtypes with multiple fields?" -- i.e., newtype X = X A B C -- and that's the question I was answering. But maybe I misunderstood. Cheers, Tim -- Tim Chevalier * catamorphism.org * Often in error, never in doubt "After three days without programming, life becomes meaningless." -- James Geoffrey ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
There's a third way, too, and I haven't seen anybody mention it yet I've noticed it, but there are some problems with this representation, so I decided not to mention it. It's OK as far as we don't want functions working on two areas - I don't see, how we can implement, say, intersect :: Shape -> Shape -> Bool in this way. However, it's a useful pattern. (apologies if I just missed it). You can provide an explicit record of the relevant "member functions", and "instantiate" it in different ways. E.g. data Shape = Shape { area :: Int } square x = Shape (x^2) rectangle x y = Shape (x*y) circle r = Shape (pi*r^2) ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Am Montag, 17. Dezember 2007 19:26 schrieb Tim Chevalier: > On 12/17/07, Evan Laforge <[EMAIL PROTECTED]> wrote: > > I'm sure there's a trivial explanation for this, but here's something > > that I've always kind of wondered about: Given a single constructor > > type like "data X = X A B C" can't that be transformed into "newtype X > > = X (A, B, C)"? There must be some difference, because if there > > weren't we could transform all single constructor types that way, and > > dispense with newtype entirely. > > Strictness. In newtype X = X A, the A field is strict. In data X = X > A, the A field is lazy. So the compiler can't just turn all > single-constructor "data" types into "newtypes". Evan talked about data constructors with multiple fields, not with one single field. > (To generalize, if you were going to allow newtypes like > "newtype X = X (A, B, C)", the tuple would be unboxed, and you'd have the > same strictness/laziness distinction.) This is not a generalization of what you talked about. Why should the tuple type be unboxed? Tuple types are boxed, meaning there is a difference between _|_ and (_|_,…,_|_). If you write newtype X = X (A, B, C) then X doesn’t add another level of indirection but the level of indirection introduced by the tuple constructor remains, of course. So you could write the above newtype declaration instead of data X = X A B C. _|_ would then be represented as X _|_ (equal to _|_) and X _|_ _|_ _|_ as X (_|_,_|_,_|_). Instead of pattern matching against X a b c, you would have to pattern match against X (a,b,c). So why not use the above newtype declaration instead of multi-field data declarations? One strong reason is that tuple types are itself algebraic data types which could be defined by data declarations if they wouldn’t use special syntax. So we would have to represent a tuple type by a newtype whose field type would be the tuple type we just want to represent. > […] > Cheers, > Tim Best wishes, Wolfgang ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
On 12/17/07, Evan Laforge <[EMAIL PROTECTED]> wrote: > Oops, nevermind, I just saw the other thread and link to > http://www.haskell.org/haskellwiki/Newtype. Ok, so that seems like a > pretty subtle diffenence... I'm assuming the rationale behind > differentiating between a single constructor data and newtype is so > that data types don't suddenly change their behaviour around undefined > when they have only one constructor. I would find example y3 > surprising if I came across it in real code! It's not that subtle if you think about what newtype is for. Newtype is like "type", except that you're not just declaring a type synonym, but asking the typechecker to check that you don't use the synonym interchangeably with the type it's standing in for. Types declared with newtype and with type are supposed to act exactly the same way at runtime. In order to act exactly the same way at runtime, if you write newtype X = X A, X _|_ has to be indistinguishable from _|_ at runtime. In other words, the data constructor X has to be strict. In types declared with "data", constructors are lazy -- if they weren't, you wouldn't be programming in Haskell. Cheers, Tim -- Tim Chevalier * catamorphism.org * Often in error, never in doubt "People. Can't live with 'em, can't legally set fire to 'em." -- Sheree Schrager ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
On 12/17/07, Evan Laforge <[EMAIL PROTECTED]> wrote: > I'm sure there's a trivial explanation for this, but here's something > that I've always kind of wondered about: Given a single constructor > type like "data X = X A B C" can't that be transformed into "newtype X > = X (A, B, C)"? There must be some difference, because if there > weren't we could transform all single constructor types that way, and > dispense with newtype entirely. Strictness. In newtype X = X A, the A field is strict. In data X = X A, the A field is lazy. So the compiler can't just turn all single-constructor "data" types into "newtypes". (To generalize, if you were going to allow newtypes like "newtype X = X (A, B, C)", the tuple would be unboxed, and you'd have the same strictness/laziness distinction.) This is explained in section 4.2.3 of the H98 Report: http://www.haskell.org/onlinereport/decls.html Cheers, Tim -- Tim Chevalier * catamorphism.org * Often in error, never in doubt "Do we learn from our mistakes? I surely hope not / Takes all the fun out of making them again."--Trout Fishing In America ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
> I'm sure there's a trivial explanation for this, but here's something > that I've always kind of wondered about: Given a single constructor > type like "data X = X A B C" can't that be transformed into "newtype X > = X (A, B, C)"? There must be some difference, because if there > weren't we could transform all single constructor types that way, and > dispense with newtype entirely. Oops, nevermind, I just saw the other thread and link to http://www.haskell.org/haskellwiki/Newtype. Ok, so that seems like a pretty subtle diffenence... I'm assuming the rationale behind differentiating between a single constructor data and newtype is so that data types don't suddenly change their behaviour around undefined when they have only one constructor. I would find example y3 surprising if I came across it in real code! ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
> A newtype can only have one constructor, with one argument, and is > essentially a wrapper for that argument type. > > In the general case, you want to use "data" instead of "newtype": > > data Rectangle = R Int Int I'm sure there's a trivial explanation for this, but here's something that I've always kind of wondered about: Given a single constructor type like "data X = X A B C" can't that be transformed into "newtype X = X (A, B, C)"? There must be some difference, because if there weren't we could transform all single constructor types that way, and dispense with newtype entirely. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Peter Verswyvelen wrote: Very interesting, I did not know that! I thought newtype was an optimization of data, and that "newtype" was bad terminology. But if newtype is just a wrapper around a type, then the name is choosen well. I'm a bit confused why then one needs a data-constructor-like tag to construct a newtype value then? Is this to avoid having to add a type signature (for type inference)? I find this a bit weird since newtype Foo = Foo Int bar = Foo 123 does not safe a lot of keystrokes ;) compared to -- Incorrect Haskell follows newtype Foo = Int bar = 123::Foo You've broken the principle type property. let's stay away from numeric literals (which are fiddly because they're overloaded already in typeclass Num) and take a concrete type: data Foo = A | B newtype Bar = Bar Foo Now, the type of "A" is "Foo". If I was allowed to write "A::Bar" then I no longer have a simple principle type for "A": it appears that the type of "A" is "Foo" or "Bar" depending how I annotate it. Of course, I can make this work fine, using some form of constraint. Haskell already has constraints, we call them classes, and I could imagine giving "A" the principle type "(FooOrNewtypeOfFoo a) => a" However, that's a bunch of added complexity for such a simple feature :) Much nicer just to write "A" :: Foo and "Bar A" :: Bar. Jules ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Thomas Davie <[EMAIL PROTECTED]> writes: > Yes, and you can indeed do a similar thing in Haskell. The natural > thing to do here would be to define a type Shape... > data Shape = Circle Int > | Rectangle Int Int > | Square Int > If however, you *really* want to keep your shapes as being seperate > types, then you'll want to invoke the class system (note, not the same > as OO classes). > > class Shape a where > area :: a -> Int > > newtype Circle = C Int > > instance Shape Circle where > area (C r) = pi * r^2 There's a third way, too, and I haven't seen anybody mention it yet (apologies if I just missed it). You can provide an explicit record of the relevant "member functions", and "instantiate" it in different ways. E.g. data Shape = Shape { area :: Int } square x = Shape (x^2) rectangle x y = Shape (x*y) circle r = Shape (pi*r^2) -k -- If I haven't seen further, it is by standing in the footprints of giants ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
RE: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Very interesting, I did not know that! I thought newtype was an optimization of data, and that "newtype" was bad terminology. But if newtype is just a wrapper around a type, then the name is choosen well. I'm a bit confused why then one needs a data-constructor-like tag to construct a newtype value then? Is this to avoid having to add a type signature (for type inference)? I find this a bit weird since newtype Foo = Foo Int bar = Foo 123 does not safe a lot of keystrokes ;) compared to -- Incorrect Haskell follows newtype Foo = Int bar = 123::Foo -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Wolfgang Jeltsch Sent: Monday, December 17, 2007 5:39 PM To: haskell-cafe@haskell.org Subject: Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions. Am Montag, 17. Dezember 2007 13:04 schrieb Jed Brown: > […] > When your type only has one constructor, newtype is preferred over data, but > they are semantically equivalent. They are *not* semantically equivalent, as has already been said more or less. data adds an extra level of indirection. With data A a = MkA a, _|_ (i.e., undefinedness) is different from MkA _|_. If I don’t know anything about a value of A a then this is not the same as knowing that the value is at least an application of MkA. newtype just creates wrapper types and it’s very unfortunate that it uses syntax similar to data because it’s very different. With newtype A a = MkA a, you just create a wrapper type A a for each type a. Applying the constructor just means casting from a to A a, and pattern matching just means casting from A a to a. Type-casting _|_ yields botton, that’s why MkA _|_ is _|_ and pattern matching _|_ against A x doesn’t fail but assigns _|_ to x. > […] Best wishes, Wolfgang ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Am Montag, 17. Dezember 2007 13:04 schrieb Jed Brown: > […] > When your type only has one constructor, newtype is preferred over data, but > they are semantically equivalent. They are *not* semantically equivalent, as has already been said more or less. data adds an extra level of indirection. With data A a = MkA a, _|_ (i.e., undefinedness) is different from MkA _|_. If I don’t know anything about a value of A a then this is not the same as knowing that the value is at least an application of MkA. newtype just creates wrapper types and it’s very unfortunate that it uses syntax similar to data because it’s very different. With newtype A a = MkA a, you just create a wrapper type A a for each type a. Applying the constructor just means casting from a to A a, and pattern matching just means casting from A a to a. Type-casting _|_ yields botton, that’s why MkA _|_ is _|_ and pattern matching _|_ against A x doesn’t fail but assigns _|_ to x. > […] Best wishes, Wolfgang ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
RE: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
No neither do II think we can drop that bitI think I got confused about it for a second.not unsurprisingly. From: Brent Yorgey [mailto:[EMAIL PROTECTED] Sent: 17 December 2007 15:38 To: Nicholls, Mark Cc: Thomas Davie; Haskell Cafe Subject: Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions. On Dec 17, 2007 8:04 AM, Nicholls, Mark <[EMAIL PROTECTED]> wrote: No that's fineits all as clear as mud!..but that's not your fault. To recap... "type" introduces a synonym for another type, no new type is createdit's for readabilities sake. "Newtype" introduces an isomorphic copy of an existing type...but doesn't copy it's type class membership...the types are disjoint/distinct but isomorphic (thus only 1 constructor param). "data" introduces a new type, and defines a composition of existing types to create a new one based on "->" and "(". "class" introduces a constraint that any types declaring themselves to be a member of this class...that functions must exist to satisfy the constraint. I'm sure that's wrong, but it's a good as I've got at the moment. And to a degree it's all upside downwhat Haskell thinks are types...I think are "singnatures" and what Haskell thinks is a type "class" I think of as a type.it's not going to be easy. I think you've got it pretty well! The one quibble I would have with your recap is that I'm not sure what you mean by saying that "data" creates a new type 'based on "->" and "("'. Other than that it seems pretty spot-on. =) -Brent ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
On Dec 17, 2007 8:04 AM, Nicholls, Mark <[EMAIL PROTECTED]> wrote: > No that's fineits all as clear as mud!..but that's not your > fault. > > To recap... > > "type" introduces a synonym for another type, no new type is > createdit's for readabilities sake. > > "Newtype" introduces an isomorphic copy of an existing type...but > doesn't copy it's type class membership...the types are > disjoint/distinct but isomorphic (thus only 1 constructor param). > > "data" introduces a new type, and defines a composition of existing > types to create a new one based on "->" and "(". > > "class" introduces a constraint that any types declaring themselves to > be a member of this class...that functions must exist to satisfy the > constraint. > > I'm sure that's wrong, but it's a good as I've got at the moment. > > And to a degree it's all upside downwhat Haskell thinks are > types...I think are "singnatures" and what Haskell thinks is a type > "class" I think of as a type.it's not going to be easy. > > I think you've got it pretty well! The one quibble I would have with your recap is that I'm not sure what you mean by saying that "data" creates a new type 'based on "->" and "("'. Other than that it seems pretty spot-on. =) -Brent ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
RE: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Ahhh I'll give it a read. thanks -Original Message- From: Henning Thielemann [mailto:[EMAIL PROTECTED] Sent: 17 December 2007 13:05 To: Nicholls, Mark Cc: haskell-cafe@haskell.org Subject: Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions. On Mon, 17 Dec 2007, Nicholls, Mark wrote: > After many years of OOP though my brain is wired up to construct > software in that 'pattern'a problem for me at the moment is I cannot > see how to construct programs in an OO style in HaskellI know this > is probably not the way to approach it...but I feel I need to master the > syntax before the paradigm. This issue is rather a FAQ. Let's look what our Wiki provides: http://www.haskell.org/haskellwiki/OOP_vs_type_classes ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
On Mon, 17 Dec 2007, Nicholls, Mark wrote: > After many years of OOP though my brain is wired up to construct > software in that 'pattern'a problem for me at the moment is I cannot > see how to construct programs in an OO style in HaskellI know this > is probably not the way to approach it...but I feel I need to master the > syntax before the paradigm. This issue is rather a FAQ. Let's look what our Wiki provides: http://www.haskell.org/haskellwiki/OOP_vs_type_classes ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
RE: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
No that's fineits all as clear as mud!..but that's not your fault. To recap... "type" introduces a synonym for another type, no new type is createdit's for readabilities sake. "Newtype" introduces an isomorphic copy of an existing type...but doesn't copy it's type class membership...the types are disjoint/distinct but isomorphic (thus only 1 constructor param). "data" introduces a new type, and defines a composition of existing types to create a new one based on "->" and "(". "class" introduces a constraint that any types declaring themselves to be a member of this class...that functions must exist to satisfy the constraint. I'm sure that's wrong, but it's a good as I've got at the moment. And to a degree it's all upside downwhat Haskell thinks are types...I think are "singnatures" and what Haskell thinks is a type "class" I think of as a type.it's not going to be easy. -Original Message- From: Thomas Davie [mailto:[EMAIL PROTECTED] Sent: 17 December 2007 12:35 To: Nicholls, Mark Cc: Haskell Cafe Subject: Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions. On 17 Dec 2007, at 12:22, Nicholls, Mark wrote: > Ok... > > Thanks I need to revisit data and newtype to work out what the > difference is I think. Beware in doing so -- type, and newtype are not the same either. type creates a type synonim. That is, if I were to declare type Jam = Int then Jam and Int from that point on become completely interchangable, the only thing this does is make things readable. For example, a parser might be described as a function that takes a list of tokens, and outputs a parse tree, and a list of unparsed tokens: type Parser = [Token] -> (ParseTree, [Token]) if I write some parser combinators, I can now give them clear types like <|> :: Parser -> Parser -> Parser I could however still write this, and it would have *exactly* the same meaning. <|> :: ([Token] -> (ParseTree, [Token])) -> ([Token] -> (ParseTree, [Token])) -> [Token] -> (ParseTree, [Token]) newtype on the other hand introduces a new type to the type system. Because of this, the type system has to be able to tell when you're using your new type, so a tag gets attached. newtype Ham = Ham Int This creates a type that contains only an integer, but is different from Int (and Jam) in the type system's eyes. Thus, I cannot for example write (Ham 5) + (Ham 6) Because Ham is not Int and thus (+) does not work (or actually, more specifically, Ham is not a member of the class Num, the numeric types, and therefore (+) doesn't work). This can of course be fixed thus: newtype Ham = Ham Int deriving Num Hope that helps Tom Davie p.s. Sorry for the slip with the newtype Rectangle. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
On 17 Dec 2007, at 12:22, Nicholls, Mark wrote: Ok... Thanks I need to revisit data and newtype to work out what the difference is I think. Beware in doing so -- type, and newtype are not the same either. type creates a type synonim. That is, if I were to declare type Jam = Int then Jam and Int from that point on become completely interchangable, the only thing this does is make things readable. For example, a parser might be described as a function that takes a list of tokens, and outputs a parse tree, and a list of unparsed tokens: type Parser = [Token] -> (ParseTree, [Token]) if I write some parser combinators, I can now give them clear types like <|> :: Parser -> Parser -> Parser I could however still write this, and it would have *exactly* the same meaning. <|> :: ([Token] -> (ParseTree, [Token])) -> ([Token] -> (ParseTree, [Token])) -> [Token] -> (ParseTree, [Token]) newtype on the other hand introduces a new type to the type system. Because of this, the type system has to be able to tell when you're using your new type, so a tag gets attached. newtype Ham = Ham Int This creates a type that contains only an integer, but is different from Int (and Jam) in the type system's eyes. Thus, I cannot for example write (Ham 5) + (Ham 6) Because Ham is not Int and thus (+) does not work (or actually, more specifically, Ham is not a member of the class Num, the numeric types, and therefore (+) doesn't work). This can of course be fixed thus: newtype Ham = Ham Int deriving Num Hope that helps Tom Davie p.s. Sorry for the slip with the newtype Rectangle. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
RE: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Ok... Thanks I need to revisit data and newtype to work out what the difference is I think. -Original Message- From: Jed Brown [mailto:[EMAIL PROTECTED] On Behalf Of Jed Brown Sent: 17 December 2007 12:04 To: Nicholls, Mark Cc: haskell-cafe@haskell.org Subject: Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions. On 17 Dec 2007, [EMAIL PROTECTED] wrote: > Ooo > > "The constructor of a newtype must have exactly one field but `R' has > two In the newtype declaration for `Rectangle'" > > It doesn't like > > "newtype Rectangle = R Int Int" You want data Rectangle = R Int Int A newtype declaration will be completely erased at compile time. That is, when you have a declaration like newtype Circle = C Int the compiled code will not be able to distinguish between a Circle and an Int. You do, however, get all the benefits of a separate entity in the type system. When your type only has one constructor, newtype is preferred over data, but they are semantically equivalent. There are extensions which provide impressive newtype-deriving-foo (getting the compiler to write fairly non-trivial instance declarations for you). Jed ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
On 17 Dec 2007, [EMAIL PROTECTED] wrote: > Ooo > > "The constructor of a newtype must have exactly one field but `R' has > two In the newtype declaration for `Rectangle'" > > It doesn't like > > "newtype Rectangle = R Int Int" You want data Rectangle = R Int Int A newtype declaration will be completely erased at compile time. That is, when you have a declaration like newtype Circle = C Int the compiled code will not be able to distinguish between a Circle and an Int. You do, however, get all the benefits of a separate entity in the type system. When your type only has one constructor, newtype is preferred over data, but they are semantically equivalent. There are extensions which provide impressive newtype-deriving-foo (getting the compiler to write fairly non-trivial instance declarations for you). Jed pgp595ILQHSg7.pgp Description: PGP signature ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
On Dec 17, 2007 10:47 PM, Nicholls, Mark <[EMAIL PROTECTED]> wrote: > "The constructor of a newtype must have exactly one field but `R' has > two In the newtype declaration for `Rectangle'" > > It doesn't like > > "newtype Rectangle = R Int Int" A newtype can only have one constructor, with one argument, and is essentially a wrapper for that argument type. In the general case, you want to use "data" instead of "newtype": data Rectangle = R Int Int Stuart ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
RE: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
Ooo "The constructor of a newtype must have exactly one field but `R' has two In the newtype declaration for `Rectangle'" It doesn't like "newtype Rectangle = R Int Int" -Original Message- From: Thomas Davie [mailto:[EMAIL PROTECTED] Sent: 17 December 2007 11:04 To: Nicholls, Mark Cc: haskell-cafe@haskell.org Subject: Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions. On 17 Dec 2007, at 10:46, Nicholls, Mark wrote: > > I can obviously at a later date add a new class Triangle, and not > have to touch any of the above code Yes, and you can indeed do a similar thing in Haskell. The natural thing to do here would be to define a type Shape... data Shape = Circle Int | Rectangle Int Int | Square Int area :: Shape -> Int -- Note, this is an interesting type if you want the area of circles area (Circle r) = pi * r^2 area (Rectangle h w) = h * w area (Square l) = area (Rectangle l l) If however, you *really* want to keep your shapes as being seperate types, then you'll want to invoke the class system (note, not the same as OO classes). class Shape a where area :: a -> Int newtype Circle = C Int instance Shape Circle where area (C r) = pi * r^2 newtype Rectangle = R Int Int instance Shape Rectangle where area (R h w) = h * w newtype Square = Sq Int instance Shape Square where area (Sq l) = l * l -- Now we can do something with our shapes doubleArea :: Shape a => a -> Int doubleArea s = (area s) * 2 Hope that helps Bob ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
On 17 Dec 2007, at 11:14, Nicholls, Mark wrote: OK I'll have to digest this and mess about a bitbut can I make an observation at this point If I define "Shape" like data Shape = Circle Int | Rectangle Int Int | Square Int Isn't this now "closed"...i.e. the statement is effectively defining that shape is this and only ever thisi.e. can I in another module add new "types" of Shape? (sorry about all the quotation marks, but it's a minefield of potential confusions over types, classes etc). That's correct, another module could not add constructors to this type. The idea here is that you tell it all of the possible ways to construct Shape, and can then write functions to deal with it elsewhere. My other observation is...are the things on the right hand side of the the "="'s sign not types? Correct, they're constructors. So you could never for example write a function that accepts only Rectangles (unless you start getting into odd type extensions) The lower version makes more sense to me...I'll have to give it a go Both versions make sense. They differ only in how "heavy weight" they are. Defining a type allows you to do pattern matching on the constructors, and is a much better way of defining anything you know the structure of in the first place. Using the class system on the other hand, gives you more flexibility, but at the cost of a lot of readability. The class system is designed to be able to describe things that aren't explicitly the same type, but exhibit similar properties. For example the Eq class describes all things that are equatable, it defines the (==) and (/=) operators. Your Shape class describes all types in which it's sane to compute an area. A P.S. would be...I tend to write code rather than mess about in the GHCi shell.is there a way in code to output the type of a value..i.e. the ":t" operation? Take a look at the Typable class. Although, pretty much any code that you can compile can be loaded into ghci without modification, and that's by far the easier way of finding the types of things. Bob ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
RE: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
OK I'll have to digest this and mess about a bitbut can I make an observation at this point If I define "Shape" like data Shape = Circle Int | Rectangle Int Int | Square Int Isn't this now "closed"...i.e. the statement is effectively defining that shape is this and only ever thisi.e. can I in another module add new "types" of Shape? (sorry about all the quotation marks, but it's a minefield of potential confusions over types, classes etc). My other observation is...are the things on the right hand side of the the "="'s sign not types? The lower version makes more sense to me...I'll have to give it a go A P.S. would be...I tend to write code rather than mess about in the GHCi shell.is there a way in code to output the type of a value..i.e. the ":t" operation? -Original Message- From: Thomas Davie [mailto:[EMAIL PROTECTED] Sent: 17 December 2007 11:04 To: Nicholls, Mark Cc: haskell-cafe@haskell.org Subject: Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions. On 17 Dec 2007, at 10:46, Nicholls, Mark wrote: > > I can obviously at a later date add a new class Triangle, and not > have to touch any of the above code Yes, and you can indeed do a similar thing in Haskell. The natural thing to do here would be to define a type Shape... data Shape = Circle Int | Rectangle Int Int | Square Int area :: Shape -> Int -- Note, this is an interesting type if you want the area of circles area (Circle r) = pi * r^2 area (Rectangle h w) = h * w area (Square l) = area (Rectangle l l) If however, you *really* want to keep your shapes as being seperate types, then you'll want to invoke the class system (note, not the same as OO classes). class Shape a where area :: a -> Int newtype Circle = C Int instance Shape Circle where area (C r) = pi * r^2 newtype Rectangle = R Int Int instance Shape Rectangle where area (R h w) = h * w newtype Square = Sq Int instance Shape Square where area (Sq l) = l * l -- Now we can do something with our shapes doubleArea :: Shape a => a -> Int doubleArea s = (area s) * 2 Hope that helps Bob ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
"Nicholls, Mark" <[EMAIL PROTECTED]> writes: > After many years of OOP though my brain is wired up to construct software in > that ?pattern??.a problem for me at the moment is I cannot see how to > construct > programs in an OO style in Haskell?.I know this is probably not the way to > approach it?but I feel I need to master the syntax before the paradigm. Mostly, you'd use an algebraic data type. I.e. data Shape = Square Int | Rectangle Int Int | Circle Int area :: Shape -> Int area (Square x) = x^2 area (Rectangle x y) = x * y area (Circle r) = pi*r^2 -k -- If I haven't seen further, it is by standing in the footprints of giants ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....
On 17 Dec 2007, at 10:46, Nicholls, Mark wrote: I can obviously at a later date add a new class Triangle, and not have to touch any of the above code…. Yes, and you can indeed do a similar thing in Haskell. The natural thing to do here would be to define a type Shape... data Shape = Circle Int | Rectangle Int Int | Square Int area :: Shape -> Int -- Note, this is an interesting type if you want the area of circles area (Circle r) = pi * r^2 area (Rectangle h w) = h * w area (Square l) = area (Rectangle l l) If however, you *really* want to keep your shapes as being seperate types, then you'll want to invoke the class system (note, not the same as OO classes). class Shape a where area :: a -> Int newtype Circle = C Int instance Shape Circle where area (C r) = pi * r^2 newtype Rectangle = R Int Int instance Shape Rectangle where area (R h w) = h * w newtype Square = Sq Int instance Shape Square where area (Sq l) = l * l -- Now we can do something with our shapes doubleArea :: Shape a => a -> Int doubleArea s = (area s) * 2 Hope that helps Bob___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe