Re: [Haskell-cafe] OOP'er with (hopefully) trivial questions.....

2007-12-18 Thread Jules Bean

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.....

2007-12-18 Thread Miguel Mitrofanov
 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.....

2007-12-18 Thread Jules Bean

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.....

2007-12-18 Thread Jules Bean

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.....

2007-12-18 Thread Felipe Lessa
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.....

2007-12-18 Thread C.M.Brown
 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.....

2007-12-18 Thread Tillmann Rendel

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.....

2007-12-18 Thread Lutz Donnerhacke
* 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.....

2007-12-18 Thread Sterling Clover
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.....

2007-12-17 Thread Thomas Davie


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.....

2007-12-17 Thread Ketil Malde
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.....

2007-12-17 Thread Nicholls, Mark
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.....

2007-12-17 Thread Thomas Davie


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.....

2007-12-17 Thread Nicholls, Mark
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.....

2007-12-17 Thread Stuart Cook
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.....

2007-12-17 Thread Jed Brown
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.....

2007-12-17 Thread Nicholls, Mark
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.....

2007-12-17 Thread Thomas Davie


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.....

2007-12-17 Thread Nicholls, Mark
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.....

2007-12-17 Thread Henning Thielemann

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.....

2007-12-17 Thread Nicholls, Mark
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.....

2007-12-17 Thread Brent Yorgey
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.....

2007-12-17 Thread Nicholls, Mark
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.....

2007-12-17 Thread Wolfgang Jeltsch
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.....

2007-12-17 Thread Peter Verswyvelen
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.....

2007-12-17 Thread Ketil Malde
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.....

2007-12-17 Thread Jules Bean

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.....

2007-12-17 Thread Evan Laforge
 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.....

2007-12-17 Thread Evan Laforge
 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.....

2007-12-17 Thread 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. (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.....

2007-12-17 Thread Tim Chevalier
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.....

2007-12-17 Thread Wolfgang Jeltsch
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.....

2007-12-17 Thread Tim Chevalier
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.....

2007-12-17 Thread Miguel Mitrofanov

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.....

2007-12-17 Thread Evan Laforge
 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.....

2007-12-17 Thread Derek Elkins
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.....

2007-12-17 Thread Ketil Malde
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_castCircle(s)){...}
   else if (dynamic_castRectangle(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