Re: [Haskell-cafe] Byte Histogram

2011-03-31 Thread Gábor Lehel
On Thu, Mar 17, 2011 at 11:14 PM, Andrew Coppin
 wrote:
>>> Right. So somebody else came up with an idea similar to mine, but since
>>> nobody could agree on anything more than a rough idea, nothing actually
>>> got
>>> done...(?)
>>
>> Well, I also got the sense that it would be more than a little
>> nontrivial to implement. Or at least, someone was talking about how it
>> would be a good topic for writing a thesis about if someone managed to
>> figure how to do it. I suspect that if someone were to actually put in
>> the effort they would be afforded the privilege of getting to nail
>> down the details. That's just completely baseless speculation, though.
>
> That sounds like a good description for just about every imaginable
> extension to Haskell that does something interesting! :-D

Turns out people *have* already written papers related to the topic.

Stefan Holdermans: Making Stricterness More Relevant
http://www.holdermans.nl/pubs/assets/holdermans10making-slides.pdf
http://www.holdermans.nl/pubs/assets/holdermans10making.pdf

Max Bolingbroke, Simon Peyton Jones: Types are Calling Conventions
http://www.cl.cam.ac.uk/~mb566/papers/tacc-hs09.pdf

The latter is particularly fascinating.

>
> ___
> Haskell-Cafe mailing list
> Haskell-Cafe@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>



-- 
Work is punishment for failing to procrastinate effectively.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-03-17 Thread Andrew Coppin

Right. So somebody else came up with an idea similar to mine, but since
nobody could agree on anything more than a rough idea, nothing actually got
done...(?)


Well, I also got the sense that it would be more than a little
nontrivial to implement. Or at least, someone was talking about how it
would be a good topic for writing a thesis about if someone managed to
figure how to do it. I suspect that if someone were to actually put in
the effort they would be afforded the privilege of getting to nail
down the details. That's just completely baseless speculation, though.


That sounds like a good description for just about every imaginable 
extension to Haskell that does something interesting! :-D


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-03-17 Thread Gábor Lehel
On Thu, Mar 17, 2011 at 10:37 PM, Andrew Coppin
 wrote:
> On 17/03/2011 12:11 PM, Gábor Lehel wrote:
>>
>> Necroing this thread because I just noticed there's a (rather old!)
>> bug report which covers much of the same ground and doesn't seem to
>> have been mentioned by anyone:
>>
>> http://hackage.haskell.org/trac/ghc/ticket/1349
>
> Right. So somebody else came up with an idea similar to mine, but since
> nobody could agree on anything more than a rough idea, nothing actually got
> done...(?)

Well, I also got the sense that it would be more than a little
nontrivial to implement. Or at least, someone was talking about how it
would be a good topic for writing a thesis about if someone managed to
figure how to do it. I suspect that if someone were to actually put in
the effort they would be afforded the privilege of getting to nail
down the details. That's just completely baseless speculation, though.

>
> ___
> Haskell-Cafe mailing list
> Haskell-Cafe@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>



-- 
Work is punishment for failing to procrastinate effectively.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-03-17 Thread Andrew Coppin

On 17/03/2011 12:11 PM, Gábor Lehel wrote:

Necroing this thread because I just noticed there's a (rather old!)
bug report which covers much of the same ground and doesn't seem to
have been mentioned by anyone:

http://hackage.haskell.org/trac/ghc/ticket/1349


Right. So somebody else came up with an idea similar to mine, but since 
nobody could agree on anything more than a rough idea, nothing actually 
got done...(?)


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-03-17 Thread Gábor Lehel
Necroing this thread because I just noticed there's a (rather old!)
bug report which covers much of the same ground and doesn't seem to
have been mentioned by anyone:

http://hackage.haskell.org/trac/ghc/ticket/1349


2011/2/8 Gábor Lehel :
> 2011/2/8 Ketil Malde :
>> Gábor Lehel  writes:
>>
>>> Is there any sensible meaning for bangs on return types? I've been
>>> trying to think this through but not necessarily succeeding.
>>
>> Not knowing Clean in any detail, I've always just thought that a type
>> signature of, say:
>>
>>          something :: !Foo -> Bar
>>
>> would mean the same as, in Haskell:
>>
>>          something :: Foo -> Bar
>>          something foo = foo `seq` ...
>>
>> In this case, there's no point to a strict return type, since it would
>> boil down to "x `seq` x", which is just  "x".
>
> Yeah, this is what I keep arriving at as well, I'm not sure if there's
> another option I might be missing...
>
>>
>> But it seems that a lot of these discussions are about considering Foo
>> and !Foo distinct types, which would mean that you can no longer, say,
>> add a strict and a lazy integer - at least not with the current Num
>> instance.  I find this line of thought very confusing.
>
> As I would ideally imagine it, again, strictness would be entirely
> orthogonal to the 'normal' part of the type. So you could combine Foo
> and !Foo completely freely as if the ! had never been there. !Foo
> would be a subtype of Foo, so to speak -- !Foo representing evaluated
> values, and Foo representing either evaluated or unevaluated values.
> The ! would be an instruction to the compiler/runtime, "make sure the
> Foo is evaluated by this point", and information for the programmer,
> "the Foo is certain to be evaluated by this point". Adding !s would
> only ever result in evaluation happening, and not ever a type error.
> The advantage over bang patterns would be that the time/place of
> evaluation could be controlled by the user rather than/in addition to
> the implementer of a function/type (or at least more flexibly and
> easily than it can be done now), it would more visible, obvious, and
> certain, and perhaps type inference/elaboration could even be done.
>
> But I'm minimally well-versed in compilers and type theory, so if
> someone sees something fundamentally wrong with this idea, please
> enlighten me.
>
>>
>>> This does seem a bit excessive. As a start, I don't remember anyone
>>> asking for control over (un)boxedness, so hopefully we could jettison
>>> that part of it?
>>
>> Uh, you mean like in IOUArrays, the UNPACK pragma, or
>> -funbox-strict-fields?  Unboxing is an important optimization, but
>> perhaps the current feature set suffices.
>
> Yeah, I meant within the current context. I don't recall hearing
> complaints that control over unboxing is currently insufficient or
> that unboxing is insufficiently predictable. (But if there have been,
> feel free to fill me in...)
>
>>
>> -k
>> --
>> If I haven't seen further, it is by standing in the footprints of giants
>>
>
>
>
> --
> Work is punishment for failing to procrastinate effectively.
>



-- 
Work is punishment for failing to procrastinate effectively.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-15 Thread Scott Turner
On 2011-02-11 02:06, wren ng thornton wrote:
> And it is clear
> that pointed and unpointed versions are different types[1]. 
...
> [1] Though conversion between them is easy. From unpointed to pointed is
> just a forgetful functor; from pointed to unpointed is the monad of
> evaluation.

I'm unskilled with categories.  For the monad of evaluation, don't the
category's objects need to be strict types?

There was an old thread in which Luke Palmer looked at an implementation
of (>>=) that uses seq to evaluate the left operand. He showed that it's
not a monad.

It would be nice to use a language with rich monads like Haskell, but
with an evaluation monad that fits together with a variety of monad
transformers.  I think this requires strict types. Adding them to
Haskell may not be achievable.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-10 Thread wren ng thornton

On 2/8/11 6:00 AM, Ketil Malde wrote:

This does seem a bit excessive. As a start, I don't remember anyone
asking for control over (un)boxedness, so hopefully we could jettison
that part of it?


Uh, you mean like in IOUArrays, the UNPACK pragma, or
-funbox-strict-fields?  Unboxing is an important optimization, but
perhaps the current feature set suffices.


As another issue to bear in mind, there is a big difference between 
strict types and unpointed types (either as types themselves, or as 
function spaces).


Semantically we have lots of reasons for wanting unpointed types--- that 
is, types which do not have bottom as an inhabitant. And it is clear 
that pointed and unpointed versions are different types[1]. One of the 
major issues looming here is the fact that unpointed types may not form 
domains, wreaks havoc for the domain theory semantics people often use 
for laziness. But at the same time, removing bottom can make it much 
easier to reason about things.


Strict types are, semantically, the same as unpointed types. And since 
Haskell is non-total, strict types are the only possible exact 
implementation of unpointed types (though decent type-checkable 
approximations may exist). However, operationally, strict types and 
unpointed types are quite different. In strict types we know that the 
value has been evaluated to WHNF (or some other normal form) and 
therefore we can avoid the computational cost of checking to ensure that 
it's been evaluated. Whereas unpointed types may not have been evaluated 
already, we simply know that when we do evaluate them we won't get 
bottom. Thus, unpointed types can allow us to have our laziness and... 
er, eat it too.


The arguments for having unpointed types (as opposed to strict types) 
are the same as the arguments for having laziness in the first place. 
Conversely, the arguments for having strict types (as opposed to 
unpointed types) are the same as the arguments for having strictness 
annotations of any kind. Both have their place, but we should be clear 
about what our goals are before choosing one or the other. Personally 
I'd like to have both, because they fill different needs, and because 
it's easy to automate the conversion between them[2].



[1] Though conversion between them is easy. From unpointed to pointed is 
just a forgetful functor; from pointed to unpointed is the monad of 
evaluation.


[2] Functions of strict arguments can be lifted to functions of 
unpointed arguments by simple wrappers to force argument evaluation. 
With strictness analysis, it can be possible to optimize the wrapper 
away and to call the strict-typed version directly. This is sort of like 
the SPECIALIZE pragmas.


We can also lift functions of unpointed arguments into functions of 
pointed arguments by changing the return type of the function to allow 
for bottom to be returned. Note that this requires that we distinguish 
pointed and unpointed types, not just pointed and unpointed function 
spaces. This is a natural consequence of the fact that evaluation is a 
monad, but it makes things get really hairy really quickly. Then again, 
that complexity may be unavoidable since we'd like to be able to have 
functions return strict and unpointed values just like they can return 
unboxed values.


--
Live well,
~wren

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-08 Thread John Lato
On Tue, Feb 8, 2011 at 12:33 PM, Ivan Lazar Miljenovic <
ivan.miljeno...@gmail.com> wrote:

> On 8 February 2011 23:25, John Lato  wrote:
> >> class Container c where
> >> type Elem c :: *
> >>
> >> class (Container cIn, Container cOut) => CMap cIn cOut where
> >> cmap :: (Elem cIn -> Elem cOut) -> cIn -> cOut
> >>
> >> instance (a ~ Elem (c a), b ~ Elem (c b), Functor c, Container (c a),
> >> Container (c b)) => CMap (c a) (c b) where
> >> cmap = fmap
>
> I'm not sure if that will work for types like Set, as you're not
> explicitly bringing the constraint in.


It won't work for Set, but Set's not a functor.  In this case just write
this instance instead:

> instance (Ord a, Ord b) => CMap (Set a) (Set b) where
> cmap = Set.map

John
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-08 Thread Ivan Lazar Miljenovic
On 8 February 2011 23:25, John Lato  wrote:
>> class Container c where
>>     type Elem c :: *
>>
>> class (Container cIn, Container cOut) => CMap cIn cOut where
>>     cmap :: (Elem cIn -> Elem cOut) -> cIn -> cOut
>>
>> instance (a ~ Elem (c a), b ~ Elem (c b), Functor c, Container (c a),
>> Container (c b)) => CMap (c a) (c b) where
>>     cmap = fmap

I'm not sure if that will work for types like Set, as you're not
explicitly bringing the constraint in.

-- 
Ivan Lazar Miljenovic
ivan.miljeno...@gmail.com
IvanMiljenovic.wordpress.com

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-08 Thread John Lato
On Mon, Feb 7, 2011 at 11:30 PM, Ivan Lazar Miljenovic <
ivan.miljeno...@gmail.com> wrote:

> On 8 February 2011 09:57, John Lato  wrote:
> > I think the real problem we have with container classes has a lot more to
> do
> > with what we would use them for.  That is, Haskell already has Monoid,
> > Foldable and Traversable.  These three (especially Foldable) cover nearly
> > everything OOP programmers would expect out of generic container
> operations.
>
> That was what my rewrite was going to be using.  The problem, however,
> is two-fold:
>
> * Dealing with types of kind * vs kind * -> *


> * Dealing with types of kind * -> * that have a restriction on the
> type parameter (e.g. Set).
>
> I was basing my approach on Ganesh's rmonad [1] library whilst taking
> into account the Functor => Applicative => Monad hierarchy when
> re-defining the classes, but the approach was very quickly becoming
> unwieldy.
>

 I think the Functor => Applicative => Monad hierarchy should be orthogonal
to container design.  Although many containers form useful monads, those
monads can have very different behavior (e.g. List and Set).  Therefore very
few (if any) algorithms can both be usefully polymorphic with respect to the
container instance and also take advantage of the monadic structure.  For
those algorithms this is useful, adding an extra Monad to the context is
entirely appropriate.

Probably more importantly, what users want from a container is often not
what the monad provides.  Although the List monad is very elegant, I usually
find the semantics of ZipList more useful.  This leads me to believe that
getting "singleton" and "<*>" from a class other than Applicative is the
correct approach.

Functor is generally better-suited to containers, except for types of kind *
that aren't functors.  I would suggest there's a better approach than the
rmonad machinery, perhaps something like this:

> class Container c where
> type Elem c :: *
>
> class (Container cIn, Container cOut) => CMap cIn cOut where
> cmap :: (Elem cIn -> Elem cOut) -> cIn -> cOut
>
> instance (a ~ Elem (c a), b ~ Elem (c b), Functor c, Container (c a),
Container (c b)) => CMap (c a) (c b) where
> cmap = fmap

Now we have the same operation which fmap provides, only we can define it
for any container type.  Better, we have an instance which is suitable for
all Functor instances, so we need only write instances for containers of
kind * (e.g. ByteString).

An annoyance with this approach is that the output type of cmap (c b) can't
be determined from the input function, so it's sometimes necessary to add
type annotations.  I think this can be solved by using bidirectional fundeps
instead of associated types though.

If you design container classes so that the element type is part of the
class instance, restrictions aren't a problem.  It's only when you try to
accommodate Functor etc. that workarounds such as rmonad become necessary.

John
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-08 Thread Gábor Lehel
2011/2/8 Ketil Malde :
> Gábor Lehel  writes:
>
>> Is there any sensible meaning for bangs on return types? I've been
>> trying to think this through but not necessarily succeeding.
>
> Not knowing Clean in any detail, I've always just thought that a type
> signature of, say:
>
>          something :: !Foo -> Bar
>
> would mean the same as, in Haskell:
>
>          something :: Foo -> Bar
>          something foo = foo `seq` ...
>
> In this case, there's no point to a strict return type, since it would
> boil down to "x `seq` x", which is just  "x".

Yeah, this is what I keep arriving at as well, I'm not sure if there's
another option I might be missing...

>
> But it seems that a lot of these discussions are about considering Foo
> and !Foo distinct types, which would mean that you can no longer, say,
> add a strict and a lazy integer - at least not with the current Num
> instance.  I find this line of thought very confusing.

As I would ideally imagine it, again, strictness would be entirely
orthogonal to the 'normal' part of the type. So you could combine Foo
and !Foo completely freely as if the ! had never been there. !Foo
would be a subtype of Foo, so to speak -- !Foo representing evaluated
values, and Foo representing either evaluated or unevaluated values.
The ! would be an instruction to the compiler/runtime, "make sure the
Foo is evaluated by this point", and information for the programmer,
"the Foo is certain to be evaluated by this point". Adding !s would
only ever result in evaluation happening, and not ever a type error.
The advantage over bang patterns would be that the time/place of
evaluation could be controlled by the user rather than/in addition to
the implementer of a function/type (or at least more flexibly and
easily than it can be done now), it would more visible, obvious, and
certain, and perhaps type inference/elaboration could even be done.

But I'm minimally well-versed in compilers and type theory, so if
someone sees something fundamentally wrong with this idea, please
enlighten me.

>
>> This does seem a bit excessive. As a start, I don't remember anyone
>> asking for control over (un)boxedness, so hopefully we could jettison
>> that part of it?
>
> Uh, you mean like in IOUArrays, the UNPACK pragma, or
> -funbox-strict-fields?  Unboxing is an important optimization, but
> perhaps the current feature set suffices.

Yeah, I meant within the current context. I don't recall hearing
complaints that control over unboxing is currently insufficient or
that unboxing is insufficiently predictable. (But if there have been,
feel free to fill me in...)

>
> -k
> --
> If I haven't seen further, it is by standing in the footprints of giants
>



-- 
Work is punishment for failing to procrastinate effectively.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-08 Thread Ketil Malde
Gábor Lehel  writes:

> Is there any sensible meaning for bangs on return types? I've been
> trying to think this through but not necessarily succeeding.

Not knowing Clean in any detail, I've always just thought that a type
signature of, say:

  something :: !Foo -> Bar

would mean the same as, in Haskell:

  something :: Foo -> Bar
  something foo = foo `seq` ...

In this case, there's no point to a strict return type, since it would
boil down to "x `seq` x", which is just  "x".

But it seems that a lot of these discussions are about considering Foo
and !Foo distinct types, which would mean that you can no longer, say,
add a strict and a lazy integer - at least not with the current Num
instance.  I find this line of thought very confusing.

> This does seem a bit excessive. As a start, I don't remember anyone
> asking for control over (un)boxedness, so hopefully we could jettison
> that part of it?

Uh, you mean like in IOUArrays, the UNPACK pragma, or
-funbox-strict-fields?  Unboxing is an important optimization, but
perhaps the current feature set suffices.

-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] Byte Histogram

2011-02-08 Thread Gábor Lehel
2011/2/7 Richard O'Keefe :
>
> On 8/02/2011, at 3:47 AM, Gábor Lehel wrote:
>>
>> I dunno. As a language extension, would - let's call it BangTypes - be
>> backwards-incompatible in any way?
>
> Let's look at an intermediate step first, BangFunctions.
>
> What this does is to say that there are two versions of "->":
>
>   t1 -> t2
>
>      What we have right now, which might be evaluated or not.
>
>   !t1 -> t2
>
>      The function wants its argument evaluated.  Suppose f is a
>      value of this type.  Then a use of f is rather like a
>      use of (\x -> x `seq` f x) and we can already write that.
>
> Now if you write
>
>        f :: !t1 -> t2
>        f p1 = e1
>        ...
>        f pn = en
>
> you're making the function strict whether it would have been strict
> or lazy.  But again, with BangPatterns we can already do that:
>
>        f !(p1) = e1
>        ...
>        f !(pn) = en
>
> The advantage of BangPatterns is that they can be precisely and
> selectively located.
>
> The advantages of BangFunctions include
>  - the forced strictness is part of the function's (published)
>   *interface*, not its implementation
>  - the question of what happens if some patterns for an argument
>   are banged and some are not does not arise (I *think* that this
>   can avoid some mistakes)
>  - it's compatible with BangTypes but simpler.
>
> So in some sense there is (now) nothing new here *except* putting
> the information where people can easily see it.

Perhaps the compiler could even do inference, showing bangs on those
parameters in which the function is (detectably) always strict? This
vaguely reminds me of type elaboration in Disciple (at least, that's
where I encountered it), in that even if you manually supply a type
signature for your function as Foo -> Bar without bangs, if in
practice it is strict in the Foo parameter, the type is actually !Foo
-> Bar. And presumably the compiler could infer that -- the strictness
properties are orthogonal in a sense to the rest of the type, so
underspecifying them is not an error, and the compiler could fill the
additional information in automatically where available. (Again this
is only if evaluation were to happen implicitly where required by the
types, so that !Foo -> Bar would equivalently mean "applying this
function to the argument results in the argument being evaluated"
whether the bang was supplied or inferred.)

Is there any sensible meaning for bangs on return types? I've been
trying to think this through but not necessarily succeeding.

Perhaps instead of all this inquiring and conjecturing it might be
easier to just read up on how Clean does it... :-)

>
> BangTypes could be rather more complicated.  Clean 2 offers
> lazy, head strict spine lazy, head lazy spine strict, head and spine
> strict, head unboxed spine lazy, head unboxed spine strict
> for lists, which are all different types; it also offers
> strictness-polymorphic lists.  I never actually made use of this
> because having so many kinds of list made my head spin.
> Roughly speading, Clean 1 had BangFunctions, Clean 2 BangTypes.

This does seem a bit excessive. As a start, I don't remember anyone
asking for control over (un)boxedness, so hopefully we could jettison
that part of it?

The dichotomy between head-strict (WHNF) and spine-strict seems
potentially more meaningful though. I could easily imagine wanting to
specify a type as being WHNF (so as to avoid accumulating thunks)
while still allowing it to be spine-lazy; are there any use cases for
the reverse, not-necessarily-evaluated but
spine-strict-once-evaluated? If there aren't, we could use ! for
head-strict, and !! for both head- and spine-strict (to borrow syntax
I saw proposed for 'hyperstrictness' somewhere). Maybe this is still
more complexity than desirable (ideally there would be only !...), but
the problems with insufficient predictability of and control over
evaluation seem very real, so if (_if_) this would go a significant
way towards alleviating that problem (in particular not having to
duplicate code N times for each desired combination of strictness and
laziness in container classes seems like it would be a win), then
maybe the extra complexity would be worth it.

>
> One of the things that makes me wary of BangPatterns is that it seems
> as though it's headed in a BangTypes kind of direction.
>
> Oh, by the way, I got the Clean syntax wrong.
> ![a] means "lazy list evaluated to WHNF";
> [a!] means "value is spine strict".
>
>



-- 
Work is punishment for failing to procrastinate effectively.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Johan Tibell
On Mon, Feb 7, 2011 at 11:57 PM, John Lato  wrote:
> I think the real problem we have with container classes has a lot more to do
> with what we would use them for.  That is, Haskell already has Monoid,
> Foldable and Traversable.  These three (especially Foldable) cover nearly
> everything OOP programmers would expect out of generic container operations.

Unfortunately using e.g. Foldable hurts performance a lot. We need to
look into inlining and specialization and move some functions (e.g.
foldl') into the type class if we want acceptable performance.

> What's missing are classes for specific data types.  That is, a Map/Dict
> interface, a Queue interface, and a Heap interface (probably others too, but
> these are the first that come to mind).  But the standard Data.Map and List
> (for a queue) seem good enough for most people, so there seems to be a lot
> of inertia to overcome for these to be popular.

I think the missing piece to make this abstraction worthwhile is a
second Map/Dict type worth using. Then there's a point in abstracting
over which type is actually used. In most OOP languages the two map
types are sorted and hashed maps.

Johan

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Ivan Lazar Miljenovic
On 8 February 2011 09:57, John Lato  wrote:
> I think the real problem we have with container classes has a lot more to do
> with what we would use them for.  That is, Haskell already has Monoid,
> Foldable and Traversable.  These three (especially Foldable) cover nearly
> everything OOP programmers would expect out of generic container operations.

That was what my rewrite was going to be using.  The problem, however,
is two-fold:

* Dealing with types of kind * vs kind * -> *

* Dealing with types of kind * -> * that have a restriction on the
type parameter (e.g. Set).

I was basing my approach on Ganesh's rmonad [1] library whilst taking
into account the Functor => Applicative => Monad hierarchy when
re-defining the classes, but the approach was very quickly becoming
unwieldy.

[1]: http://hackage.haskell.org/package/rmonad

-- 
Ivan Lazar Miljenovic
ivan.miljeno...@gmail.com
IvanMiljenovic.wordpress.com

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread John Lato
From: Johan Tibell 

>
> >
> > (The OOP people, of course, just don't bother trying. They use typecasts
> > everywhere...)
> >
> > Do associated types solve this? Or are there still problems?
>
> Duncan showed me a definition using associated types, which I have
> unfortunately forgotten.
>

Yes, associated types (or fundeps) solve this problem.  This problem of
container types is one of the motivating examples behind both extensions.

I think the real problem we have with container classes has a lot more to do
with what we would use them for.  That is, Haskell already has Monoid,
Foldable and Traversable.  These three (especially Foldable) cover nearly
everything OOP programmers would expect out of generic container operations.

What's missing are classes for specific data types.  That is, a Map/Dict
interface, a Queue interface, and a Heap interface (probably others too, but
these are the first that come to mind).  But the standard Data.Map and List
(for a queue) seem good enough for most people, so there seems to be a lot
of inertia to overcome for these to be popular.

John
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Richard O'Keefe

On 8/02/2011, at 10:43 AM, Roel van Dijk wrote:

> On 7 February 2011 22:00, Andrew Coppin  wrote:
>> I clearly have my languages mixed up.
>> 
>> The language I'm thinking of required all variables (even top-level ones) to
>> be declared with "let" - unless the definition is recursive, in which case
>> you have to say "letrec" (i.e., the compiler it too stupid to deduce this
>> automatically). Apparently that isn't Clean...
> 
> You are not necessarily wrong. 
> The Clean of 1987—1994 sounds a lot like the language you are
> talking about.
> 
> 1 - 
> http://www.cs.ru.nl/~thomas/publications/groj10-exchanging-sources-between.pdf

No, it doesn't.  Here's an example from
"Clean - A Language for Functional Graph Rewriting",
T.H. Brus, M.C.J.D. van Eekelen, M.O. van Leer, M.J. Plasmeijer,
a 1987 paper which I _think_ is the first one about Clean:

Start stdin -> Double (Add (Succ Zero) Zero);
Double a-> Add a a;
Add Zero n  ->n |
Add (Succ m) n  ->Succ (Add m n);

You will notice
 - an entire absence of 'let'
 - an entire absence of any 'letrec'

You'll also discover that Clean was originally
 - thought of as an intermediate language
 - a subset of something called LEAN

Clean 1 adopted Haskell-like syntax, but it was lazy from the beginning.




___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Evan Laforge
> The distinction between let and letrec predates OCAML.  Scheme does it too.

Haskell's choice of recursive everywhere is nice for the syntax, but
occasionally error prone.  I don't actually use explicit recursion too
often because there are functions for that, but I still occasionally
typo a variable name and make a circular reference, say naming a
function's output the same as one of its inputs.  If they're the same
type then you get that least-friendly of crashes: an error-less hang
with no indications about where it is.  It means you sometimes can't
reuse variable names when it would be better to shadow the old one and
sometimes wind up with tricks like 'x <- return $ f x'.

So there's a case to be made for letrec too.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Richard O'Keefe

On 8/02/2011, at 10:00 AM, Andrew Coppin wrote:
> I clearly have my languages mixed up.
> 
> The language I'm thinking of required all variables (even top-level ones) to 
> be declared with "let" - unless the definition is recursive, in which case 
> you have to say "letrec" (i.e., the compiler it too stupid to deduce this 
> automatically). Apparently that isn't Clean...

That sounds like an ML-family language, possibly OCAML.

However, this is *not* a question of stupidity.  It's a question of scope rules.

Example 1:

let f x = 1;;
let f x = if x = 0 then 0 else f x;;
f 3;;

This answers 1.

Example 2:

let f x = 1;;
let rec f x = if x = 0 then 0 else f x;;
f 3;;

This goes into an infinite loop.

If you don't like redeclaration, which is rather useful in an interactive
top level, try nested:

let f x = 1;;
let g y = let f x = if x = 0 then 0 else f x in f (f y);;

vs

let f x = 1;;
let g y = let rec f x = if x = 0 then 0 else f x in f (f y);;

The distinction between let and letrec predates OCAML.  Scheme does it too.


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Roel van Dijk
On 7 February 2011 22:00, Andrew Coppin  wrote:
> I clearly have my languages mixed up.
>
> The language I'm thinking of required all variables (even top-level ones) to
> be declared with "let" - unless the definition is recursive, in which case
> you have to say "letrec" (i.e., the compiler it too stupid to deduce this
> automatically). Apparently that isn't Clean...

You are not necessarily wrong. Clean, like Haskell, is a moving
target. To quote the paper "Exchanging Sources Between Clean and
Haskell" [1]:

  The year of 1987 was a founding one for two pure, lazy, and
  strongly typed functional programming languages. Clean (Brus et
  al., 1987) was presented to the public for the first time and
  the first steps towards a common functional language, later
  named Haskell, were taken (Hudak et al., 2007).

  Clean was conceived at the Radboud University Nijmegen as a core
  language that is directly based on the computational model of
  functional term graph rewriting to generate efficient code. It
  also serves as an intermediate language for the compilation of
  other functional languages (Koopman and Nöcker, 1988;
  Plasmeijer and van Eekelen, 1993). For these reasons, it
  deliberately used a sparse syntax (van Eekelen et al., 1990):
  “... at some points one can clearly recognize that [..] Clean
  is a compromise between a functional programming language and
  an intermediate language used to produce efficient code. For
  instance, a minimal amount of syntactic sugar is added in [..]
  Clean.”. Later, the core language was sugared.

The Clean of 1987—1994 sounds a lot like the language you are
talking about.

1 - 
http://www.cs.ru.nl/~thomas/publications/groj10-exchanging-sources-between.pdf

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Johan Tibell
On Mon, Feb 7, 2011 at 10:01 PM, Andrew Coppin
 wrote:
>> I think haskell2010's type system is just not expressive enough to
>> create interface generic enough. It's not possible to create type class
>> which will work for both ByteStrings (or IntSet) and lists.
>
> It seems that most people agree: The reason why we don't have container
> classes is that it's difficult to define them in a completely type-safe
> mannar.
>
> (The OOP people, of course, just don't bother trying. They use typecasts
> everywhere...)
>
> Do associated types solve this? Or are there still problems?

Duncan showed me a definition using associated types, which I have
unfortunately forgotten.

Johan

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Richard O'Keefe

On 8/02/2011, at 3:47 AM, Gábor Lehel wrote:
> 
> I dunno. As a language extension, would - let's call it BangTypes - be
> backwards-incompatible in any way?

Let's look at an intermediate step first, BangFunctions.

What this does is to say that there are two versions of "->":

   t1 -> t2

  What we have right now, which might be evaluated or not.

   !t1 -> t2

  The function wants its argument evaluated.  Suppose f is a
  value of this type.  Then a use of f is rather like a
  use of (\x -> x `seq` f x) and we can already write that.

Now if you write

f :: !t1 -> t2
f p1 = e1
...
f pn = en

you're making the function strict whether it would have been strict
or lazy.  But again, with BangPatterns we can already do that:

f !(p1) = e1
...
f !(pn) = en

The advantage of BangPatterns is that they can be precisely and
selectively located.

The advantages of BangFunctions include
 - the forced strictness is part of the function's (published)
   *interface*, not its implementation
 - the question of what happens if some patterns for an argument
   are banged and some are not does not arise (I *think* that this
   can avoid some mistakes)
 - it's compatible with BangTypes but simpler.

So in some sense there is (now) nothing new here *except* putting
the information where people can easily see it.

BangTypes could be rather more complicated.  Clean 2 offers
lazy, head strict spine lazy, head lazy spine strict, head and spine
strict, head unboxed spine lazy, head unboxed spine strict
for lists, which are all different types; it also offers
strictness-polymorphic lists.  I never actually made use of this
because having so many kinds of list made my head spin.
Roughly speading, Clean 1 had BangFunctions, Clean 2 BangTypes.

One of the things that makes me wary of BangPatterns is that it seems
as though it's headed in a BangTypes kind of direction.

Oh, by the way, I got the Clean syntax wrong.
![a] means "lazy list evaluated to WHNF";
[a!] means "value is spine strict".


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Andrew Coppin

I think haskell2010's type system is just not expressive enough to
create interface generic enough. It's not possible to create type class
which will work for both ByteStrings (or IntSet) and lists.


It seems that most people agree: The reason why we don't have container 
classes is that it's difficult to define them in a completely type-safe 
mannar.


(The OOP people, of course, just don't bother trying. They use typecasts 
everywhere...)


Do associated types solve this? Or are there still problems?

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Andrew Coppin

Haskell en Clean are very much alike.


 From what I could determine from a basic Clean introduction, Clean is very 
*unlike* Haskell, having a far more verbose and low-level syntax. (E.g., the 
compiler can't even determine whether a binding is recursive or not for itself. 
You have to say that manually.)


I have no idea what you are talking about here.
Clean is _very_ Haskell-like, including typeclasses.

Here's the first few lines of code from a Clean file I wrote in 1998.


I clearly have my languages mixed up.

The language I'm thinking of required all variables (even top-level 
ones) to be declared with "let" - unless the definition is recursive, in 
which case you have to say "letrec" (i.e., the compiler it too stupid to 
deduce this automatically). Apparently that isn't Clean...


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Gábor Lehel
On Mon, Feb 7, 2011 at 1:36 PM, Jimbo Massive
 wrote:
> On 07/02/2011 11:40, Stephen Tetley wrote:
>
>> Interesting point, but excepting that its adding more complexity
>> Haskell type system, the Clean way of putting strictness information
>> into the type system seems preferable don't you think?
>
> If we were starting from a clean sheet (no pun intended) then yes, I
> would say this is unquestionably preferable.
>
> Given the amount of Haskell code out in the world, I'd expect people to
> argue against it, on the basis that fiddling with the types is quite a
> major change. (Though I would not necessarily be one of those people)

I dunno. As a language extension, would - let's call it BangTypes - be
backwards-incompatible in any way? As far as I understand it, 'banged'
types would accept only evaluated values, whereas 'unbanged' types
would accept either evaluated or unevaluated ones -- exactly as it is
now. So, given that none of the types in currently-existing Haskell
code are banged, the effect on them of enabling the extension should
be pretty more or less nil. And I think code with banged types would
still be completely interoperable with code without (at least if
evaluation happened implicitly wherever required) -- passing a value
of a banged type to a function expecting an unbanged one would have no
special effect, while passing a value of an unbanged type to a
function expecting a banged one would merely result in it being
evaluated.

The potentially disruptive effect I can think of is that currently
authors of data structures have full control over their strictness
(for good or ill), whereas with this extension their users would be
able to instantiate them to various varieties of strictness
themselves. I'm not sure if the implementations of the data structures
(or other external uses thereof) tend to depend on their assumed
strictness, and would break were it different? If that were the case
it might indeed be problematic, forcing people to distinguish between
'bang-safe' and 'bang-unsafe' code. But I don't know if this is the
case (or, for that matter, whether it's even possible for it to be the
case...).

One thing I'm unclear on is what precisely the meaning of banging a
type would be (or what the meaning is in Clean). Would !a indicate
that values of type !a must be evaluated to WHNF, that constructors of
!a which occur in a's definition recursively would be strict (as if
they had been declared with a bang pattern), or both? (Or something
else entirely?) You would need the second property to be able to
specify a spine-strict but element-lazy list (as opposed to merely a
non-bottom list) as ![a]; you would need the first for it to have any
effect on non-recursive types. Or would it have the first meaning for
type variables, and both meanings for concrete types?

>
> Regards,
> Jimbo
>
> ___
> Haskell-Cafe mailing list
> Haskell-Cafe@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>



-- 
Work is punishment for failing to procrastinate effectively.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Jimbo Massive
On 07/02/2011 11:40, Stephen Tetley wrote:

> Interesting point, but excepting that its adding more complexity
> Haskell type system, the Clean way of putting strictness information
> into the type system seems preferable don't you think?

If we were starting from a clean sheet (no pun intended) then yes, I
would say this is unquestionably preferable.

Given the amount of Haskell code out in the world, I'd expect people to
argue against it, on the basis that fiddling with the types is quite a
major change. (Though I would not necessarily be one of those people)

Regards,
Jimbo

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Ross Paterson
On Mon, Feb 07, 2011 at 11:05:53AM +, John Lato wrote:
> From: Ivan Lazar Miljenovic 
> 
> On 7 February 2011 12:30, wren ng thornton  wrote:
> > On 2/6/11 4:53 PM, Ivan Lazar Miljenovic wrote:
> >>
> >> On 7 February 2011 08:12, Alexey Khudyakov
> >> ?wrote:
> >>>
> >>> Also there is a container-classes package which provide set of type
> class
> >>> for containers.
> >>>
> >>> [1] http://hackage.haskell.org/package/container-classes
> >>
> >> Don't use that package: it's broken. ?I did start on a re-write that
> >> works (and there are similar libraries around that I believe do work),
> >> but gave up because it was a) too fiddly, and b) I decided that the
> >> use case I had for them wasn't worth it (as it would just make that
> >> library more complicated and difficult to use, possibly also less
> >> efficient). ?If anyone wants it I can certainly send them what I've
> >> got though.
> >
> > Any chance you could push a 0.0.0.1 version which tells people this, so
> that
> > they know to avoid it?
> 
> Didn't think about that; I'll try to do so tonight.
> 
> Perhaps a better approach would be to ask the hackage maintainer (Ross
> Patterson, if I'm not mistaken) to deprecate container-classes.

Done.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Stephen Tetley
On 7 February 2011 10:16, Jimbo Massive  wrote:

> It's often struck me that, this information is clearly part of the
> interface to a function, given that correct operation of calls to that
> function may depend on it, yet we (implicitly) pretend that it's not (by
> rarely documenting it).
>
> Would it not be both incredibly useful and possible to automatically
> document information of this sort using tools like haddock?

Interesting point, but excepting that its adding more complexity
Haskell type system, the Clean way of putting strictness information
into the type system seems preferable don't you think?

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread John Lato
>
> From: Ivan Lazar Miljenovic 
>
> On 7 February 2011 12:30, wren ng thornton  wrote:
> > On 2/6/11 4:53 PM, Ivan Lazar Miljenovic wrote:
> >>
> >> On 7 February 2011 08:12, Alexey Khudyakov
> >> ?wrote:
> >>>
> >>> Also there is a container-classes package which provide set of type
> class
> >>> for containers.
> >>>
> >>> [1] http://hackage.haskell.org/package/container-classes
> >>
> >> Don't use that package: it's broken. ?I did start on a re-write that
> >> works (and there are similar libraries around that I believe do work),
> >> but gave up because it was a) too fiddly, and b) I decided that the
> >> use case I had for them wasn't worth it (as it would just make that
> >> library more complicated and difficult to use, possibly also less
> >> efficient). ?If anyone wants it I can certainly send them what I've
> >> got though.
> >
> > Any chance you could push a 0.0.0.1 version which tells people this, so
> that
> > they know to avoid it?
>
> Didn't think about that; I'll try to do so tonight.
>

Perhaps a better approach would be to ask the hackage maintainer (Ross
Patterson, if I'm not mistaken) to deprecate container-classes.

John
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Jimbo Massive
On 05/02/2011 15:35, Andrew Coppin wrote:

>> At the very
>> least we need to teach people how to tell which arguments a pure
>> function is strict in by looking at its definition.
> 
> That's not necessarily tractible. It depends on what other functions you
> call. Many functions have obvious strictness properties, but very few
> have *documented* strictness properties.

It's often struck me that, this information is clearly part of the
interface to a function, given that correct operation of calls to that
function may depend on it, yet we (implicitly) pretend that it's not (by
rarely documenting it).

Would it not be both incredibly useful and possible to automatically
document information of this sort using tools like haddock?  Obviously,
entirely accurate indicators of lazyness are not going to be computable,
but it seems like we could at least get information of the type
"argument never forced", "argument always forced", "argument may be
forced".  It seems like this would be a huge step forward - data
structures like map which are pure containers for their elements would
be clearly indicated as such in their documentation.

Jimbo

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-07 Thread Ketil Malde
Johan Tibell  writes:

>> The GHC documentation says the information is in the interface files,
>> but they are binary now, and I can't find it there.

> ghc --show-iface HI_FILE

> The strictness signatures are a bit hard to parse though. Having a
> cheat sheet would be nice.

Am I the only one who keep thinking it'd be great to have this
incorporated in my Emacs haskell-mode?  Along with a nice interface to
core, please.  And a pony.

-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] Byte Histogram

2011-02-06 Thread Richard O'Keefe

On 7/02/2011, at 8:41 AM, Andrew Coppin wrote:

> On 06/02/2011 09:13 AM, Roel van Dijk wrote:
> 
>> Haskell en Clean are very much alike.
> 
> From what I could determine from a basic Clean introduction, Clean is very 
> *unlike* Haskell, having a far more verbose and low-level syntax. (E.g., the 
> compiler can't even determine whether a binding is recursive or not for 
> itself. You have to say that manually.)

I have no idea what you are talking about here.
Clean is _very_ Haskell-like, including typeclasses.

Here's the first few lines of code from a Clean file I wrote in 1998.

// This is a 'data' declaration.
  :: ArrTree a
   = ArrEmpty
   | ArrLeaf a
   | ArrNode a (ArrTree a) (ArrTree a)

// The parentheses were not necessary
  empty :: (ArrTree a)
  empty = ArrEmpty

  asize :: (ArrTree a) -> Int
  asize (ArrEmpty)  = 0
  asize (ArrLeaf _) = 1
  asize (ArrNode _ l r) = 1 + asize l + asize r

// In Haskell it would be Int -> (ArrTree a) -> Bool.
// Leaving the first arrow out means that both arguments
// must be present in each rule.
// 'if' is a function.
  known :: Int (ArrTree a) -> Bool
  known i ArrEmpty= False
  known i (ArrLeaf _) = i == 1
  known i (ArrNode x l r) = i == 1 || known (i/2) (if (i mod 2 == 0) l r)

  fetch :: Int (ArrTree a) -> a
  fetch i (ArrLeaf x) | i == 1 = x
  fetch i (ArrNode x l r) | i == 1 = x
  | i mod 2 == 0 = fetch (i/2) l
  | otherwise= fetch (i/2) r

As for the compiler being unable to determine whether a binding is recursive,
I cannot find any such restriction in the Clean 2.1.1 manual and don't remember
one in Clean 1.  Here's an example straight out of the manual:

primes :: [Int]
primes = sieve [2..]
  where
sieve :: [Int] -> [Int]
sieve [pr:r] = [pr:sieve (filter pr r)]

filter :: Int [Int] -> [Int]
filter pr [n:r]
  | n mod pr == 0 = filter pr r
  | otherwise = [n:filter pr r]

Clean uses [head : tail] where Haskell uses (head : tail).
sieve and filter are both recursive (local) bindings, and the
compiler manages just FINE.

> It seems a very unecessarily complicated and messy language - which makes the 
> name rather ironic.

It would be if true.  There _are_ complexities in Clean, just as there are in
Haskell.  For the most part, they are the same complexities (laziness, type 
classes,
type inference, generic programming).

> As I say, I thought the main difference is that Clean is strict

Wrong.

> (which is why you can get good performance). Uniqueness typing is an 
> interesting idea, that looks like it might be useful for more than mere I/O.

It has been much used for arrays and records...


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Ivan Lazar Miljenovic
On 7 February 2011 12:30, wren ng thornton  wrote:
> On 2/6/11 4:53 PM, Ivan Lazar Miljenovic wrote:
>>
>> On 7 February 2011 08:12, Alexey Khudyakov
>>  wrote:
>>>
>>> Also there is a container-classes package which provide set of type class
>>> for containers.
>>>
>>> [1] http://hackage.haskell.org/package/container-classes
>>
>> Don't use that package: it's broken.  I did start on a re-write that
>> works (and there are similar libraries around that I believe do work),
>> but gave up because it was a) too fiddly, and b) I decided that the
>> use case I had for them wasn't worth it (as it would just make that
>> library more complicated and difficult to use, possibly also less
>> efficient).  If anyone wants it I can certainly send them what I've
>> got though.
>
> Any chance you could push a 0.0.0.1 version which tells people this, so that
> they know to avoid it?

Didn't think about that; I'll try to do so tonight.

-- 
Ivan Lazar Miljenovic
ivan.miljeno...@gmail.com
IvanMiljenovic.wordpress.com

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread wren ng thornton

On 2/6/11 4:53 PM, Ivan Lazar Miljenovic wrote:

On 7 February 2011 08:12, Alexey Khudyakov  wrote:

Also there is a container-classes package which provide set of type class
for containers.

[1] http://hackage.haskell.org/package/container-classes


Don't use that package: it's broken.  I did start on a re-write that
works (and there are similar libraries around that I believe do work),
but gave up because it was a) too fiddly, and b) I decided that the
use case I had for them wasn't worth it (as it would just make that
library more complicated and difficult to use, possibly also less
efficient).  If anyone wants it I can certainly send them what I've
got though.


Any chance you could push a 0.0.0.1 version which tells people this, so 
that they know to avoid it?


--
Live well,
~wren

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Richard O'Keefe

On 6/02/2011, at 4:21 AM, Andrew Coppin wrote:
> I didn't think Clean supported laziness at all? I thought it was a strict 
> language.

Absolutely not.  Back in the Good Old Days the one thing that
used to keep on tripping me up is that
Haskellif e0 then e1 else e2
 <=>Clean  if e0 e1 e2

Now, in what kind of language can 'if' be a perfectly ordinary function?


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Ivan Lazar Miljenovic
On 7 February 2011 08:12, Alexey Khudyakov  wrote:
> Also there is a container-classes package which provide set of type class
> for containers.
>
> [1] http://hackage.haskell.org/package/container-classes

Don't use that package: it's broken.  I did start on a re-write that
works (and there are similar libraries around that I believe do work),
but gave up because it was a) too fiddly, and b) I decided that the
use case I had for them wasn't worth it (as it would just make that
library more complicated and difficult to use, possibly also less
efficient).  If anyone wants it I can certainly send them what I've
got though.

-- 
Ivan Lazar Miljenovic
ivan.miljeno...@gmail.com
IvanMiljenovic.wordpress.com

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Alexey Khudyakov

On 07.02.2011 00:37, Johan Tibell wrote:

Also there is a container-classes package which provide set of type class
for containers.


I'd like to avoid MPTC and fundeps if possible.

I think haskell2010's type system is just not expressive enough to 
create interface generic enough. It's not possible to create type class 
which will work for both ByteStrings (or IntSet) and lists.



___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Johan Tibell
On Sun, Feb 6, 2011 at 10:12 PM, Alexey Khudyakov
 wrote:
> Well Foldable and Traversable provide set of generic operations for
> containers. Although they are quite limited, containter must be polymorphic
> (e.g. no IntMap) and parameter must be of any type (e.g. no unboxed vectors)
> both are still quite useful.

I looked into providing instances for these but IIRC the performance
was really bad. Someone need to look at inlining/specialization for
these.

> Also there is a container-classes package which provide set of type class
> for containers.

I'd like to avoid MPTC and fundeps if possible.

Johan

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Alexey Khudyakov

On 06.02.2011 23:29, Johan Tibell wrote:

On Sun, Feb 6, 2011 at 8:48 PM, Andrew Coppin
  wrote:

In particular, I get strange looks from people in the OOP community when I
say I'm using a language that doesn't have any abstractions at all for
dealing polymorphically with containers. In general, it's almost impossible
to write a Haskell function that will work with a list, an (immutable)
array, a hash table or a map, polymorphically.


I think one reason we haven't seen a type class for containers is that
it isn't easy to create one using vanilla type classes (see Simon PJ's
paper on the topic.)

Well Foldable and Traversable provide set of generic operations for 
containers. Although they are quite limited, containter must be 
polymorphic (e.g. no IntMap) and parameter must be of any type (e.g. no 
unboxed vectors) both are still quite useful.


Also there is a container-classes package which provide set of type 
class for containers.


[1] http://hackage.haskell.org/package/container-classes

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Johan Tibell
On Sun, Feb 6, 2011 at 8:48 PM, Andrew Coppin
 wrote:
> In particular, I get strange looks from people in the OOP community when I
> say I'm using a language that doesn't have any abstractions at all for
> dealing polymorphically with containers. In general, it's almost impossible
> to write a Haskell function that will work with a list, an (immutable)
> array, a hash table or a map, polymorphically.
>
> I guess it's the case that containers has been there so long now that
> changing it would break everything. Still, I find myself hungry for
> something better.
>
> Than again, the Prelude itself leaves several things to be desired...

I'm working on a new map data type at the moment, which is 2x faster
than Data.Map for all key types I've tried (i.e. Ints, Strings, and
ByteStrings). As part of that work I might try to define a map class
using associated data types. Data.Map can be made an instance of that
class without breaking any old code.

I think one reason we haven't seen a type class for containers is that
it isn't easy to create one using vanilla type classes (see Simon PJ's
paper on the topic.)

Johan

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Stephen Tetley
On 6 February 2011 19:41, Andrew Coppin  wrote:
. (E.g., the
> compiler can't even determine whether a binding is recursive or not for
> itself. You have to say that manually.) It seems a very unecessarily
> complicated and messy language - which makes the name rather ironic.


Erm - nope. Sure you haven't mixed OCaml and Clean to get OCClaeman?

Clean is a very clean language. The only thing I got tripped up on
were uniqueness and strict annotations (thanks to Richard O'Keefe
above in the thread, for useful clarification).

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Andrew Coppin

Random fact: Data.Map.insertWith' exists. Data.IntMap.insertWith' does *not*
exist.


The containers library is a mess.


I'm inclined to agree.

In particular, I get strange looks from people in the OOP community when 
I say I'm using a language that doesn't have any abstractions at all for 
dealing polymorphically with containers. In general, it's almost 
impossible to write a Haskell function that will work with a list, an 
(immutable) array, a hash table or a map, polymorphically.


I guess it's the case that containers has been there so long now that 
changing it would break everything. Still, I find myself hungry for 
something better.


Than again, the Prelude itself leaves several things to be desired...

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Andrew Coppin

On 06/02/2011 09:13 AM, Roel van Dijk wrote:


Haskell en Clean are very much alike.


From what I could determine from a basic Clean introduction, Clean is 
very *unlike* Haskell, having a far more verbose and low-level syntax. 
(E.g., the compiler can't even determine whether a binding is recursive 
or not for itself. You have to say that manually.) It seems a very 
unecessarily complicated and messy language - which makes the name 
rather ironic.



You can even compile Haskell 98
code with the latest (experimental) Clean compiler and having it
interact with Clean code and vice-versa [2]. The main difference is
Clean's use of uniqueness typing.


As I say, I thought the main difference is that Clean is strict (which 
is why you can get good performance). Uniqueness typing is an 
interesting idea, that looks like it might be useful for more than mere I/O.


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Gábor Lehel
On Thu, Feb 3, 2011 at 11:40 PM, Richard O'Keefe  wrote:
>
> On 4/02/2011, at 10:10 AM, Andrew Coppin wrote:
>>
>> The important obsevation is this: One tiny, almost insignificant change can 
>> transform a program from taking 50 seconds and 400 MB of RAM into one that 
>> takes 0.02 seconds and 0.1 MB of RAM. And, at least in this case, the 
>> simpler version is the slow one.
>>
>> To say that Haskell is "slow" is both a little bit vague, and not really 
>> backed up by facts. In about 5 minutes flat, I managed to write a Haskell 
>> program that's very simple, and yet faster than a comparably simple C++ 
>> program (and C++ is supposed to be "fast"). So it's not that Haskell is 
>> "slow". It's that Haskell is *tricky*. Tiny, tiny little changes that look 
>> innocuous can have vast effects on performance. And this is a nice little 
>> example of that effect.
>
> This seems to me to be the heart of the message, so maybe this reply is 
> on-topic.
>
> Back in the days when systems other than Wintel and maybe sort of intel Linux 
> were
> supported by Clean, I used to really love one of the features of the Clean 
> compiler.
> One simple command line switch and the compiler would list the names of all 
> your
> top level functions together with their types, and the types included 
> strictness.
> (Also uniqueness, not relevant to Haskell.)
>
> The GHC documentation says the information is in the interface files,
> but they are binary now, and I can't find it there.
>
>> That got me thinking... What would happen if, instead of "Integer", we had 
>> two types, "evaluated Integer" and "possibly unevaluated Integer"? What if 
>> the strictness or otherwise of a data structure were exposed at the type 
>> level?
>
> Oh, you mean like "!Int" and "Int" in Clean?  I used to find bang *types* 
> rather easier to deal with
> than I now do bang *patterns*.
>
>> Currently, if you want a strict list, you have to implement one yourself. 
>> But is that strict in the spine, or the elements, or what?
>
> Spine strict: ![t].
> Spine and element strict: ![!t].

This does seem like a very appealing idea (to me), especially if
evaluation were to happen implicitly wherever the types require it.
Are there any major obstacles or philosophical objections to it other
than available time and manpower?


>>
>> I have no idea what the syntax for that would look like,
>
> Clean?
>
>
>
> ___
> Haskell-Cafe mailing list
> Haskell-Cafe@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>



-- 
Work is punishment for failing to procrastinate effectively.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Johan Tibell
On Sat, Feb 5, 2011 at 4:16 PM, Andrew Coppin
 wrote:
> Random fact: Data.Map.insertWith' exists. Data.IntMap.insertWith' does *not*
> exist.

The containers library is a mess. For example, Data.Map has 10+
functions (e.g. adjust) that don't have strict counterparts even
though the strict version is most likely what you want. Some functions
do allow you to force the value before it's inserted into the map just
because you can piggy-back on the evaluation of a constructor e.g.

update :: Ord k => (a -> Maybe a) -> k -> Map k a -> Map k a

f = update g someKey someMap
  where g = (\ v -> let v' = v + 1 in v' `seq` Just v')

Since the implementation must evaluate the result of g to decide
whether to remove the element or not.

Johan

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Roel van Dijk
On 5 February 2011 16:21, Andrew Coppin  wrote:
> I didn't think Clean supported laziness at all? I thought it was a strict
> language.

"CLEAN is a practical applicable general-purpose lazy pure functional
programming language suited for the development
of real world applications." [1]

Haskell en Clean are very much alike. You can even compile Haskell 98
code with the latest (experimental) Clean compiler and having it
interact with Clean code and vice-versa [2]. The main difference is
Clean's use of uniqueness typing.


1 - http://clean.cs.ru.nl/download/Clean20/doc/CleanLangRep.2.1.pdf
2 - 
http://www.cs.ru.nl/~thomas/publications/groj10-exchanging-sources-between.pdf

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-06 Thread Bernie Pope
On 6 February 2011 02:40, Andrew Coppin  wrote:

> Then again, if you could actually single-step through a Haskell program's
> execution, most strictness issues would become quite shallow.

You can single-step through a Haskell program's execution with the
GHCi debugger. It can provide considerable insight into evaluation
order.

A proper stack tracer would make it even more useful.

Cheers,
Bernie.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-05 Thread Andrew Coppin

On 04/02/2011 07:30 AM, Johan Tibell wrote:


Right. It can still be tricky. I think we can get rid of a large
number of strictness issues by using strict data structures more
often, this should help beginners in particular. For the rest better
tooling would help. For example, a lint tool that marked up code with
the strictness information inferred by the compiler would be useful. I
had time to write one I would make the output look like HPC html
reports, with one color for strict function arguments and one color
for lazy function arguments.


There's the RTS watch that makes it spit out heap profiling information. 
However, determining what the hell this data actually means is well 
beyond my powers of comprehension.


I keep hoping that eventually the mechanism used by ThreadScope will 
eventually allow you to compile a program with profiling, run it, and 
observe absolutely everything about its execution - how many cores it's 
using, how much RAM is allocated to each generation, etc.


Then again, if you could actually single-step through a Haskell 
program's execution, most strictness issues would become quite shallow. 
Indeed, when I first learned Haskell, the very concept of lazyness ever 
being "detrimental" was incomprehensible to me. I couldn't imagine why 
you would ever want to turn it off. But then I built a simple program 
that single-steps through Haskell(ish) expressions, and suddenly 
discovered that foldl' needs to exist...


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-05 Thread Andrew Coppin

For what it's worth I saw the problems in your counting examples right
away, without reading the explanatory text below.


Yes, they were pretty obvious with enough experience. For beginners I
expect it to be a rather insidious trap.


Beginners or anybody coding Haskell while not completely awake. ;-)


Hopefully that means
that it's possibly to learn how to spot such things without resorting
to e.g. running the program or reading Core *gasp*.


Within limits. Detrimental laziness or strictness can be arbitrarily well
hidden.


I agree. Unfortunately... :-/

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-05 Thread Andrew Coppin

On 03/02/2011 10:15 PM, Johan Tibell wrote:


First, we need to stop pretending that you can use Haskell effectively
without first learning to reason about program evaluation order.


Writing a program in *any* language without understanding the 
performance implications of different language constructs is unlikely to 
produce performant code. OTOH, Haskell is unusual in just how easily 
seemingly trivial alternations of a few characters can cause utterly 
*giagintic* performance differences in both time and space.



Learning how is not terrible difficult, but there's very little
material on how to do it [1]. Some of us have learnt it the hard way
by experimentation or by talking to people who do understand lazy
evaluation [2] (the Simons, Don, and Bryan to name a few).


I think perhaps the problem is that Haskell's execution model is so 
utterly *implicit*. In some imperative languag, if you call an expensive 
function, it will be expensive. In Haskell, if you call an expensive 
function and then never touch the result, it's cheap. Touch the result 
once, and you might get fusion. Touch it twice and suddenly the space 
complexity of the program changes. So simply adding a debug statement 
can utterly transform your program's runtime.


What it comes down to is: Tiny changes sometimes have profound effects.

Best of all, there is little tool support for detecting these effects. 
If you change your program and it suddenly slows down, you need to go 
look at what you just changed. But if you write a brand new program and 
it's drop-dead slow, where do you start looking? (Assuming you're not 
writing a micro-benchmark.)



At the very
least we need to teach people how to tell which arguments a pure
function is strict in by looking at its definition.


That's not necessarily tractible. It depends on what other functions you 
call. Many functions have obvious strictness properties, but very few 
have *documented* strictness properties.



That keeping a simple map of counters is tricky should tell us
that something is wrong.


Agreed.


Many strictness related problems
people have are due to common data types like Maybe, tuples, and
arrays being lazy. This is rarely what you want.


I'm not sure that's 100% true. You might have a function that returns a 
tuple, and on occasion you're only actually interested in one of the two 
results. But that looks like the exception rather than the rule.


Lazy lists are rather useful, but it looks like strict lists would be 
useful too. The number of times I've written !String and then thought 
"hey, wait, that's not helping me..."


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-05 Thread Andrew Coppin

That got me thinking... What would happen if, instead of "Integer", we had two types, 
"evaluated Integer" and "possibly unevaluated Integer"? What if the strictness or 
otherwise of a data structure were exposed at the type level?


Oh, you mean like "!Int" and "Int" in Clean?  I used to find bang *types* 
rather easier to deal with
than I now do bang *patterns*.


I have no idea what the syntax for that would look like,


Clean?


I didn't think Clean supported laziness at all? I thought it was a 
strict language.


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-05 Thread Andrew Coppin

On 03/02/2011 09:37 PM, Daniel Fischer wrote:

To illustrate your prediction about the side-issues:

On Thursday 03 February 2011 22:10:51, Andrew Coppin wrote:

Consider for a moment the original implementation with Data.Map. Adding
a seq or two here will do no good at all; seq reduces to WHNF. What we
are wanting is NF, and I can see no way at all of doing that.


Check out Data.Map.insertWith'


Random fact: Data.Map.insertWith' exists. Data.IntMap.insertWith' does 
*not* exist.


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-05 Thread Janis Voigtländer

On 2/5/11 4:26 AM, Claus Reinke wrote:

Lately I've been trying to go the other direction: make a large
section of formerly strict code lazy.


There used to be a couple of tools trying to make suggestions when a
function could be made less strict (Olaf Chitil's StrictCheck and
another that escapes memory at the moment).


Probably Sloth:

http://korsika.informatik.uni-kiel.de/~jac/wordpress/
http://korsika.informatik.uni-kiel.de/~jac/wordpress/wp-content/uploads/PADL2011.pdf

Best,
Janis.

--
Jun.-Prof. Dr. Janis Voigtländer
http://www.iai.uni-bonn.de/~jv/
mailto:j...@iai.uni-bonn.de

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-05 Thread wren ng thornton

On 2/5/11 4:26 AM, Claus Reinke wrote:

Lately I've been trying to go the other direction: make a large
section of formerly strict code lazy.


There used to be a couple of tools trying to make suggestions
when a function could be made less strict (Olaf Chitil's StrictCheck and
another that escapes memory at the moment).


Perhaps you're thinking of the chasing bottoms[1] library?

[1] http://hackage.haskell.org/package/ChasingBottoms

--
Live well,
~wren

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-05 Thread Claus Reinke

Lately I've been trying to go the other direction: make a large
section of formerly strict code lazy.  


There used to be a couple of tools trying to make suggestions
when a function could be made less strict (Olaf Chitil's StrictCheck 
and another that escapes memory at the moment). Often, it

comes down to some form of eta-expansion - making information
available earlier [(\x->f x) tells us we have a function without
having to evaluate f, (\p->(fst p,snd p)) marks a pair without
needing to evaluate p, and so on].

I fully agree that once code size gets big these problems get a lot 
harder.  You have to be very careful passing around state that you 
don't do anything that causes too much to be evaluated at the 
wrong time.  


Generally, the trick is to develop an intuitition early, before
growing the program in size;-) However, as long as you can
run your big code with small data sets, you might want to try
GHood, maintained on hackage thanks to Hugo Pacheco:

   http://hackage.haskell.org/package/GHood
   http://community.haskell.org/~claus/GHood/ (currently unavailable:-(

The latter url has a few examples and a paper describing how
GHood can be useful for observing relative strictness, ie, when
data at one probe is forced relative to when it is forced at another.

(it seems that citeseerx has a copy of the paper, at least:
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.132.1397 )

For instance, if you put one probe on the output and one on the
input, you can see which parts of the input are forced to produce
which parts of the output. As I said, small data sets help, but since
you put in probes manually and selectively, large code size should
not interfere with observations (though it might hinder intuition:-).


But there's definitely a knack to be learned, and I think I might
eventually get better at it.  For example, I realized that the
criteria to make something non-strict wrt data dependency are the same
as trying to parallelize.  Sometimes it's easier to think "what do I
have to do to make these two processes run in parallel" and that's the
same thing I have to do to make them interleave with each other
lazily.


Sometimes, I think of non-strict evaluation as "spark a thread for
everything, then process the threads with a single processor"..

Claus


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-04 Thread Evan Laforge
On Thu, Feb 3, 2011 at 3:38 PM, Erik de Castro Lopo
 wrote:
> I am a relative newcomer to Haskell, but I think I have a reasonable
> understanding of the executaion model. Enough to fix performance
> issues in simple code like the example given.
>
> However, one of the Haskell projects I work on is Ben Lippmeier's
> DDC compiler. Thats about 5 lines of Haskell code and finding
> performance issues there is really difficult.

Lately I've been trying to go the other direction: make a large
section of formerly strict code lazy.  I fully agree that once code
size gets big these problems get a lot harder.  You have to be very
careful passing around state that you don't do anything that causes
too much to be evaluated at the wrong time.  E.g., you can put back
the final result of a mapAccumL into a StateT but you want to make
sure it doesn't get looked at until the output of the mapAccumL would
be evaluated.  Even something seemingly innocuous like bundling it
into a newtype will cause the mapAccumL to run over the entire list
and evaluate a bunch of stuff too early and probably wind up with a
bunch of lag.  And the only way I can think of to find out what order
these things are running is to throw and infinite list and see if they
hang or put in a bunch of unsafePerformIO logging... not very
satisfying in either case, especially when trying to inspect things
can change the evaluation order.

Sometimes I wonder what this would look like if I were generating
incremental output with python yields... while getting the data
dependencies right is essential in any case, I'm suspicious it would
be easier to think about and understand in a strict language.

But there's definitely a knack to be learned, and I think I might
eventually get better at it.  For example, I realized that the
criteria to make something non-strict wrt data dependency are the same
as trying to parallelize.  Sometimes it's easier to think "what do I
have to do to make these two processes run in parallel" and that's the
same thing I have to do to make them interleave with each other
lazily.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-04 Thread Richard O'Keefe

On 4/02/2011, at 8:26 PM, Johan Tibell wrote:

> --show-iface HI_FILE

sort.hs has 50 top level functions.
One of them is main, and the others are all reachable from it.

ghc -O sort.hs
ghc --show-iface sort.hi

The only functions listed are variants of main.
Dropping -O leaves one variant of main only;
the other 49 functions have disappeared.

It is, by the way, something of a nuisance that if you do
ghc sort.hs
...
ghc -O sort.hs
it insists "compilation NOT required" despite the fact that
the previous compilation was with materially *different* options.
(GHC 6.12.3)

Given this clue I was able to get the information I wanted by
exporting all the functions.

This is the wrong interface.  If a programmer is concerned that
strictness analysis might not be finding something they thought
was strict, they would ideally like to have *all* the functions
reported, but at a minimum, all of the top level functions.



___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-04 Thread Jake McArthur

On 02/03/2011 03:10 PM, Andrew Coppin wrote:

(Unless you're seriously going to suggest that GHC's native code
generator is any match for the might of a half-decent C compiler...)


I don't know enough about the native code generator to make a claim like 
that, but we're not comparing the native code generator against a C 
compiler; we're comparing it against a C code generator whose output is 
fed through a C compiler. These are very different things, and I think 
it gives the native code generator an edge. My own observations from 
immediately before the C backend was deprecated was that the native code 
generator averaged slightly better performing code.


- Jake

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-03 Thread Johan Tibell
On Fri, Feb 4, 2011 at 12:38 AM, Erik de Castro Lopo
 wrote:
> However, one of the Haskell projects I work on is Ben Lippmeier's
> DDC compiler. Thats about 5 lines of Haskell code and finding
> performance issues there is really difficult.

Right. It can still be tricky. I think we can get rid of a large
number of strictness issues by using strict data structures more
often, this should help beginners in particular. For the rest better
tooling would help. For example, a lint tool that marked up code with
the strictness information inferred by the compiler would be useful. I
had time to write one I would make the output look like HPC html
reports, with one color for strict function arguments and one color
for lazy function arguments.

Johan

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-03 Thread Johan Tibell
On Thu, Feb 3, 2011 at 11:40 PM, Richard O'Keefe  wrote:
> Back in the days when systems other than Wintel and maybe sort of intel Linux 
> were
> supported by Clean, I used to really love one of the features of the Clean 
> compiler.
> One simple command line switch and the compiler would list the names of all 
> your
> top level functions together with their types, and the types included 
> strictness.
> (Also uniqueness, not relevant to Haskell.)
>
> The GHC documentation says the information is in the interface files,
> but they are binary now, and I can't find it there.

ghc --show-iface HI_FILE

The strictness signatures are a bit hard to parse though. Having a
cheat sheet would be nice.

Johan

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-03 Thread Erik de Castro Lopo
Daniel Fischer wrote:

> On Thursday 03 February 2011 23:19:31, Johan Tibell wrote:
> > Hi,
> >
> > For what it's worth I saw the problems in your counting examples right
> > away, without reading the explanatory text below.
> 
> Yes, they were pretty obvious with enough experience. For beginners I 
> expect it to be a rather insidious trap.
> 
> > Hopefully that means
> > that it's possibly to learn how to spot such things without resorting
> > to e.g. running the program or reading Core *gasp*.
> 
> Within limits. Detrimental laziness or strictness can be arbitrarily well 
> hidden.

I am a relative newcomer to Haskell, but I think I have a reasonable
understanding of the executaion model. Enough to fix performance
issues in simple code like the example given.

However, one of the Haskell projects I work on is Ben Lippmeier's
DDC compiler. Thats about 5 lines of Haskell code and finding
performance issues there is really difficult. 

Erik
-- 
--
Erik de Castro Lopo
http://www.mega-nerd.com/

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-03 Thread Richard O'Keefe

On 4/02/2011, at 10:10 AM, Andrew Coppin wrote:
> 
> The important obsevation is this: One tiny, almost insignificant change can 
> transform a program from taking 50 seconds and 400 MB of RAM into one that 
> takes 0.02 seconds and 0.1 MB of RAM. And, at least in this case, the simpler 
> version is the slow one.
> 
> To say that Haskell is "slow" is both a little bit vague, and not really 
> backed up by facts. In about 5 minutes flat, I managed to write a Haskell 
> program that's very simple, and yet faster than a comparably simple C++ 
> program (and C++ is supposed to be "fast"). So it's not that Haskell is 
> "slow". It's that Haskell is *tricky*. Tiny, tiny little changes that look 
> innocuous can have vast effects on performance. And this is a nice little 
> example of that effect.

This seems to me to be the heart of the message, so maybe this reply is 
on-topic.

Back in the days when systems other than Wintel and maybe sort of intel Linux 
were
supported by Clean, I used to really love one of the features of the Clean 
compiler.
One simple command line switch and the compiler would list the names of all your
top level functions together with their types, and the types included 
strictness.
(Also uniqueness, not relevant to Haskell.)

The GHC documentation says the information is in the interface files,
but they are binary now, and I can't find it there.

> That got me thinking... What would happen if, instead of "Integer", we had 
> two types, "evaluated Integer" and "possibly unevaluated Integer"? What if 
> the strictness or otherwise of a data structure were exposed at the type 
> level?

Oh, you mean like "!Int" and "Int" in Clean?  I used to find bang *types* 
rather easier to deal with
than I now do bang *patterns*.

> Currently, if you want a strict list, you have to implement one yourself. But 
> is that strict in the spine, or the elements, or what?

Spine strict: ![t].
Spine and element strict: ![!t].
> 
> I have no idea what the syntax for that would look like,

Clean?



___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-03 Thread Daniel Fischer
On Thursday 03 February 2011 23:19:31, Johan Tibell wrote:
> Hi,
>
> For what it's worth I saw the problems in your counting examples right
> away, without reading the explanatory text below.

Yes, they were pretty obvious with enough experience. For beginners I 
expect it to be a rather insidious trap.

> Hopefully that means
> that it's possibly to learn how to spot such things without resorting
> to e.g. running the program or reading Core *gasp*.

Within limits. Detrimental laziness or strictness can be arbitrarily well 
hidden.


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-03 Thread Johan Tibell
Hi,

For what it's worth I saw the problems in your counting examples right
away, without reading the explanatory text below. Hopefully that means
that it's possibly to learn how to spot such things without resorting
to e.g. running the program or reading Core *gasp*.

Johan

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-03 Thread Johan Tibell
On Thu, Feb 3, 2011 at 11:10 PM, Andrew Coppin
 wrote:
> Wouldn't that still mean that the spine of the map is still lazy though?

No, Data.Map and Data.Set are both spine strict (which should be
documented!). Data.Map is key strict in addition. Both are value lazy.

Johan

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-03 Thread Johan Tibell
Hi,

Thanks for bringing up these issues. It's something we could be better
at addressing as a community.

First, we need to stop pretending that you can use Haskell effectively
without first learning to reason about program evaluation order.
Learning how is not terrible difficult, but there's very little
material on how to do it [1]. Some of us have learnt it the hard way
by experimentation or by talking to people who do understand lazy
evaluation [2] (the Simons, Don, and Bryan to name a few). At the very
least we need to teach people how to tell which arguments a pure
function is strict in by looking at its definition.

Second, many of our core data structures are lazy, but most uses are
strict. That keeping a simple map of counters is tricky should tell us
that something is wrong (you need to use insertWith'). It wouldn't be
if Data.Map was strict in the values. Many strictness related problems
people have are due to common data types like Maybe, tuples, and
arrays being lazy. This is rarely what you want.

1. I tried to start creating some. For example, by giving a high
performance Haskell talk at CUFP. Unfortunately the talk wasn't taped.
2. Haskell is non-strict, which doesn't necessarily imply lazy
evaluation. However, lazy evaluation is what we actually deal with.

Johan

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-03 Thread Andrew Coppin

On 03/02/2011 09:37 PM, Daniel Fischer wrote:

To illustrate your prediction about the side-issues:

On Thursday 03 February 2011 22:10:51, Andrew Coppin wrote:

Consider for a moment the original implementation with Data.Map. Adding
a seq or two here will do no good at all; seq reduces to WHNF. What we
are wanting is NF, and I can see no way at all of doing that.


Check out Data.Map.insertWith'


*facepalm*

Wouldn't that still mean that the spine of the map is still lazy though?

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Byte Histogram

2011-02-03 Thread Daniel Fischer
To illustrate your prediction about the side-issues:

On Thursday 03 February 2011 22:10:51, Andrew Coppin wrote:
> Consider for a moment the original implementation with Data.Map. Adding
> a seq or two here will do no good at all; seq reduces to WHNF. What we
> are wanting is NF, and I can see no way at all of doing that.

Check out Data.Map.insertWith'

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Byte Histogram

2011-02-03 Thread Andrew Coppin
There now follows a small grab-bag of miscelaneous but related thoughts. 
(Which probably means that this post will spawn a 2000 message thread 
discussing one tiny side-issue, rather than the main thrust of the 
message...)




First of all, benchmarking. We have The Great Language Shootout, which 
tests how fast solutions implemented in various programming languages 
can be, given unbounded amounts of time, energy, expertise, and compiler 
modifications. Which is interesting, from a certain point of view.


In another sense, it's less interesting. For example, a C program can be 
as fast as any Haskell program, since compiling Haskell entails 
transforming it *into* C. (Unless you're seriously going to suggest that 
GHC's native code generator is any match for the might of a half-decent 
C compiler...)


That got me thinking about a more interesting question: Not *how fast* 
can it go, but *how easily* can it go fast? People have written fast C 
programs and fast Haskell programs, but how easy is it to write a 
"typical" program and have it go fast, without spending years optimising it?


With that in mind, I set of with a plan to do some small-scale 
benchmarking. Pick a problem, solve it in both Haskell and C++, in the 
"simplest, most obvious way", and then apply "the simplest, most obvious 
optimisations". Measure performance and compare.


There are benchmarks that just output some data. ("Find all the prime 
numbers less than 1000...") I dislike these for a couple of reasons, not 
least because you can precompute the correct answer and just write a 
program which outputs that. (!) So I decided that all my benchmark 
programs should take a variable-sized data file as input, and save the 
results as output.


There's an old maxim of running benchmarks multiple times, to ensure 
that whatever time you got wasn't just a fluke. But then, maybe the 
first run pulls the input file into the file cache, and subsequent runs 
go faster. If your input data was randomly generated, perhaps you chose 
a particularly optimal or pessimal data set by accident. So I decided 
that each test run should use a different input file of approximately 
the same characteristics (size, random distribution, etc.)


So I ended up picking benchmarks like "sort the lines of this file into 
ascending order", "count the number of unique words in this file", 
"produce a histogram of byte values", "compute some statistics of this 
list of numbers", etc. The tasks are all extremely simple, so that there 
is some hope of it being possible to also implement them in C++.




One benchmark turned out to be particularly interesting: I call it "byte 
histogram". The task is simple:

- Open a binary input file.
- Read a stream of bytes from it.
- Count how many times each of the 256 possible byte values appears.
The test inputs are binary files of various sizes, some with a uniform 
distribution, some with variously skewed distributions (so that some 
bytes have a vastly higher count than others).


Assuming we have some suitable import statements, it's quite easy to do 
this:


  bytes <- BS.readFile "Input.bin"
  let out = BS.foldl' (\ map byte -> MAP.insertWith (+) byte 1 map) 
MAP.empty bytes
  writeFile "Output.csv" (unlines $ map (\(k,v) -> show k ++ "," ++ 
show v) $ MAP.toAscList out)


(There is some slight trickiness if you want bytes with zero frequency 
to still be listed.)


All of this *works* perfectly - i.e., it produces the correct answers. 
It's also astronomically slow, and it's very easy to make it eat many 
gigabytes of RAM while it runs. (If the program starts actually 
swapping, then you will truly know what "slow" is!)


OK, so what happens if we replace Data.Map with Data.IntMap? Well, it 
goes slightly faster, and consumes slightly less RAM. Inputs which 
didn't quite complete before will run to completion now. But performance 
is still abysmal.


Enough with this tree sillyness. What happens if you use an array? Given 
that the entire program (apart from the last 0.02% of it) spends its 
time notionally mutating the data, a mutable array would be the logical 
choise. Dial up an IOArray Word8 Int and the structure of the program 
changes slightly, but it's still only a handful of lines of code. And 
the performance? Still glacial.


In particular, suppose we have

  inc :: IOArray Word8 Int -> Word8 -> IO ()
  inc array byte = do
count <- readArray array byte
let count' = count + 1
writeArray array byte count'

in the main loop. The program is giving us the right answer, but using 
absurd amounts of time and space to get it. Now watch this:


  inc :: IOArray Word8 Int -> Word8 -> IO ()
  inc array byte = do
count <- readArray array byte
let count' = count + 1
count' `seq` writeArray array byte count'

And now, suddenly, memory usage becomes constant, regardless of input 
size, and run-time is slashed. The program goes from taking 50 seconds 
to process a certain file to taking only 0.02 secon