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

Reply via email to