Re: Help on Homework help

2003-09-03 Thread Andrew J Bromage
G'day all.

On Wed, Sep 03, 2003 at 08:34:58AM +0100, Simon Peyton-Jones wrote:

 One suggestion: it'd be good to suggest *strongly* that people only
 send their homework-style questions to Haskell-café, not to the main
 Haskell list. 

Done, thanks.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Poll: How to respond to homework questions

2003-08-28 Thread Andrew J Bromage
G'day all.

On Wed, Aug 27, 2003 at 05:50:14PM -0400, Matthew Donadio wrote:

 For the first case, I would vote for D and/or E as appropriate.  For the
 second case, I vote for (F) Ignore.

IMO, based on the result of this poll, we should develop some kind of
short FAQ (e.g. on the wiki) which we can include in the list
subscription information and can also send to people who ask for the
kind of homework help that we don't like to see.  IMO, this is better
than ignoring, and far more polite than giving a correct but highly
useless answer, fun though that might be.

I'd be happy to write something once the vote comes in.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Poll: How to respond to homework questions

2003-08-28 Thread Andrew J Bromage
G'day all.

On Thu, Aug 28, 2003 at 11:25:43AM +0200, Ketil Z. Malde wrote:

 I suppose C is one way to do F, in particular by providing a working
 program so complex and opaque that no first-year could possibly have
 written it.

Uhm... yes.

 I'm not sure I care much for politesse.

Understood (and I'm as guilty of strategy (C) as anyone), however, it
can occasionally be hard to tell the difference between someone who is
testing the waters and someone who is just lazy, and it may be worth
giving people the benefit of the doubt.  In addition, ridiculing the
lazy may turn away people who may otherwise be tempted to ask for help
properly.

 And hey, 'fun' is an important part of all this. :-)

Certainly!

Speaking of FAQs, this is quite good:

http://www.catb.org/~esr/faqs/smart-questions.html

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Pascal Line in Haskell

2003-08-22 Thread Andrew J Bromage
G'day all.

On Fri, Aug 22, 2003 at 09:40:12AM +1000, Job L. Napitupulu wrote:

 Can anyone help me how to make a function which takes an integer n  0 and
 returns the list of integers in Line of Pascal's Triangle. For examples,
 
 pascalLine 4 - [1,4,6,4,1]
 pascalLine 7 - [1,7,21,35,35,21,7,1]

This should do the trick.

Cheers,
Andrew Bromage

8---CUT HERE---8

type InfTable a = [(Integer, BinTree a)]
data BinTree a = Leaf a | Node Integer (BinTree a) (BinTree a)

swing :: Integer - Integer
swing n = rec n (\_ _ r - r)
  where
 rec :: Integer - (Integer - Integer - Integer - Integer) - Integer
 rec n k
   | n  2
 = k 1 1 1
   | otherwise
 = rec (n `div` 2) (\nn ff r - swing' n nn ff
 (\nn' ff' - k nn' ff' $! (r*r*ff')))

 swing' :: Integer - Integer - Integer -
 (Integer - Integer - Integer) - Integer
 swing' n nn ff k
   | nn `mod` 2 == 1 = swing_odd k nn ff
   | otherwise   = swing_even k nn ff
 where
 swing_odd k nn ff
   | nn = n   = swing_even k (nn+1) $! (ff*nn)
   | otherwise = k nn ff

 swing_even k nn ff
   | nn = n   = swing_odd k (nn+1) $! (ff*4 `div` nn)
   | otherwise = k nn ff

recProd :: Integer - Integer - Integer
recProd b n
  | n  5
= case n of
 0 - 1
 1 - b
 2 - b*(b+1)
 3 - b*(b+1)*(b+2)
 4 - (b*(b+1))*((b+2)*(b+3))
  | otherwise
= let n2 = n `div` 2
  in recProd b n2 * recProd (b+n2) (n-n2)

pascalLine :: Integer - [Integer]
pascalLine n
  | n = 0 = searchTable n table
  where
 table :: InfTable [Integer]
 table = buildInfTable 1 5

 buildInfTable n i
= (nextn, buildInfTable' n i) : buildInfTable nextn (i+1)
 where
 nextn = n + 2^i

 buildInfTable' base 0
 = Leaf [ c base k | k - [0..base] ]
 where
 c m n
| m  0  = 0
| n  0 || n  m = 0
| n  m `div` 2  = c' n (m-n)
| otherwise  = c' (m-n) n
 c' i j = recProd (i+1) j `div` swing j
 buildInfTable' base i
 = Node (base + midSize)
(buildInfTable' base (i-1))
(buildInfTable' (base + midSize) (i-1))
 where
 midSize = 2 ^ (i-1)

 searchTable x ((x',tree):ms)
 | x  x'= searchTree x tree
 | otherwise = searchTable x ms

 searchTree x (Leaf y) = y
 searchTree x (Node mid l r)
 | x  mid   = searchTree x l
 | otherwise = searchTree x r

___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: More type design questions

2003-08-19 Thread Andrew J Bromage
G'day all.

On Tue, Aug 19, 2003 at 12:31:08PM +0200, Konrad Hinsen wrote:

 Under what conditions would Haskell programmers make some type an instance of 
 Functor? Whenever it could possibly be done (i.e. whenever fmap makes sense)? 
 Or just when fmap would be used frequently for some type?

Like anything else in software development, it's a judgement call.

The questions you have to ask might include:

- Does it make sense?
- Is it an appropriate abstraction for this type?
- Would I want to encourage another programmer to use it?
- Do I want to use it myself?
- Would it unnecessarily limit the possible implementations of
  this abstract type?

The last point is particularly important to consider.  A Set-like type,
for example, is mathematically a functor, but any implementation of
fmap will in general change the relative orderings, hash values etc of
member elements.  This means that supporting fmap efficiently might
rule out many interesting implementations of this container.

If in doubt, don't implement it (yet).

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Type design question

2003-07-27 Thread Andrew J Bromage
G'day all.

On Fri, Jul 25, 2003 at 03:48:15PM -0400, Dylan Thurston wrote:

 Another approach is to make Universe a multi-parameter type class:
 
 class (RealFrac a, Floating a) = Universe u a | u - a where
   distanceVector :: u - Vector a - Vector a - Vector a
 ...

Actually, this is a nice way to represent vector spaces, too:

class (Num v, Fractional f) = VectorSpace vs v f | vs - v f where
scale :: vs - f - v - v
innerProduct :: vs - v - v - f

The reason why you may want to do this is that you may in general want
different inner products on the same vectors, which result in different
vector spaces.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Type design question

2003-07-27 Thread Andrew J Bromage
G'day all.

On Sun, Jul 27, 2003 at 10:36:46PM -0400, Dylan Thurston wrote:

 However, I would be sure to distinguish between an inner product space
 and a vector space.

That's true.  If you're after a completely generic solution, this might
be an issue.

 An inner product space has the 'innerProduct' operation you
 mention; as you say, there is very frequently more than one interesting
 inner product.

I might also add that normalisation doesn't necessarily make sense on
every inner product space.  In my situation, for example, the scalar
field is Rational, so it wasn't closed under square root.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Old alternative syntax for list comprehensions?

2003-07-14 Thread Andrew J Bromage
G'day all.

On Mon, Jul 14, 2003 at 11:08:55PM -0400, Ken Shan wrote:

 I just wanted to see that asterisk again.

...and semicolons returned to their rightful place as separators
for list comprehension/diagonalisation qualifiers.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Handling large ini files.

2003-07-12 Thread Andrew J Bromage
G'day all.

On Sun, Jul 13, 2003 at 10:09:21AM +1000, Andrew Rock wrote:

 I think that each being a customisation *is* sufficient for coherence
 of one data structure to hold them all.

I agree, though using different data structures for each set of
configuration parameters which will be used together is also
something to consider.

Also, if you're using GHC, -funbox-strict-fields is one flag you may
look into.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Hugs Humor

2003-07-08 Thread Andrew J Bromage
G'day all.

On Tue, Jul 08, 2003 at 01:06:23PM +0100, Jon Fairbairn wrote:

 Unfortunately we don't have Real (in
 libraries as far as I remember -- if you have a continued
 fraction implementation of it, it ought to go to the
 libraries list).

Not one, but TWO implementations!  One using continued fractions,
one using LFTs.

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/haskell-libs/libs/exactreal/

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Representing cyclic data structures efficiently in Haskell

2003-07-07 Thread Andrew J Bromage
G'day all.

As you note, some kind of indirection is what you want here.

On Mon, Jul 07, 2003 at 04:04:17PM +0100, Sarah Thompson wrote:

 I would also need to implement efficient indexes into the data structure 
 -- flat searching will be too slow for non-trivial amounts of data. In 
 C++, I'd implement one or more external (probably STL-based) indexes 
 that point into the main data structure.

The direct Haskell equivalent is to use Refs; either IORefs or
STRefs.  (I'd personally use IORefs, but that's because I like
having IO around.)  Dereferencing an IORef is a constant-time
operation, just like chasing a pointer in C.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Representing cyclic data structures efficiently in Haskell

2003-07-07 Thread Andrew J Bromage
G'day all.

On Mon, Jul 07, 2003 at 04:04:17PM +0100, Sarah Thompson wrote:

  I would also need to implement efficient indexes into the data structure 
  -- flat searching will be too slow for non-trivial amounts of data. In 
  C++, I'd implement one or more external (probably STL-based) indexes 
  that point into the main data structure.

I replied:

 The direct Haskell equivalent is to use Refs; either IORefs or
 STRefs.  (I'd personally use IORefs, but that's because I like
 having IO around.)  Dereferencing an IORef is a constant-time
 operation, just like chasing a pointer in C.

I forgot to give an example. :-)

Suppose you want some kind of electronic circuit, as you suggested.
Abstractly, you want something like this:

data Node
  = Node NodeState [Component]

data Component
  = Resistor ResistorCharacteristics Node Node
  | Transistor TransistorCharacteristics Node Node Node
  | {- etc -}

You can make this indirect in introducing refs:

type NodeRef = IORef Node
type ComponentRef = IORef Component

data Node
  = Node NodeState [ComponentRef]

data Component
  = Resistor ResistorCharacteristics NodeRef NodeRef
  | Transistor TransistorCharacteristics NodeRef NodeRef NodeRef

The data structures are mutable:

getNodeState :: NodeRef - IO NodeState
getNodeState node
  = do  Node state _ - readIORef node
return state

setNodeState :: NodeRef - NodeState - IO ()
setNodeState node state
  = do  modifyIORef (\Node _ cs - Node state cs) node

and it's straightforward to construct an index into the middle
somewhere:

type NamedNodeIndex = FiniteMap String NodeRef

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Representing cyclic data structures efficiently in Haskell

2003-07-07 Thread Andrew J Bromage
G'day all.

On Mon, Jul 07, 2003 at 04:37:46PM +0100, Sarah Thompson wrote:

 I'd considered something like embedding the type in the IO monad, with 
 links between components implemented as IORefs, but I'd really prefer 
 something cleaner (pure functional). If the code ends up horribly 
 complicated in order to get decent performance, I might as well fold and 
 use C++ instead.

At the risk of stating the obvious, IORefs _are_ pure functional. :-)

 I'm currently wondering about going for an adjacency list approach (as
 used by most graph libraries), with the tuples in the adjacency list
 extended to include input/output labels, resulting in a 4-ary tuple
 rather than the usual 2-ary. But, I don't want to be stuck with
 representing this as a list -- I really need log N lookups or
 performance will stink horribly as circuits get big. Maybe a pair of
 finite maps, allowing the edges to be traversed in either direction?

You could do that.  Or you could use just one FiniteMap and reverse
the iterator before you use it.  (Remember that reverse is an amortised
O(1) operation, assuming you need to traverse the whole list.)

Or you could take a copy of the FiniteMap source code and add your own
reverse iterator to complement the forward iterator which is already 
there.  You could even submit a patch. :-)

Or you could use a different data structure, say, one with O(n)
iteration from either end, O(log n) search and O(1) insertion onto
either end.  There are several of these floating around.  This one
is quite good:

http://citeseer.nj.nec.com/25942.html

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Non-determinism, backtracking and Monads

2003-06-11 Thread Andrew J Bromage
G'day all.

On Wed, Jun 11, 2003 at 12:36:30PM +0200, Jerzy Karczmarczuk wrote:

 It is possible, instead of implementing the *data backtracking* through lazy
 lists, to make lazy backtrackable continuations, permitting to redirect 
 the flow of control to produce something else. The two ways are - perhaps not
 entirely equivalent, but essentially two orchestrations of the same 
  theme.
 I lost my references, perhaps somebody?...

If you're referring to the paper(s) by Ralf Hinze, they are most
certainly equivalent.

WARNING: Long post follows.

Consider the simplified term implementation of a nondeterminism monad,
which basically operates on lists:

data Nondet1 a
= Cons a (Nondet1 a)
| Fail

-- This is the observer method
runNondet1 :: (Monad m) = Nondet1 a - m a
runNondet1 m = case m of
Cons x _ - return x
Fail - fail no solutions

return a = Cons a Fail

m = k  = case m of
Cons a n - mplus (k a) (n = k)
Fail - Fail

mzero = Fail

mplus m n = case m of
Cons a m' - Cons a (mplus m' n)
Fail  - n

You can derive a continuation-passing implementation by transforming
away the data structures.  This is a technique well-known to
practitioners of traditional lambda calculus.

We'll start by abstracting the data structures out.  We need replacements
for both constructor functions (i.e. Cons and Fail) and the pattern
matching used above.

data Nondet1 a = Fail | Cons a (Nondet1 a)

cons1 :: a - Nondet1 a - Nondet1 a
cons1 a m = Cons a m

fail1 :: Nondet1 a
fail1 = Fail

unpack1 :: Nondet1 a - (a - Nondet1 a - b) - b - b
unpack1 (Cons a m) c f = c a m
unpack1 Fail   c f = f

The monad can now be re-implemented in terms of these operations:

runNondet1 :: (Monad m) = Nondet1 a - m a
runNondet1 m = unpack1 m
(\x _ - return x)
(fail no solutions)

return a = cons1 a fail1

m = k  = unpack1 m
(\a n - k a `mplus` n = k)
fail1

mzero = fail1

mplus m n = unpack1 m
(\a m' - cons1 a (mplus m' n))
n

Note that there are now no data structures in here, only calls to
fail1, cons1 and unpack1.  We can implement these how we like so
long as these properties hold:

unpack1 fail1 c f = f
unpack1 (cons1 x xs) c f = c x xs

The lambda calculus solution is to make unpack1 the identity function.
Unfortunately that doesn't entirely work in Haskell because of the
type system, but we can get pretty close by using rank-2 types and
a newtype constructor:

-- Compare this with the type of unpack1 above
newtype Nondet2 a
= Nondet2 (forall b. (a - Nondet2 a - b) - b - b)

fail2 :: Nondet2 a
fail2 = Nondet2 (\c f - f)

cons2 :: a - Nondet2 a - Nondet2 a
cons2 a m = Nondet2 (\c f - c a m)

unpack2 :: Nondet2 a - (a - Nondet2 a - b) - b - b
unpack2 (Nondet2 m) = m

We can inline these functions everywhere to get:

runNondet2 :: (Monad m) = Nondet2 a - m a
runNondet2 (Nondet2 m)
= m (\x _ - return x) (fail no solutions)

return a = Nondet2 (\c _ - c a (Nondet2 (\_ f - f)))

(Nondet2 m) = k
= m (\a n - mplus (k a) (n = k)) (Nondet2 (\_ f - f))

mzero = Nondet2 (\_ f - f)

mplus (Nondet2 m) n
= m (\a m' - Nondet2 (\c _ - c a (mplus m' n))) n

...and we have a continuation-passing implementation.

Note that this is not 100% identical to the one from Ralf's paper and
tech report.  Transforming the above code into Ralf's is left as an
exercise.  (It's tricky but mechanical.)

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: powerset

2003-06-05 Thread Andrew J Bromage
G'day all.

On Wed, Jun 04, 2003 at 02:00:08PM +0100, Keith Wansbrough wrote:

 This formulation is particularly nice because in memory, you *share*
 all of the lists from the previous iteration, rather than making
 copies.
[...]
 Notice all the sharing - this is a very efficient representation!  You
 save on copying, and you save on memory use.

I can never resist a can labelled worms.  Let me get out my tin
opener...

You do save on memory allocations.  If, however, you consume the list
lazily and discard the results as you consume them (which is the
common way lazy programs are written), you actually use more memory
at once.

Try it if you don't believe me.  Test it with this program, using
each definition of powerset:

summer :: [[a]] - Integer
summer xss = foldl' (\xs r - r + toInteger (length xs)) 0 xss

n :: Int
n = 32

main :: IO ()
main = print (summer (powerset [1..n]))

You'll find that one of them runs in O(n) space and the other most
likely blows the heap.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Tokenizing Strings

2003-04-01 Thread Andrew J Bromage
G'day all.

On Wed, Apr 02, 2003 at 11:26:46AM +1000, [EMAIL PROTECTED] wrote:

 in this case, I have a string containing multiples fields seperated by *two*
 blank lines (\n\n). I can't just break on the newline character, as single
 newline characters can be found inside each field.
 
 any idea how I can do this without too much hassle?

Here's some code I wrote some time ago which does Knuth-Morris-Pratt
string searching:

http://haskell.org/wiki/wiki?RunTimeCompilation

Note that there are a couple of differences between matchKMP and break
which you will no doubt discover.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: speedup help

2003-03-03 Thread Andrew J Bromage
G'day all.

On Mon, Mar 03, 2003 at 04:59:21PM -0800, Hal Daume III wrote:

 I think you would get a big speed-up if you got rid of all the rational
 stuff and just used:
 
 comb m n = fact m `div` (fact n * fact (m-n))

Or, even better, if you didn't multiply stuff that you're just going
to divide out in the first place.

  choose :: (Integral a) = a - a - Integer
  choose m n
| m  0  = 0
| n  0 || n  m = 0
| n  m `div` 2  = choose' n (m-n)
| otherwise  = choose' (m-n) n
where
  choose' i' j'
  = let i = toInteger i'
j = toInteger j'
in  productRange (i+1) j `div` factorial j

  factorial :: (Integral a) = a - Integer
  factorial n = productRange 1 n

  productRange :: (Integral a) = Integer - a - Integer
  productRange b n
| n  5
= case n of
  0 - 1
  1 - b
  2 - b*(b+1)
  3 - (b*(b+1))*(b+2)
  4 - (b*(b+3))*((b+1)*(b+2))
  _ - 0
| otherwise
  = let n2 = n `div` 2
in productRange b n2 * productRange (b+toInteger n2) (n-n2)

Note that productRange uses a divide-and-conquer algorithm.  The
reason for this is that it's more efficient to multiply similarly-sized
Integers than dissimilarly-sized Integers using GMP.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: is identity the only polymorphic function without typeclasses?

2003-03-02 Thread Andrew J Bromage
G'day all.

On Sun, Mar 02, 2003 at 10:18:13AM +0200, Cagdas Ozgenc wrote:

 Is identity function the only meaningful function one can write
 without constraining the type variable using a typeclass? If not,
 could you please give a counter-example?

This might help:

@incollection{ wadler89theorems,
author = Philip Wadler,
title = Theorems for Free!,
booktitle = Proceedings 4th Int.\ Conf.\ on Funct.\ Prog.\ Languages and Computer 
Arch., {FPCA}'89, London, {UK}, 11--13 Sept 1989,
publisher = ACM Press,
address = New York,
pages = 347--359,
year = 1989
}

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: a monadic if or case?

2003-02-13 Thread Andrew J Bromage
G'day all.

On Thu, Feb 13, 2003 at 02:54:42PM -0500, David Roundy wrote:

 That's pretty nice (although not quite as nice as it would be to be able to
 use real ifs with no extra parentheses).  Any idea how to do something like
 this with a case? http://www.haskell.org/mailman/listinfo/haskell-cafe

In the case of Maybe, what you're really trying to do there is a kind of
exception handling.  You may or may not be better off using a real
exception monad transformer on top of IO (or whatever the underlying
monad is).

One possibility is Control.Monad.Error (fromt he MTL).  Here's another
possibility:

  http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/hfl/hfl/mtl/Negate.hs?rev=1.2

I know this didn't directly answer your question, but it's good to
explore the design space.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Global variables?

2003-02-05 Thread Andrew J Bromage
G'day.

On 05-Feb-2003, Simon Peyton-Jones [EMAIL PROTECTED] wrote:

  H98 has nothing to say about the separate compilation; it's an issue for
  the implementation.

H98 indeed says nothing about separate compilation, and it is indeed
an issue for the implementation.

What H98 does is it defines a language for which separate compilation
is at best extremely difficult and at worst virtually impossible
without extra information which is not part of H98 (such as GHC's
hi-boot files).

On Wed, Feb 05, 2003 at 07:41:52PM +1100, Fergus Henderson wrote:

 In other words, GHC doesn't support separate compilation of
 Haskell 98 -- it supports separate compilation of a closely related
 but distinct language which we can call Haskell 98 + GHC hi-boot files.

Exactly.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: separate compilation [was Re: Global variables?]

2003-02-05 Thread Andrew J Bromage
G'day all.

On Wed, Feb 05, 2003 at 04:16:33PM -0800, Iavor S. Diatchki wrote:

 why do you think separate compilation is difficult to achieve in Haskell 
 98?

Because of type inference over recursive module imports.  Determining
the type of a function may, in general, require inferring types from an
arbitrary number of other modules, and may require inference to occur
at the level of granularity of a clique in the import graph, rather than
at the level of a single module.

Requiring an implementation to perform static analysis a clique at a
time is not separate compilation, because changing something which is
private to one module may in general require an unbounded number of
other modules to be recompiled, even if inter-module optimisation is
turned off.

 as simon pointed out, GHC does it and has been doing it for a long 
 time.

GHC does separate compilation by requiring the programmer to step
outside H98, by writing GHC-specific hi-boot files.  I agree that
GHC therefore supports separate compilation, but, as Fergus pointed
out, it does not support separate compilation within H98.

 dealing with mutually recusrive modules is i think a separate 
 issue.

Why is it a separate issue?

 even though GHC doesn't quite do it, it is certainly possible, 
 and not very difficult to do.  in fact we have it implemented in one of 
 the projects i am currently working on. hopefully one day GHC will also 
 dispense with the hi-boot files.

I would certainly like to see this, but it doesn't fix the concern
noted above, that changing something private to one module may cause
an arbitrary number of other modules to be recompiled.  That is not
separate compilation by any definition of the word separate that
I am aware of.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: separate compilation [was Re: Global variables?]

2003-02-05 Thread Andrew J Bromage
G'day all.

On Wed, Feb 05, 2003 at 08:05:56PM -0600, Jon Cast wrote:

 I'm not sure I follow this.  If you change the type of a value exported
 from a given module, that's a public change, no?  And if you don't, why
 should re-compilation be needed?

Consider this:


module A where

import B

{- use B.b -}



module B (b) where

import C

b = C.c



module C (c) where

c :: Int


Changing the type of c requires recompiling module A.

You would expect that changing c's type forces a recompilation of B,
since you changed C's public interface.  However, this also changes B's
public interface even though you did not touch the text of module B.
The reason is that B's public interface is partly based on modules
which it _privately_ imports, even if it does not re-export any symbols
from those modules.

One fix is to require all exported symbols to have explicit type
declarations.  Since this is good practice anyway, I would be in
favour of making it a language requirement in Haskell 2.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: separate compilation [was Re: Global variables?]

2003-02-05 Thread Andrew J Bromage
G'day all.

On Wed, Feb 05, 2003 at 09:28:05PM -0600, Jon Cast wrote:

 I think I see what you're saying.  I still maintain, however, that,
 since you've changed the type of B.b (admittedly implicitly), and B.b is
 exported from B, that you've changed B's interface.
 
 There is a reason make is designed to re-build B /and/ (potentially) A
 when C changes, after all.

In principle, it shouldn't.  If module D imports module E, changing
E's implementation should not force a recompilation of module D
(assuming no intermodule optimisation, of course).  In GHC terms,
D.o should only depend on D.hs and E.hi.

However, this isn't my main problem.  This is at best a big pain,
and at worst a potential waste of an expensive software engineer's
time.  Software engineers like it when they can predict how long a
compilation will take.  The unknowns are an acceptible risk when
intermodule optimisation is turned on, but if I'm being paid by the
hour to hack Haskell code, I want a way to turn that off in order to
better schedule my day.  I digress.

My main problem is that under H98, it's not possible, in general, to
determine what the public interface of a module actually _is_ without
intermodule analysis.  This, IMO, breaks pretty much every sensible
meaning that you could assign to the term separate compilation.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Stacking up state transformers

2003-02-04 Thread Andrew J Bromage
G'day.

On Tue, Feb 04, 2003 at 05:24:29PM -, Guest, Simon wrote:

 I can still access my backtracked state using Control.Monad.State.{get,put}, but
 I can't access my non-backtracked state.

Iavor mentioned using lift, plus some other ideas.  That's what
I'd do:

liftNondet = lift
liftOuterState = lift . lift

(Naturally I'd call these something more meaningful.)

As a matter of style, I generally advocate the philosophy that your
basic operations should be semantically meaningful, rather than
operationally meaningful.  So, for example, rather than:

type FooM a = StateT Bar (StateT Baz IO) a

munch :: FooM ()
munch = do baz - lift (lift get)
   doStuffWith baz

I prefer:

type FooM a = StateT Bar (StateT Baz IO) a

getBaz :: FooM Baz
getBaz = lift (lift get)

munch :: FooM ()
munch = do baz - getBaz
   doStuffWith baz

Not only is it more readable, it's also more robust in the face of
change (e.g. when you decide to change to ReaderT instead).

In your case, it's a state monad you're trying to get at, and a state
monad only supports a few meaningful operations (get, put, modify, gets)
not all of which are generally useful for a given kind of state.  I
think it makes more sense to specify a public interface for your
monad and use only that.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Global variables?

2003-02-02 Thread Andrew J Bromage
G'day all.

On Fri, Jan 31, 2003 at 09:08:22AM +0100, Ralf Hinze wrote:

 John Hughes wrote a nice pearl on the subject, see
 
   http://www.math.chalmers.se/~rjmh/Globals.ps

Nice!  Why isn't RefMonad in hslibs?

Possibly because of the class signature:

class Monad m = RefMonad m r | m - r where
{- etc -}

It makes perfect sense for there to be more than one kind of ref
for a given monad.  Indeed, sometimes it's important.  Quite often, I
use a custom ref built on top of IORef which supports Ord, as this is
needed for hash consing.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Global variables?

2003-02-02 Thread Andrew J Bromage
G'day all.

On Fri, Jan 31, 2003 at 01:54:26PM -0600, Jon Cast wrote:

 Otherwise, though, see my other post on this subject: unsafePerformIO
 will perform its action when the variable is accessed, so you can't
 write a Haskell program which differentiates between what any compiler
 actually does and running the variable allocations before main.

As has been pointed out, there is no language requirement for a
Haskell implementation to be fully lazy.  In particular, it is
technically possible for an implementation to garbage collect
globalVar and re-evaluate it on the next call.

Haskell 2 should probably have a pragma controlling this.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Problem with backtracking monad transformer

2003-02-02 Thread Andrew J Bromage
G'day all.

On Fri, Jan 31, 2003 at 09:05:11AM -, Guest, Simon wrote:

 This bit I don't understand.  I only have one monad transformer, which I use to 
 transform my SM monad.

What I mean is (and recall that I have not looked very hard at your
program, just the BACKTR implementation, so I'm not sure what
semantics you were really after) you may have meant to stack a state
monad transformer on top of BACKTR, rather than the other way.

Good luck.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Problem with backtracking monad transformer

2003-01-30 Thread Andrew J Bromage
G'day all.

On Thu, Jan 30, 2003 at 01:55:50PM -, Guest, Simon wrote:

 I'm trying to make a backtracking state monad using Ralf Hinze's
 backtracking monad transformer.  My problem is that it won't backtrack
 very far.
 
 Suppose I try ( a  b ) `mplus` c.
 
 If b fails, it should try c, but it doesn't rewind past a.

I added this to your source file:

testBACKTR :: (Monad m) = BACKTR m Int
testBACKTR
= ( return 1  M.mzero ) `M.mplus` (return 2)

main :: IO ()
main = putStrLn (show (observe testBACKTR :: Maybe Int))

The result is Just 2, so I don't think there's anything wrong with
your implementation of BACKTR.  I've compared it with my own
well-tested implementation and it seems identical modulo renamings.

In case you want to compare:

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/hfl/hfl/mtl/

I didn't follow the rest of the code, so I suspect the problem is
elsewhere.  One place to look is here:

 -- backtracking state monad
 --
 type NDSM st a = BACKTR (SM st) a

You may have meant to stack the monad transformers in a different
order.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Ambiguous defaults

2003-01-02 Thread Andrew J Bromage
G'day all.

On Thu, Jan 02, 2003 at 05:49:41PM +0100, Ferenc Wagner wrote:

 What's the way to express the following: a compound object
 is generally made up of two components with identical type.

This should work:

\begin{code}
module Test where

class Component b where
property :: b - Int

class (Component b) = Compound a b | a - b where
decompose :: a - (b,b)
additive :: a - Int
additive x = property l + property r
where (l,r) = decompose x
\end{code}

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: comonads, io

2003-01-02 Thread Andrew J Bromage
G'day all.

On Thu, Jan 02, 2003 at 08:08:20PM -0800, Ashley Yakeley wrote:

 So is Kieburtz smoking crack, or are we writing OI-style programs 
 incorrectly?

I mailed him the example and asked.  (I phrased the question a bit
differently, though.)

 One possibility is that comonads are useful for some 
 things, but not for doing IO actions safely.

Another possibility is that comonads aren't as suited for standard
pipes as monads.  The problem only happens with an implicit file
handle, as you have with getChar.  Using hGetChar it's perfectly
safe because the Handle is embedded in an OI comonad.

Yet another possibility is that we haven't quite gotten the type
signatures right on the OI primitives.

A third possibility is that everything is okay and we're just missing
something very obvious.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Error Handling

2002-12-08 Thread Andrew J Bromage
G'day all.

On Mon, Dec 09, 2002 at 11:35:54AM +1100, Thomas L. Bevan wrote:

 main = do (a:b:cs) - getArgs
   i - return (read a :: Int)
   j - return (read b :: Int)
   putStr $ i + j
 
 How can I catch any possible cast exception?

How about this?

readM :: (Read a, Monad m) = String - m a
readM s
  = case readEither s of
Left err - fail err
Right x  - return x

main = runErrorT main'

main' = do  (a:b:cs) - liftIO getArgs
(i::Int) - readM a
(j::Int) - readM b
liftIO (putStr $ i + j)

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Error Handling

2002-12-08 Thread Andrew J Bromage
G'day all.

Slight correction...

On Mon, Dec 09, 2002 at 12:03:03PM +1100, Andrew J Bromage wrote:

 main = runErrorT main'

Of course you need to define an error type and do something with the
result of runErrorT, but you get the general idea.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: AW: Editor Tab Expansion

2002-12-07 Thread Andrew J Bromage
G'day all.

On Fri, Dec 06, 2002 at 05:40:28PM +0100, Ingo Wechsung wrote:

 No. It didn't hamper portability with C, Java, Perl or any other *nix stuff
 since more than 30 years except with COBOL, Python (?) and Haskell, [...]

Add to that: Fortran, Occam and Makefiles.  There's probably also a lot of
application-specific files (like Makefiles) that others know of.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Editor Tab Expansion

2002-12-05 Thread Andrew J Bromage
G'day all.

On Thu, Dec 05, 2002 at 09:49:27PM +0100, Ingo Wechsung wrote:

 I am not going to change my editing habits just to make hugs or ghc happy.

What editor do you use?  If you use a relatively smart one (e.g. vim,
emacs etc), you should be able to configure it to do it to do what you
want when the extension is .hs or .lhs or whatever.

I use vim and I have been known to use the following:

set ts=8
set sts=4Or sometimes 2

With either expandtab or noexpandtab as the mood takes me.  That way,
when I hit tab I get 2 or 4 spaces, which are expanded to an 8-space
tab if I hit it enough times.

 Wether spaces or tabs are better in source files is a matter of taste and
 a language should not force me to use one or another.

The language does not force you to do anything of the sort.  It's your
editor's fault if it can't decouple the concept of hitting the tab
key from the concept of putting a ^I character in your file.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Editor Tab Expansion

2002-12-05 Thread Andrew J Bromage
G'day all.

On Thu, Dec 05, 2002 at 06:36:22PM -0800, Ashley Yakeley wrote:

 Haven't we all been through this argument several months ago? I believe 
 the conclusion was people have different preferences, and Haskell allows 
 for that.

Sure, but that's a separate issue.

My remark was merely in response to the claim that Haskell cares
whether you put tabs or spaces in your files.  It does not, so long
as the tabs are of length 8.  If your editor produces tabs of a
different size, that's a problem with your editor or the way you
dislike Haskell's layout rules.

Or, to look at it another way, there are better reasons to dislike
Haskell's layout rules than this.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: library of monadic functions [was: Why no findM ? simple Cat revisited]

2002-11-20 Thread Andrew J Bromage
G'day all.

On Wed, Nov 20, 2002 at 08:25:46PM +, Jorge Adriano wrote:

 I think both versions can be very useful:
 findM  :: (Monad m) = (a - m Bool) - [a] - m (Maybe a)
 findM'  :: (Monad m) = (a - Bool) - [m a] - m (Maybe a)

I can also make a case for:

  findM'' :: (Monad m) = (a - Bool) - [m a] - m a
  findM'' p [] = fail findM'': not found
  findM'' p (x:xs) = p x = \b - if b then return x else findM'' p xs

This goes with the philosophy that library functions shouldn't just
return Maybe.

Somewhere, somehow, there is a most general version of findM to be
found. :-)

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Random Color

2002-11-20 Thread Andrew J Bromage
G'day all.

On Wed, Nov 20, 2002 at 08:44:36PM -0500, Mike T. Machenry wrote:

 I am trying to construct an infinate list of pairs of random colors.
 I am hung up on getting a random color. I have:
 
 data Color = Blue | Red | Green deriving (Eq, Ord, Show)
 
 am I supposed to instantiate a Random class instance from color?

You could derive instances of Enum (and possibly also Bounded) and
create random elements that way.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Last generator in do {...}

2002-10-29 Thread Andrew J Bromage
G'day all.

On Tue, Oct 29, 2002 at 11:20:47AM +0200, George Kosmidis wrote:

 I am sure there are a billion errors in this.
 This is the first one: 
 Line:17 - Last generator in do {...} must be an expression 

What this means is that the compiler has interpreted the last line
of a do expression to be a generator (i.e. pat - exp), which is
bad Haskell.

In your case, here is main:

 main=do userText-getText

Occasionally, this may be caused by offside errors:

main = do foo - bar
return foo
^ offside error, Haskell interprets this as not being
  part of the do expression

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: can't find sequence?

2002-10-29 Thread Andrew J Bromage
G'day.

On Wed, Oct 30, 2002 at 01:49:37PM +1300, Jason Smith wrote:

 i.e. TernaryTrie.hs:165: Data constructor not in scope: `M'

There is no M in that module anywhere, and I'm pretty sure there
never was.

Please update your copy from CVS and, if it still isn't working, send
a bug report to [EMAIL PROTECTED]

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: can't find sequence?

2002-10-28 Thread Andrew J Bromage
G'day all.

On Mon, Oct 28, 2002 at 08:47:08AM +, Alastair Reid wrote:

 (btw There were some remarks that Chris's library might be dropped
 from distributions because no-one is supporting it.  I don't recall
 whether a decision was made on this.)

If Jason is using a version of Edison that requires
Control.Monad.Identity, it's almost certainly the HFL version, which
is indeed supported (by me, mostly).

However it is very alpha (especially the interface), so I wouldn't
recommend packaging it at the moment.  In particular, Hugs is not
currently a Supported Platform(tm).

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: dozen

2002-10-26 Thread Andrew J Bromage
G'day all.

On Sat, Oct 26, 2002 at 11:40:04AM -0700, Nuno Silva wrote:

 can anyone help me how to get the dozen number? using Int
 
 example 
 
 dozen 1020
 
 the expected result is: 2

dozen :: Int - Int
dozen 1020 = 2

Hope this helps.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: representation getting verbose...

2002-10-22 Thread Andrew J Bromage
G'day all.

On Thu, Oct 17, 2002 at 11:08:57AM -0400, [EMAIL PROTECTED] wrote:

 For an
 interpreter I'm writing, I found myself writing a function
 constructVarExpr :: String - Expr just to make it easier.

As an alternative opinion, I don't think there's anything wrong
with this.  A constructor is just a function, and if you need to
do more work than just construct one constructor, there's no reason
not to use a real function.

In OO design pattern terminology they call this a factory function,
though in Haskell the term smart constructor might also apply if the
function does real work.  Were the wiki working, I would point you to
the relevant page there, but it isn't, so I won't.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: infinite (fractional) precision

2002-10-10 Thread Andrew J Bromage

G'day all.

On Thu, Oct 10, 2002 at 11:50:39AM +0200, Jerzy Karczmarczuk wrote:

 There are of course more serious approaches: intervals, etc. The infinite-
 precision arithmetic is a mature domain, developed by many people. Actually
 the Gosper arithmetic of continued fractions is also based on co-recursive
 expansion, although I have never seen anybody implementing it using a lazy
 language, and a lazy protocol.
 
 Anybody wants to do it with me? (Serious offers only...)

Already did it.  It's not pretty, but I'll send you my implementation
off-list.

One thing I'd like to see is a lazy implementation of linear
fractional transformations.  The reason I'd like to see this is
that it's easier to implement fixpoint-style computations (e.g.
transcendental functions) using LFTs than using continued fractions.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: need help optimizing a function

2002-10-09 Thread Andrew J Bromage

G'day all.

On Wed, Oct 09, 2002 at 02:29:26PM -0400, David Roundy wrote:

 I get a speedup of about a factor of 6 for the test files I was using (of
 course, this would depend on file size), and find that now only 2% of my
 time is spent in that function.  I'm still something like 100 times slower
 than GNU diff, so I think (hope, certainly!) there's still room for more
 improvement (another day).  I'm sure I'll have more questions in a few
 days, once I've tracked down what the new bottlenecks are.

If you understand logic languages, you might want to look at the diff
implementation which I wrote for the Mercury distribution:

http://www.cs.mu.oz.au/research/mercury/

It's pretty close to GNU diff in speed.  In fact, it was
indistinguishable on every test case I could think of.

There are, two main differences to what I could gather from your 
implementation.

First thing was that I noticed that a lot of time was being spent
doing string comparisons.  I inserted a pre-pass which mapped strings
to (unboxed) integers with the constraint that the integers are equal
if and only if the strings are equal.  This also turned out to be
critical for implementing flags such as --ignore-space-change.

The other was I used a different algorithm than you did:

Eugene W. Myers. An O(ND) difference algorithm and its
variations. Algorithmica, 1:251-266, 1986. 

I found it to be much faster than the O(n log n) algorithm, even
on cases where you would expect it to perform poorly (i.e. where
D is large), partly because the constant factors are really, really
low and because in the pre-pass you can optimise the case where you
have a number of consecutive lines none of which appear anywhere
else, which is typical for most uses of diff.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Dealing with configuration data

2002-09-28 Thread Andrew J Bromage

G'day all.

On Fri, Sep 27, 2002 at 12:56:38PM -0400, Dean Herington wrote:

 I'm not sure why you consider the code you refer to above so ugly.

Anything which relies on unsafePerformIO (or seq, for that matter)
is ugly.  Personal opinion, of course. :-)

 Question:
 Why do you use `seq` on `globalTableRef`?

Good question.  It's actually a form of documentation.  I wasn't 100%
sure how concurrency and CAFs interact at the time (and I'm still
not), so I left that in as a sort of note to myself to check this out.

Admittedly a comment would have been clearer. :-)

 You use `addToFM` to replace entries in your table.  Without additional
 logic to increase strictness, I think you unnecessarily risk stack
 overflow.

That's true, although the case of many writes followed by a single
read I would expect to be rare in practice.  Besides, IOGlobal is not
designed for performance.  It's designed for quick hacks.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Dealing with configuration data

2002-09-25 Thread Andrew J Bromage

G'day all.

On Thu, Sep 26, 2002 at 12:06:36AM +0100, Liyang Hu wrote:

 The problem I'm having is with the preferences: How do I make it
 available throughout the entire program? (FWIW, most of the work is
 effectively done inside the IO monad.) I could explicitly pass the
 record around everywhere, but that seems a trifle inelegant.
 
 My current solution is to use a global ('scuse my terminology, I'm not
 sure that's the right word to use here) variable of type IORef Config
 obtained through unsafePerformIO. It works, but strikes me as a rather
 barbaric solution to a seemingly tame enough problem...

One solution is to do precisely as you suggested, using a state
monad to wrap the IORef.  For example:

import Control.Monad.Reader
import Data.IORef

type MyIO a = ReaderT (IORef Config) IO a

main
  = do  config - readConfigurationStuff
configref - newIORef config
runReaderT configref main'

getConfig :: MyIO Config
getConfig
  = do  configref - ask
liftIO (readIORef configref)

-- Same as above, but you can supply a projection function.
getsConfig :: (Config - a) - MyIO a
getsConfig f
  = do  config - getConfig
return (f config)

-- ...and this is where the code REALLY starts.

main' :: MyIO ()
main'
  = do  config - getConfig
liftIO (putStrLn (show config)) -- etc

You can wrap whole slabs of existing code in liftIO if it uses
IO but does not need to read the configuration.

There's also a much uglier solution which I occasionally use if I
need an ad hoc global variable.  Rather than using IORefs, I use
Strings as keys.  The code is here:

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/hfl/hfl/ioext/

Example of use:

import IOGlobal

main :: IO ()
main
  = do  writeIOGlobalM foo Foo data
writeIOGlobalM bar (Bar, [data])
foo - readIOGlobalM foo
putStrLn foo
bar - readIOGlobalM bar
putStrLn (show (bar :: (String, [String])))

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Question about use of | in a class declaration

2002-08-21 Thread Andrew J Bromage

G'day all.

On Wed, Aug 21, 2002 at 02:46:16PM -0400, Mark Carroll wrote:

 One issue we have here is that any Haskell we write is stuff we'll
 probably want to keep using for a while so, although we've only just got
 most of the bugs out of the H98 report, I'll certainly watch with interest
 as people come to a consensus about multi-parameter typeclasses,
 concurrency libraries, etc. and such things start to look very much like
 they'll be fixed in the next round of standardisation. It's hard to know
 which are experiments that ultimately will be shunned in favour of
 something else, and which are just all-round good ideas. (-:

Apart from the mailing lists, there are two forums which are sort
of used for this.

One is the wiki:

http://haskell.org/wiki/wiki?HaskellTwo

...which, as those of us who use it regularly know, is down at
the moment.  The other is the Haskell Wish List:

http://www.pms.informatik.uni-muenchen.de/forschung/haskell-wish-list/

...which has also been down for some time.

Clearly whichever malevolent forces are responsible for downtime
don't want Haskell to evolve. :-)

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Question about use of | in a class declaration

2002-08-21 Thread Andrew J Bromage

G'day all.

On Wed, Aug 21, 2002 at 02:31:05PM +0100, Guest, Simon wrote:

 Please could someone explain the meaning of | in this class
 declaration (from Andrew's example):
 
   class (Ord k) = Map m k v | m - k v where
 lookupM :: m - k - Maybe v

Others have answered the question about what it means.  However, this
doesn't explain why I used a fundep when Haskell has perfectly good
constructor classes.  I could have written:

class (Ord k) = Map m k v where
  lookupM :: m k v - k - Maybe v

instance (Ord k) = Map FiniteMap k v where
  lookupM = lookupFM

However, this would not work for the other two cases (the assoc list
and the function).  For that, I'd have to introduce a new type, such
as:

newtype MapFunc k v = MapFunc (k - Maybe v)

instance (Ord k) = Map MapFunc k v where
  lookupM (MapFunc f) = f

A good Haskell compiler would optimise the representation of the type,
so it wouldn't cost much (or possibly _anything_) at run time, but it's
still a pain to program with.  You need to pack and unpack the MapFunc
type at awkward places, when all you really want to do is rearrange
type variables for one declaration.  Fundeps let you avoid many of these
artificial constructors.

Unfortunately, I don't think that fundeps will help you to get rid
of all of them.  For example, the standard state transformer monad:

newtype State s a = State { runState :: s - (a, s) }

I don't think you can get rid of the constructor here.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Newbie question on statefullness

2002-08-13 Thread Andrew J Bromage

G'day all.

On Mon, Aug 12, 2002 at 10:06:51PM +0100, Alistair Bayley wrote:

 OTOH, if you want to do anything useful with any language you have to learn 
 to do IO (and simple IO is tackled early in most languages), and therefore 
 you must deal with Monads. I often wish that Haskell books and tutorials 
 would introduce IO earlier; it is often near the end, in the advanced 
 topics (after you've been dazzled/saturated by the magic you can do with list 
 functions and comprehensions, and how easy it is to create abstract 
 datatypes, and write parsers, etc...).

Being fair for a moment, most Haskell books are intended as
undergraduate computer science textbooks.  There are many purposes
of these introductory courses, but learning a particular programming
language is not one of them.  You can teach a lot of computer science
without getting bogged down in the details of doing IO.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Haskell wiki problems

2002-08-13 Thread Andrew J Bromage

G'day all.

On Mon, Aug 12, 2002 at 04:19:38AM -0700, John Meacham wrote:

 grr. this used to be in a FAQ at the Wiki. whatever happened to that?

Unfortunately, the ReportingProblems page is one of the ones which
died.  It's also not in the google cache.

Does anyone know who's responsible for the wiki?

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Newbie question on statefullness

2002-08-11 Thread Andrew J Bromage

G'day all.

On Sun, Aug 11, 2002 at 07:03:04PM -0700, Alex Peake wrote:

 I am trying to implement a long-lived accumulator

How long is long?  Over what kind of code must it be preserved?
In what kind of code do you want to modify it and in what kind of
code do you want to read it?

By what kind, I mean things like:

- Is it just needed at the top level of your program?

- Do you need I/O (or some other monadic construction) in the
  same places as this accumulator or is it in different places?

- What other state do you have?  How cleanly does
  it separate from the rest of your code?

- Is there some identifiable part of your program where
  the state is read only, some where it is write only
  and/or some where it is read/write?

These are important considerations.  C has no automatic memory
management, so you must (usually) structure your code around the
lifetimes of your data.  Similarly, Haskell has no automatic state, so
you must (usually) structure your code around the scope of the state
that you intend to simulate.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Newbie question on statefullness

2002-08-11 Thread Andrew J Bromage

G'day all.

On Sun, Aug 11, 2002 at 05:36:21PM -0700, Alex Peake wrote:

 I am new to Haskell. I want to do something very simple (I thought)
 but got lost in the world of Monads.
 
 I want to implement something like the C idea of:
 n += i
 
 So how does one doe this in Haskell?

I think this needs to be an FAQ.

The short answer is that if you find yourself needing to do this,
especially if you're new to Haskell, you're probably thinking about
the problem in the wrong way.  Haskell does not support the n += i
idiom in the same way that C does not support, say, higher-order
functions.

The flip side is that Haskell _does_ support the n += i idiom in
the same way that C _does_ support higher-order functions, in that
with some effort (sometimes a little, sometimes a lot) you can simulate
the same functionality if you find you really need it (using monads,
continuations or whatever).  However, most of the time where you
would use this idiom in C, you would not use it in the equivalent
Haskell program, simply because there's usually a more appropriate
way of phrasing your intentions.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Combining type constraints

2002-08-08 Thread Andrew J Bromage

G'day all.

I have a large number of functions all of which use the same set
of type constraints, such as:

  foo :: (Monad m, Ord t, Show t) = ...

Ideally, I'd like to combine them into one typeclass.  At the moment,
I'm using the equivalent of:

  class (Monad m, Ord t, Show t) = Constraints m t  where { }
  instance  (Monad m, Ord t, Show t) = Constraints m t  where { }

  foo :: (Constraints m t) = ...

This requires undecidable instances.  Is there a way to do this that
doesn't require non-98 features apart from multi-parameter type
classes?

If not, is there an argument for a language construction which supports
this idiom, analogous to type synonyms, except for type classes?

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: can a lazy language give fast code?

2002-07-31 Thread Andrew J Bromage

G'day all.

On Wed, Jul 31, 2002 at 09:59:31AM +0100, D. Tweed wrote:

 It's in saying this is warranted by `almost all'
 processes being bound by things other than throughput which may be true in
 the average sense, but I don't think that all programmers have almost all
 their programming tasks being dominated by something other than raw
 throughput but rather there are sets of programmers who have all of the
 tasks being dominated by the need something else (robustness, say) and
 some who have all their tasks being dominated by the need for raw
 throughput.

Fair enough.  I was speaking in generalities and average cases and
deliberately avoiding the special needs of many programmers and
applications.  I've worked in enterprise applications, web
applications and high-performance servers (both CPU-bound and
I/O-bound) and the concerns of all of them are different.

Perhaps if I cut down on the superlatives I can say something that
everyone agrees with: An awful lot of new code today is written in
languages like Visual Basic and Java, despite their relative
unsuitability for high throughput.  If it doesn't stop the use
of those kinds of languages, it shouldn't stop the use of Haskell
either, especially since Haskell arguably scales much better.

Therefore were I someone with a stake in the future of Haskell, I would
not be not overly concerned about these kinds of benchmarks.  Speed is
important, and it should be worked on, but it's not as important as
the things which Haskell already does better.

 You make very good points in what I've snipped below, again it's just
 the use of `most' in a way that implies (to me) taking an average as
 the representative of what everyone has to deal with that I `disagree
 with'.

Sure.  I wasn't implying that it was representative of what everyone has
to deal with.  It's certainly not representative of what I do for a
living, though it's pretty close to something I used to do.

Perhaps the quibble is over the word average.  While I don't think I
used that word, if I did, I'd mean mode rather than mean. :-)

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: can a lazy language give fast code?

2002-07-30 Thread Andrew J Bromage

G'day all.

On Tue, Jul 30, 2002 at 08:14:27AM +0100, D. Tweed wrote:

 Mmm, such statements really assume that there's a sensible meaning to
 `almost always' when applied to the set of all programmers, whereas I
 think a much more realistic assumption is that `there's lots of people out
 there, all with different priorities' and present things in way which 
 lets people perform their own evaluations.

Let me clarify what I meant by that and see if you still disagree.

Realistically, _most_ new software installations today (I deliberately
ignore legacy systems etc) are not overloaded, in that there are more
computrons available than are required to perform the task required
of them.  Of course this is partly because when you do a new
installation, you add more than you need because you expect to grow.

Secondly, most non-embedded CPUs in the world are not overloaded
either.  Chances are for a given desktop machine, it spends most of
its waking hours waiting for the next keystroke or mouse movement.
Web developers in particular know this: For the typical case, your
application server runs at the speed of the network.

If you agree with me so far, it follows that for most _new_ software,
throughput is not as great a consideration as other performance
metrics, because throughput measures the saturation point of your
system, and most new systems don't get saturated.

Of course I'm speaking in generalities, and there are an awful lot of
situations where throughput is an issue.  I've worked in a few of those
situations before.  I'm working in that situation right now, in fact.
Throughput measures are important to have if this is the situation that
you're in.

More information is good.  Perhaps the problem is I don't trust
everyone to use the information wisely?

 The problem with language
 benchmarks is not that they `over-rate' the importance of performance but
 that they assume per se that choice of language is a single-variable
 (execution speed) optimization problem; there's no attempt to measure the
 other items in your list, most especially flexibility.

While I agree with you here, I don't even claim that language benchmarks
of this kind over-rate the value of performance.  I claim that they
don't measure performance _at_all_!  They measure (in this case) two
possible measures of performance, namely memory usage and execution
speed, but ignores factors like scalability and latency, which are IMO
often more important.

 Of more
 concern to me is, when's the last time you actually got a well specified
 computational problem and a reasonable amount of time to write a carefully
 crafted program to solve it, (particularly when you had some reassurance
 that the very specification of what to solve wouldn't change after the
 first time you ran the code :-) )?

Perhaps the ICFP contests are actually fairer as benchmarks than as
competitions?

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: can a lazy language give fast code?

2002-07-30 Thread Andrew J Bromage

G'day all.

On Tue, Jul 30, 2002 at 01:57:58PM +0200, Josef Svenningsson wrote:

 I think the reason why Haskell compilers aren't generating any faster code
 is that there is a lack of competition among different compilers. And I
 think that the lack of competition depends on that noone wants to write a
 front-end to Haskell.

There's no competition in Haskell compilers because there is no
money in it.  It might not even be boring work in most cases.
The reality is that if there's no research quota or postgraduate
degree to be gained, nobody will fund a university or other research
institution to actually do the work.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: Writing a counter function

2002-06-30 Thread Andrew J Bromage

G'day all.

On Sun, Jun 30, 2002 at 01:51:56PM +0100, Peter G. Hancock wrote:

 Why not have a monad m a = Int - (a,Int) which is a state monad plus
 the operation bump : Int - m Int
 
  bump k n = (n,n+k) 

Oh, ye of insufficient genericity.  We can do better than that...

import MonadTrans

class (Monad m, Enum i) = MonadCounter i m | m - i where
bump :: Int - m i
 
newtype CounterT i m a = CounterT { runCounterT :: i - m (a,i) }

instance (Monad m, Enum i) = Monad (CounterT i m) where
return a = CounterT $ \x - return (a, x)
m = k  = CounterT $ \x - do
(a, x') - runCounterT m x
runCounterT (k a) x'
fail str = CounterT $ \_ - fail str

instance (Monad m, Enum i) = MonadCounter i (CounterT i m) where
bump k = CounterT $ \x -
let (next:_) = drop k [x..]
in return (x, next)   

instance (Enum i) = MonadTrans (CounterT i) where
lift m = CounterT $ \x - do
a - m
return (a, x)

evalCounterT :: (Monad m, Enum i) = CounterT i m a - i - m a
evalCounterT m x = do
(a, _) - runCounterT m x
return a

-- Example code follows

main :: IO ()
main = evalCounterT count 0

count :: CounterT Int IO ()
count = do
x1 - bump 1
x2 - bump 5
x3 - bump 0
x4 - bump 1
lift (putStrLn $ show [x1,x2,x3,x4])

I'd better get back to work now.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe



Re: type equivalency

2002-06-05 Thread Andrew J Bromage

G'day all.

On Wed, Jun 05, 2002 at 08:20:03PM -0500, Jon Cast wrote:

 I think you're confused about what the type declarations mean.  When
 you say
 
  sqrt :: Float - Float
 
 you're promising to operate over /all/ Floats.

That would be true of Haskell functions were constrained to be
total functions.  They are not.  Sqrt takes values of type Float,
but it just happens to be a partial function over that type.

 Unfortunately, Haskell
 doesn't allow {x :: Float | x = 0} as a type, nor does it provide a
 positive-only floating point type.

One general rule of strongly-typed programming is:  A program is type
correct if it is accepted by my favourite type checker.  A corollary
is that what you call a type, I reserve the right to call a
precondition.

Cheers,
Andrew Bromage
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe