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: A first try (Heinrich Apfelmus)
2. Re: A first try (David Place)
3. Need help understanding (1) typeclass instances that have
multiple parameter types, and (2) overlapping instances
(Costello, Roger L.)
4. Re: Need help understanding (1) typeclass instances that
have multiple parameter types, and (2) overlapping instances
(David Place)
5. Re: Need help understanding (1) typeclass instances that
have multiple parameter types, and (2) overlapping instances
(Daniel Fischer)
6. Re: A first try (Manfred Lotz)
7. Re: A first try (David Place)
8. Re: A first try (Manfred Lotz)
----------------------------------------------------------------------
Message: 1
Date: Sun, 26 Jun 2011 14:25:38 +0200
From: Heinrich Apfelmus <[email protected]>
Subject: Re: [Haskell-beginners] A first try
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=UTF-8; format=flowed
David Place wrote:
> Heinrich Apfelmus wrote:
>
>> Personally, I think that lazy IO is not a weakness and works
>> extremely well for prototyping. In contrast, I find IterateeIO to
>> be ugly and non-idiomatic Haskell, since it exposes implementation
>> details and is not built on an algebraic "combinators & laws"
>> approach. Being challenging to understand is not a substitute for
>> beauty.
>
> Interesting, I appreciate your point of view. My experience with
> Lazy IO is that its non-determinism breaks down the
> algebraic/equational intuition. In order to manage handle resources,
> I must have in mind too many operational details.
Well, one could say that it's the fault of the operating system for not
doing garbage collection on file handles (c.f. Oberon).
> I feel that iteratee IO encapsulates these in nice compositional
> combinators.
What about the combinator
withFile :: FilePath -> (String -> a) -> IO a
withFile name f = bracket (openFile name ReadMode) hClose $ \h ->
evaluate . f =<< hGetContents h
? It gives you the same thing as Iteratees - a way to apply a function
to the contents of a file - without the need to rewrite all the existing
list functions like map , lines , words , and so on.
> I agree that it's not very beautiful, though. My feeling is that it
> is not quite finished. Perhaps there are a couple of more insights
> that will make it really nice.
I'm all for beauty in programming.
Best regards,
Heinrich Apfelmus
--
http://apfelmus.nfshost.com
------------------------------
Message: 2
Date: Sun, 26 Jun 2011 09:27:47 -0400
From: David Place <[email protected]>
Subject: Re: [Haskell-beginners] A first try
To: Heinrich Apfelmus <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
On Jun 26, 2011, at 8:25 AM, Heinrich Apfelmus wrote:
> What about the combinator
>
> withFile :: FilePath -> (String -> a) -> IO a
> withFile name f = bracket (openFile name ReadMode) hClose $ \h ->
> evaluate . f =<< hGetContents h
>
> ? It gives you the same thing as Iteratees - a way to apply a function to the
> contents of a file - without the need to rewrite all the existing list
> functions like map , lines , words , and so on.
How would you, for instance, implement the program for counting all the words
in a list of files that Oleg describes in his message?
> http://okmij.org/ftp/Haskell/Iteratee/Lazy-vs-correct.txt
Nested calls to withFile would require too many open handles.
____________________
David Place
Owner, Panpipes Ho! LLC
http://panpipesho.com
[email protected]
------------------------------
Message: 3
Date: Sun, 26 Jun 2011 09:33:45 -0400
From: "Costello, Roger L." <[email protected]>
Subject: [Haskell-beginners] Need help understanding (1) typeclass
instances that have multiple parameter types, and (2) overlapping
instances
To: "[email protected]" <[email protected]>
Message-ID:
<[email protected]>
Content-Type: text/plain; charset="us-ascii"
Hi Folks,
I have questions about:
- typeclass instances that have multiple parameter types
- overlapping instances
Let's take an example of a typeclass with two instances:
class MyShow a where
toString :: a -> String
instance MyShow Int where
toString = show
instance MyShow (Int, Int) where
toString (a, b) = toString a ++ ", " ++ toString b
The first instance has one parameter type (Int) and the second instance has two
parameter types (Int, Int).
When the class and instances are compiled, this error is generated:
Illegal instance declaration for `MyShow (Int, Int)'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are type *variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `MyShow (Int, Int)'
I interpret that error message to mean that Haskell has this rule:
Instances with one parameter type can specify non-variable
types (such as Int), but instances with multiple parameter
types can only use variable types (e.g., a, b, c).
Is that the rule?
What is the rationale for that rule?
Next, I placed this at the top of my file:
{-# LANGUAGE FlexibleInstances #-}
and the error message went away.
Apparently the pragma is telling the compiler:
Even though the Haskell code does not strictly conform to the
Haskell specification, please let it compile.
Is that what the pragma is telling the compiler?
There must be a good reason why Haskell prohibits non-variable types in
multi-parameter instances. So there must be a downside to adding that pragma.
What is the downside?
Now let's move on to my questions about overlapping instances.
I created a third instance. It is for a pair of values of any type:
instance (MyShow a, MyShow b) => MyShow (a, b) where
toString (a, b) = ">>" ++ toString a ++ " " ++ toString b ++ "<<"
It compiles without error.
But if I try to use the second instance (the one that was defined for two
Int's):
toString ((34 :: Int), (44 :: Int))
then I get an overlapping instances error:
Overlapping instances for MyShow (Int, Int)
arising from a use of `toString'
Matching instances:
instance MyShow (Int, Int) -- Defined at Overlap.hs:11:9-25
instance (MyShow a, MyShow b) => MyShow (a, b)
In the expression: toString ((34 :: Int), (44 :: Int))
I see how this:
toString ((34 :: Int), (44 :: Int))
can match with the second and third instances, and thus the compiler has
ambiguity on which instance to use.
Is there a way to express,
Hey compiler, please use this instance:
instance MyShow (Int, Int)
That is, when confronted with overlapping instances, what should I do?
/Roger
------------------------------
Message: 4
Date: Sun, 26 Jun 2011 10:12:45 -0400
From: David Place <[email protected]>
Subject: Re: [Haskell-beginners] Need help understanding (1) typeclass
instances that have multiple parameter types, and (2) overlapping
instances
To: "Costello, Roger L." <[email protected]>
Cc: "[email protected]" <[email protected]>
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
On Jun 26, 2011, at 9:33 AM, Costello, Roger L. wrote:
> instance MyShow (Int, Int) where
> toString (a, b) = toString a ++ ", " ++ toString b
>
> The first instance has one parameter type (Int) and the second instance has
> two parameter types (Int, Int).
I'm not sure what you mean by "two parameter types" here. The instance has one
parameter type: a pair of ints.
____________________
David Place
Owner, Panpipes Ho! LLC
http://panpipesho.com
[email protected]
------------------------------
Message: 5
Date: Sun, 26 Jun 2011 17:02:04 +0200
From: Daniel Fischer <[email protected]>
Subject: Re: [Haskell-beginners] Need help understanding (1) typeclass
instances that have multiple parameter types, and (2) overlapping
instances
To: [email protected]
Message-ID: <[email protected]>
Content-Type: Text/Plain; charset="iso-8859-1"
On Sunday 26 June 2011, 15:33:45, Costello, Roger L. wrote:
> Hi Folks,
>
> I have questions about:
>
> - typeclass instances that have multiple parameter types
> - overlapping instances
>
> Let's take an example of a typeclass with two instances:
>
> class MyShow a where
> toString :: a -> String
>
> instance MyShow Int where
> toString = show
>
> instance MyShow (Int, Int) where
> toString (a, b) = toString a ++ ", " ++ toString b
>
> The first instance has one parameter type (Int) and the second instance
> has two parameter types (Int, Int).
No, it also has only one parameter type, the type (Int,Int).
>
> When the class and instances are compiled, this error is generated:
>
> Illegal instance declaration for `MyShow (Int, Int)'
> (All instance types must be of the form (T a1 ... an)
> where a1 ... an are type *variables*,
> and each type variable appears at most once in the instance
> head. Use -XFlexibleInstances if you want to disable this.)
> In the instance declaration for `MyShow (Int, Int)'
>
> I interpret that error message to mean that Haskell has this rule:
>
> Instances with one parameter type can specify non-variable
> types (such as Int), but instances with multiple parameter
> types can only use variable types (e.g., a, b, c).
Int is a type constructor (of kind *), which is applied to 0 type variables
[hence the type variables it is applied to are vacuously distinct].
(Int,Int) is the type constructor (,) applied to two type arguments [which
are not type variables], both of which are the type Int.
Haskell98 (probably also Haskell2010, I'm too lazy to look it up now) says
all instance types must have the form
(type constructor) applied to distinct type variables
So
instance (MyShow a, MyShow b) => MyShow (a,b) where ...
is allowed, but none of
instance (MyShow a) => MyShow (a,a) where ... (type variables not distinct)
instance (MyShow a) => MyShow (a, Int) where .. (one non-type-variable)
instance MyShow (Int,Int) where (two non-type-variables)
instance Show a => MyShow a where ... (no type constructor)
>
> Is that the rule?
Not quite, see above.
>
> What is the rationale for that rule?
I'm not sure, I guess it's easier to implement.
>
> Next, I placed this at the top of my file:
>
> {-# LANGUAGE FlexibleInstances #-}
>
> and the error message went away.
>
> Apparently the pragma is telling the compiler:
>
> Even though the Haskell code does not strictly conform to the
> Haskell specification, please let it compile.
>
> Is that what the pragma is telling the compiler?
Yes, although in this case, it's rather "please lift an unnecessary and
cumbersome restriction on the form of instance declarations".
>
> There must be a good reason why Haskell prohibits non-variable types in
> multi-parameter instances.
Correcting the misunderstanding, it prohibits non-variable types as
arguments to type constructors in instance heads, I know of no good reason
why it does.
> So there must be a downside to adding that
> pragma. What is the downside?
Your code will only work with implementations which have the
FlexibleInstances extension.
>
>
> Now let's move on to my questions about overlapping instances.
>
> I created a third instance. It is for a pair of values of any type:
>
> instance (MyShow a, MyShow b) => MyShow (a, b) where
> toString (a, b) = ">>" ++ toString a ++ " " ++ toString b ++
> "<<"
>
> It compiles without error.
Type constructor (,) applied to two distinct type variables [a, b], that's
the form allowed by H98.
>
> But if I try to use the second instance (the one that was defined for
> two Int's):
>
> toString ((34 :: Int), (44 :: Int))
>
> then I get an overlapping instances error:
>
> Overlapping instances for MyShow (Int, Int)
> arising from a use of `toString'
> Matching instances:
> instance MyShow (Int, Int) -- Defined at Overlap.hs:11:9-25
> instance (MyShow a, MyShow b) => MyShow (a, b)
> In the expression: toString ((34 :: Int), (44 :: Int))
>
> I see how this:
>
> toString ((34 :: Int), (44 :: Int))
>
> can match with the second and third instances, and thus the compiler has
> ambiguity on which instance to use.
Exactly, the type (Int,Int) matches (a,b) as well as (Int,Int) [and it also
matches (a,a), (Int,a), (a,Int)].
>
> Is there a way to express,
>
> Hey compiler, please use this instance:
>
> instance MyShow (Int, Int)
>
> That is, when confronted with overlapping instances, what should I do?
That is what OverlappingInstances does, iirc; when several instance heads
match, it chooses the most specific one if there is a well-defined most
specific instance. If there is no well-defined most specific one, a compile
error happens.
But it's somewhat delicate, if you have a function
foo :: (MyShow a) => a -> String
and at some place you call it with an (Int,Int) argument, it may be that
the compiler uses the general (a,b) instance and not the (Int,Int) one.
Generally, OverlappingInstances are considered dangerous and if possible
you should avoid them, and if you use them, you'd better know very well how
instance selection happens.
HTH,
Daniel
------------------------------
Message: 6
Date: Sun, 26 Jun 2011 19:29:06 +0200
From: Manfred Lotz <[email protected]>
Subject: Re: [Haskell-beginners] A first try
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=US-ASCII
On Sun, 26 Jun 2011 09:27:47 -0400
David Place <[email protected]> wrote:
>
> On Jun 26, 2011, at 8:25 AM, Heinrich Apfelmus wrote:
>
> > What about the combinator
> >
> > withFile :: FilePath -> (String -> a) -> IO a
> > withFile name f = bracket (openFile name ReadMode) hClose $ \h ->
> > evaluate . f =<< hGetContents h
> >
> > ? It gives you the same thing as Iteratees - a way to apply a
> > function to the contents of a file - without the need to rewrite
> > all the existing list functions like map , lines , words , and so
> > on.
>
When I stumbled upon lazy IO newbie-wise I was pointed to withFile
resp. bracket by Daniel Fischer and now that I know how to do it it
seems fine to me. It also alerted me to pay more attention to lazyness
as this is a Haskell immanent thingie.
> How would you, for instance, implement the program for counting all
> the words in a list of files that Oleg describes in his message?
>
> > http://okmij.org/ftp/Haskell/Iteratee/Lazy-vs-correct.txt
>
I'm not quite sure if it boils down to the same problem
structure-wise but I had to scan thru some 4000 small xml files, and I
did it like this (after Daniel lifted me up...):
import qualified System.IO.UTF8 as U
...
dt <- scanDir ccbd
let xmlfiles = filter (\x -> "xml" `isSuffixOf` x) dt
-- insert xml contents into two maps s, and ht.
(s,ht) <- foldM insertXml (M.empty,M.empty) xmlfiles
...
and
insertXml (stat, m) xf =
U.withBinaryFile xf ReadMode
(\handle -> do ct <- getXmlContent xf handle
... some code...
return $! (stat',m'))
and
getXmlContent xf inh = do
xml <- U.hGetContents inh
let content = parseXMLDoc xml
...
--
Manfred
------------------------------
Message: 7
Date: Sun, 26 Jun 2011 15:02:07 -0400
From: David Place <[email protected]>
Subject: Re: [Haskell-beginners] A first try
To: Manfred Lotz <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
On Jun 26, 2011, at 1:29 PM, Manfred Lotz wrote:
> When I stumbled upon lazy IO newbie-wise I was pointed to withFile
> resp. bracket by Daniel Fischer and now that I know how to do it it
> seems fine to me. It also alerted me to pay more attention to lazyness
> as this is a Haskell immanent thingie.
Of course, it is possible to use hGetContents with withFile. You can still get
into trouble because hGetContents is unsafe. Beginners get tripped up trying
to do something like the following getting unexpected results. (i remember I
did.)
print10 =
do
contents <- withFile "/usr/share/dict/words" ReadMode (\h ->
hGetContents h)
print $ take 10 contents
So, you have to do this keeping in mind a rather procedural model of the
evaluation of the lazy data structures. I feel this is not very declarative or
intuitive.
print10' =
do
h <- openFile "/usr/share/dict/words" ReadMode
contents <- hGetContents h
print $ take 10 contents
hClose h
Iteratee IO provides a declarative way to do this that is safe, compositional
and efficient. But not yet very pretty. In haskell cafe, John Lato says that
he is working on that.
____________________
David Place
Owner, Panpipes Ho! LLC
http://panpipesho.com
[email protected]
------------------------------
Message: 8
Date: Sun, 26 Jun 2011 22:59:19 +0200
From: Manfred Lotz <[email protected]>
Subject: Re: [Haskell-beginners] A first try
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=US-ASCII
On Sun, 26 Jun 2011 15:02:07 -0400
David Place <[email protected]> wrote:
>
> On Jun 26, 2011, at 1:29 PM, Manfred Lotz wrote:
>
> > When I stumbled upon lazy IO newbie-wise I was pointed to withFile
> > resp. bracket by Daniel Fischer and now that I know how to do it it
> > seems fine to me. It also alerted me to pay more attention to
> > lazyness as this is a Haskell immanent thingie.
>
> Of course, it is possible to use hGetContents with withFile. You can
> still get into trouble because hGetContents is unsafe. Beginners get
> tripped up trying to do something like the following getting
> unexpected results. (i remember I did.)
>
> print10 =
> do
> contents <- withFile "/usr/share/dict/words" ReadMode (\h ->
> hGetContents h) print $ take 10 contents
>
> So, you have to do this keeping in mind a rather procedural model of
> the evaluation of the lazy data structures. I feel this is not very
> declarative or intuitive.
>
> print10' =
> do
> h <- openFile "/usr/share/dict/words" ReadMode
> contents <- hGetContents h
> print $ take 10 contents
> hClose h
>
> Iteratee IO provides a declarative way to do this that is safe,
> compositional and efficient. But not yet very pretty. In haskell
> cafe, John Lato says that he is working on that.
>
>
Thanks for showing this. I have to admit that I'm as a beginner not in
a position to judge about the merits of Iteratee IO versus the standard
way. Just wanted to point out that the way I work thru the XML files in
my particular task seems to work fine. I will watch what happens to
Iteratee IO.
Is there any problem in the code snippet I pasted? If so I would
like to get a hint of course.
--
Thanks,
Manfred
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 36, Issue 65
*****************************************