Send Beginners mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."
Today's Topics:
1. Re: (Implicit) equality testing using multiple function
definitions (Tom Murphy)
2. Re: (Implicit) equality testing using multiple function
definitions (Brandon Allbery)
3. Re: (Implicit) equality testing using multiple function
definitions (Brent Yorgey)
4. Typeclasses vs. Data (Thomas)
5. Re: Typeclasses vs. Data (David Place)
6. Re: Typeclasses vs. Data (David Place)
7. Re: Typeclasses vs. Data (Thomas)
8. Re: Typeclasses vs. Data (David Place)
----------------------------------------------------------------------
Message: 1
Date: Wed, 20 Jul 2011 14:38:39 -0400
From: Tom Murphy <[email protected]>
Subject: Re: [Haskell-beginners] (Implicit) equality testing using
multiple function definitions
To: Brandon Allbery <[email protected]>
Cc: beginners <[email protected]>
Message-ID:
<CAO9Q0tV90qUJM1uAKazByh8jRuTTum3=kx8p+dyzku40sm2...@mail.gmail.com>
Content-Type: text/plain; charset=ISO-8859-1
On 7/18/11, Brandon Allbery <[email protected]> wrote:
[...]
>
> "Circumvents"? You make it sound like the point of typeclasses is to
> restrict things. In fact, the point is to *undo* the restrictions
> necessarily introduced by polymorphism: if you don't know the type of
> something, you don't know what you can do with it. Typeclasses let us say
> "this can be any type, but we need to be able to do <x> with it". They
> don't circumvent; they *add*.
>
I wish I could think of a good example. Since I can't, I'll just
try and make my point: In a way, the point of typeclasses _is_ to
restrict things: one of the things that typeclasses enables is a
compile-time error if I, say, try and add Bools: by not giving Bool a
Num instance, we're expressing that something can't be expressed.
There has to be a reason why we've all typed "deriving (Eq)"
again and again: because sometimes we don't want, for some OurType, to
be able to express:
(a :: OurType) == (b :: OurType).
This is the source of my confusion.
Thanks for your time,
Tom
------------------------------
Message: 2
Date: Wed, 20 Jul 2011 15:05:07 -0400
From: Brandon Allbery <[email protected]>
Subject: Re: [Haskell-beginners] (Implicit) equality testing using
multiple function definitions
To: Tom Murphy <[email protected]>
Cc: beginners <[email protected]>
Message-ID:
<cakfcl4v4o5pornjwrem97i0cmy+qk6x989s0_sro7w47sop...@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"
On Wed, Jul 20, 2011 at 14:38, Tom Murphy <[email protected]> wrote:
> There has to be a reason why we've all typed "deriving (Eq)"
> again and again: because sometimes we don't want, for some OurType, to
> be able to express:
> (a :: OurType) == (b :: OurType).
>
There is a good reason, but that's not it. You're still thinking in terms
of objects that carry method dictionaries around; Haskell *is not object
oriented*, values are just values. Operations are defined by types, not by
values. You can't ask a value how it should be compared.
Typeclasses, which superficially look like objects/classes but aren't, are a
way around this. A typeclass actually defines a dictionary mapping types to
functions; but because values are not objects, some way needs to be provided
to pass these dictionaries where they are needed. This is the function of
contexts: they're actually function arguments.
> f :: Eq a => a -> a -> a
is a function that takes three arguments: a map of implementations, and two
values of some type. Whenever this function is invoked, the compiler passes
it the Eq dictionary entry for the appropriate type a. If there were
multiple typeclass contexts, the map would combine all of them.
It's not about hiding anything. The only reason you think there is
something to hide is because an object would carry around that information
and something would therefore have to hide it for it to not be available;
but there are no objects here, so something has to be added to carry it
around.
--
brandon s allbery [email protected]
wandering unix systems administrator (available) (412) 475-9364 vm/sms
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://www.haskell.org/pipermail/beginners/attachments/20110720/4538663d/attachment-0001.htm>
------------------------------
Message: 3
Date: Wed, 20 Jul 2011 17:04:22 -0400
From: Brent Yorgey <[email protected]>
Subject: Re: [Haskell-beginners] (Implicit) equality testing using
multiple function definitions
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
On Wed, Jul 20, 2011 at 02:38:39PM -0400, Tom Murphy wrote:
> On 7/18/11, Brandon Allbery <[email protected]> wrote:
> [...]
> >
> > "Circumvents"? You make it sound like the point of typeclasses is to
> > restrict things. In fact, the point is to *undo* the restrictions
> > necessarily introduced by polymorphism: if you don't know the type of
> > something, you don't know what you can do with it. Typeclasses let us say
> > "this can be any type, but we need to be able to do <x> with it". They
> > don't circumvent; they *add*.
> >
>
> I wish I could think of a good example. Since I can't, I'll just
> try and make my point: In a way, the point of typeclasses _is_ to
> restrict things: one of the things that typeclasses enables is a
> compile-time error if I, say, try and add Bools: by not giving Bool a
> Num instance, we're expressing that something can't be expressed.
I think you are both right. There's a duality here, depending on your
point of view. Consider a function type
blah :: Foo a => ... a ...
>From the point of view of someone *calling* this function, the Foo
constraint *adds* some restriction: you may only pass things whose type
is an instance of Foo. If you try to pass anything else you will get
an error.
>From the point of view of someone *implementing* this function, the
Foo constraint *removes* some restriction: if there was no Foo
constraint you would not be able to do anything with any arguments of
type 'a'; given the Foo constraint you can do anything you could have
done without it, *plus* you can use any Foo methods.
-Brent
------------------------------
Message: 4
Date: Wed, 20 Jul 2011 23:58:16 +0200
From: Thomas <[email protected]>
Subject: [Haskell-beginners] Typeclasses vs. Data
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Hello!
Trying to rewrite a program I ran into a type problem with typeclasses.
It's a mini-interpreter, the essential (extremely reduced) part is:
eval e k = case (car e) of
(Id "begin") -> eval_begin (cdr e) k
eval_begin e k = eval (car e) (if isNull (cdr e) then k else (BeginCont
k (cdr e)))
Using "data" to define my data all is well:
data Continuation =
BeginCont Continuation Expression
resume k e = case k of
BeginCont k' es -> eval_begin es k'
Unfortunately when trying to extend the program by other types of
"Continuation" I must add to the data definition and add a matching
clause to "resume". That is I must modify the core module.
So I tried to decouple this using a typeclass like so:
class Continuation a where
resume :: a -> Expression -> Expression
data BeginCont a = BeginCont a Expression deriving (Show)
instance (Continuation a) => Continuation (BeginCont a) where
resume (BeginCont k es) v = eval_begin es k
This, however, results in an "infinite type" error.
Is there a way to make the typeclass version typecheck?
If not: How can one decouple this code in Haskell?
What also puzzles me are the differences in "infinite" types.
The above data declaration for "Continuation" is essentially infinite,
too. But it works. And I thought I had understood this part...
Any hints greatly appreciated!
Thanks in advance,
Thomas
PS:
The minimal "program" to get it type check is:
data Expression = Null | Num Int | Id String | List [Expression]
deriving (Eq, Show)
cdr :: Expression -> Expression
cdr (List []) = error "cdr Null !"
cdr (List (_:[])) = Null
cdr (List (l:ls)) = List ls
car :: Expression -> Expression
car (List l) = head l
isNull Null = True
isNull _ = False
eval e k = case (car e) of
(Id "begin") -> eval_begin (cdr e) k
eval_begin e k = eval (car e) (if isNull (cdr e) then k else (BeginCont
k (cdr e)))
-- replace the following 5 lines...
data Continuation =
BeginCont Continuation Expression
resume k e = case k of
BeginCont k' es -> eval_begin es k'
{- ... with these to see the error
class Continuation a where
resume :: a -> Expression -> Expression
data BeginCont a = BeginCont a Expression deriving (Show)
instance (Continuation a) => Continuation (BeginCont a) where
resume (BeginCont k es) v = eval_begin es k
-]
------------------------------
Message: 5
Date: Wed, 20 Jul 2011 18:18:42 -0400
From: David Place <[email protected]>
Subject: Re: [Haskell-beginners] Typeclasses vs. Data
To: Thomas <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
On Jul 20, 2011, at 5:58 PM, Thomas wrote:
> class Continuation a where
> resume :: a -> Expression -> Expression
>
> data BeginCont a = BeginCont a Expression deriving (Show)
> instance (Continuation a) => Continuation (BeginCont a) where
> resume (BeginCont k es) v = eval_begin es k
I think we need to know the definition of Expression. if define it with a
dummy type
eval_begin a b = a
type Expression = Int
this code fragment compiles. Would you send a code fragment that will yield
the error?
____________________
David Place
Owner, Panpipes Ho! LLC
http://panpipesho.com
[email protected]
------------------------------
Message: 6
Date: Wed, 20 Jul 2011 18:23:49 -0400
From: David Place <[email protected]>
Subject: Re: [Haskell-beginners] Typeclasses vs. Data
To: Thomas <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
Please disregard my previous message. I didn't read your message carefully
enough.
____________________
David Place
Owner, Panpipes Ho! LLC
http://panpipesho.com
[email protected]
On Jul 20, 2011, at 5:58 PM, Thomas wrote:
> Hello!
>
> Trying to rewrite a program I ran into a type problem with typeclasses.
>
> It's a mini-interpreter, the essential (extremely reduced) part is:
>
> eval e k = case (car e) of
> (Id "begin") -> eval_begin (cdr e) k
> eval_begin e k = eval (car e) (if isNull (cdr e) then k else (BeginCont k
> (cdr e)))
>
> Using "data" to define my data all is well:
>
> data Continuation =
> BeginCont Continuation Expression
> resume k e = case k of
> BeginCont k' es -> eval_begin es k'
>
> Unfortunately when trying to extend the program by other types of
> "Continuation" I must add to the data definition and add a matching clause to
> "resume". That is I must modify the core module.
> So I tried to decouple this using a typeclass like so:
>
> class Continuation a where
> resume :: a -> Expression -> Expression
>
> data BeginCont a = BeginCont a Expression deriving (Show)
> instance (Continuation a) => Continuation (BeginCont a) where
> resume (BeginCont k es) v = eval_begin es k
>
> This, however, results in an "infinite type" error.
>
> Is there a way to make the typeclass version typecheck?
> If not: How can one decouple this code in Haskell?
>
> What also puzzles me are the differences in "infinite" types.
> The above data declaration for "Continuation" is essentially infinite, too.
> But it works. And I thought I had understood this part...
>
> Any hints greatly appreciated!
> Thanks in advance,
> Thomas
>
>
> PS:
> The minimal "program" to get it type check is:
>
> data Expression = Null | Num Int | Id String | List [Expression]
> deriving (Eq, Show)
>
> cdr :: Expression -> Expression
> cdr (List []) = error "cdr Null !"
> cdr (List (_:[])) = Null
> cdr (List (l:ls)) = List ls
>
> car :: Expression -> Expression
> car (List l) = head l
>
> isNull Null = True
> isNull _ = False
>
> eval e k = case (car e) of
> (Id "begin") -> eval_begin (cdr e) k
>
> eval_begin e k = eval (car e) (if isNull (cdr e) then k else (BeginCont k
> (cdr e)))
>
> -- replace the following 5 lines...
> data Continuation =
> BeginCont Continuation Expression
>
> resume k e = case k of
> BeginCont k' es -> eval_begin es k'
>
> {- ... with these to see the error
> class Continuation a where
> resume :: a -> Expression -> Expression
>
> data BeginCont a = BeginCont a Expression deriving (Show)
> instance (Continuation a) => Continuation (BeginCont a) where
> resume (BeginCont k es) v = eval_begin es k
> -]
>
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://www.haskell.org/mailman/listinfo/beginners
------------------------------
Message: 7
Date: Thu, 21 Jul 2011 00:26:19 +0200
From: Thomas <[email protected]>
Subject: Re: [Haskell-beginners] Typeclasses vs. Data
To: David Place <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Hello David!
Thank you for taking the time.
Here is a complete fragment that shows the error:
data Expression = Null | Num Int | Id String | List [Expression]
deriving (Eq, Show)
cdr :: Expression -> Expression
cdr (List []) = error "cdr Null !"
cdr (List (_:[])) = Null
cdr (List (l:ls)) = List ls
car :: Expression -> Expression
car (List l) = head l
car n = error (show n)
isNull Null = True
isNull _ = False
eval e k = case (car e) of
(Id "begin") -> eval_begin (cdr e) k
eval_begin e k = eval (car e) (if isNull (cdr e) then k else (BeginCont
k (cdr e)))
class Continuation a where
resume :: a -> Expression -> Expression
data BeginCont a = BeginCont a Expression deriving (Show)
instance (Continuation a) => Continuation (BeginCont a) where
resume (BeginCont k es) v = eval_begin es k
Regards,
Thomas
On 21.07.2011 00:18, David Place wrote:
> On Jul 20, 2011, at 5:58 PM, Thomas wrote:
>
>> class Continuation a where
>> resume :: a -> Expression -> Expression
>>
>> data BeginCont a = BeginCont a Expression deriving (Show)
>> instance (Continuation a) => Continuation (BeginCont a) where
>> resume (BeginCont k es) v = eval_begin es k
>
> I think we need to know the definition of Expression. if define it with a
> dummy type
>
> eval_begin a b = a
> type Expression = Int
>
> this code fragment compiles. Would you send a code fragment that will yield
> the error?
> ____________________
> David Place
> Owner, Panpipes Ho! LLC
> http://panpipesho.com
> [email protected]
>
>
------------------------------
Message: 8
Date: Wed, 20 Jul 2011 18:40:45 -0400
From: David Place <[email protected]>
Subject: Re: [Haskell-beginners] Typeclasses vs. Data
To: Thomas <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=iso-8859-1
On Jul 20, 2011, at 6:26 PM, Thomas wrote:
> Thank you for taking the time.
> Here is a complete fragment that shows the error:
Hi, Thomas.
I'm very sympathetic. I hate it when I get an error like this. I looked at
your code and the solution didn't jump off the page, maybe it will for someone
else. In the meantime, I suggest this strategy. Carefully give type
signatures to all of your functions. This way you can help the type checker
give better error messages. The type inference algorithm can go away into
crazy land if you give it a nonsense definition.
___________________
David Place
Owner, Panpipes Ho! LLC
http://panpipesho.com
[email protected]
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 37, Issue 40
*****************************************