Re: Writing a counter function

2002-07-02 Thread Matt Harden

John Hughes wrote:

 On Sun, 30 Jun 2002, Jon Cast wrote:
 
Mark Carroll [EMAIL PROTECTED] wrote:

On Sat, 29 Jun 2002, Samuel E. Moelius III wrote:
(snip)

Here's another not-exactly-what-you-wanted solution.  :)

(snip)

Do any of the experimental extensions to Haskell allow a
what-he-wanted solution? I couldn't arrange one in H98 without
something having an infinitely-recursive type signature.

That's because the problem requires an infinitely-recursive type.

(snip)

 
 It isn't particularly hard to implement this. Haskell typecheckers use
 unification to match types up; the only difference is that a graph
 unification algorithm would be needed instead. Such algorithms exist ---
 the only real difference is you have to remember what you're unifying to
 avoid falling into a loop when unifying graphs with cycles.
 
 The idea of adding this to Haskell has been proposed several times, but
 never implemented. And the reason for THAT is that it would make type
 errors significantly harder to understand.
 
 (snip)
 

Yes, but the dreaded Monomorphism Restriction was added for the same 
reason, wasn't it?  Haskell allows us to get around the M.R. by using 
explicit type signatures where required.  It seems to me that we could 
allow recursive types in the same way -- simply require a type signature 
for toplevel objects with recursive types.  Is there a reason why this 
wouldn't work?

Regards,

Matt Harden

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



Re: Writing a counter function

2002-07-01 Thread Frank Atanassow

Shlomi Fish wrote (on 29-06-02 17:30 +0300):
 
 I'm trying to write a counter function that would return a tuple whose
 first element is the current value and whose second element is a new
 counter.

John Hughes showed how to do this. Here is a closely related, more abstract
solution which employs existential types. First let me give a paradigmatic
example which is slightly different from what you want: streams.

  data Stream a = forall x. Stm x (x - a) (x - x)

Note that we hide the state type x. This lets us keep the implementation
hidden from the client.

  value (Stm state val next) = val state
  next (Stm state val next) = Stm (next state) val next
  both s = (value s, next s)
  
  unfold :: x - (x - a) - (x - x) - Stream a
  unfold state val next = Stm state val next
  
  -- the naturals
  nats1 = unfold 0 id succ
  -- value nats1 = 0
  -- value (next nats1) = 1
  -- value (next (next nats1)) = 2 ...

In the example above, we use an integer for the state, project it out when we
need a value, and increment it to get the next state. Here's another way to do
it, using a state which is not an integer.

  nats2 = unfold [0..] head tail

Here we just used an infinite list for the state. head :: List Int - Int, so
the state type is now different from method result type.

And here's an example where we use a step of 100 when we create the stream.

  -- step 100
  stm1 = unfold 5 id (+ 100)

But you wanted an object where we can choose the step at each point in
time. OK:

  data MyStream a = forall x. MyStm x (x - a) (a - x - x)
  
  myValue (MyStm state val next) = val state
  myNext arg (MyStm state val next) = MyStm (next arg state) val next
  myBoth arg s = (myValue s, myNext arg s)
  
  myUnfold :: x - (x - a) - (a - x - x) - MyStream a
  myUnfold state val next = MyStm state val next
  
  counter n = myUnfold n id (+)

Now the state-transforming function accepts an extra argument along with the
state. And in fact we were able to generalize the idea of stepping, since we
never had to mention integers or addition till the last line.

Easy, right? You can see the pattern for defining similar sorts datatypes
now. Hide the state type x with a forall, and, for each way of observing and/or
transforming the state, include a function of type x - ...

OO people call this a (functional) object. Mathematicians call it a
coalgebra. There is a notion of coalgebraic (or coinductive) datatype which is
dual to the notion of algebraic datatypes in Haskell; sometimes they're called
codatatypes. The analog of unfold is fold, of methods (sometimes called
destructors or observors) are data constructors, and of the state type is the
accumulator type which is the result of a fold. Some languages like Charity
support codatatypes directly, but in Haskell we can get the same effect with a
local forall.

Actually, you can make this even more OO-like using type classes, but things
seem to get messy if we keep the result type polymorphic so I'll fix it to
Integer:

  class CounterState x where
sValue :: x - Integer
sNext :: Integer - x - x
  
  data Counter = forall x. CounterState x = Counter x
  
  instance CounterState Integer where
sValue = id
sNext step state = step + state
  
  mkCounter :: Integer - Counter
  mkCounter n = Counter n

A disadvantage of this approach is that now you can only have one
implementation for each state type; with unfold, where we stored the functions
in the data constructor fields, we could give many implementations of the
methods for each state type. In OO terms, the type class approach is
class-based whereas the unfold approach is object-based.

The advantage, of course, is that you can use inheritance via the type class
inheritance now.

BTW, I hope that this note will not encourage the OO readers on this list to
objectify _everything_ now, because that leads (IMO) to twisted programs
which often emphasize the wrong sort of flexibility.

Both datatypes and codatatypes have their place:

  * A datatype is called for when you need a collection of finite-sized values
(lists, trees, etc.), and want to be able to traverse them easily. The
fold for a datatype does this for you, and is guaranteed to terminate.

  * A codatatype is called for when you have a collection of infinite-sized or
circular values (streams, automata, etc.) and you want to be able to index
arbitrarily into (grab subparts of) them, without possibility of error or
exposing the representation.

Note that you cannot generally traverse a value of a codatatype: if you try
to fold a stream, the computation will diverge.

On the other hand, you cannot index arbitrarily deeply into a value of a
datatype. Remember our stream example? We could have called the value
function head and the next function tail. You can always apply these to
a stream, and they will never fail. But if you try that with lists, you will
raise an error once you get to the end of it.

-- 
Frank Atanassow, Information  Computing 

Re: Writing a counter function

2002-07-01 Thread Jon Fairbairn

Mark Carroll [EMAIL PROTECTED] wrote:
 On Sun, 30 Jun 2002, Jon Fairbairn wrote:
 (snip)
  But there's the rub. It's not beautiful and it doesn't make
  much sense. I really wish we could get away from the How do
  I convert this imperative code snippet into Haskell
  questions into How do I solve this abstract problem?
 
 The question as originally posed didn't seem like it particularly needed
 something imperative though.

That largely misses the point. My objection is to the
mindset behind the question.

 the first bit is very similar to, say,
 
   counter a = (a, \to_add - counter (a + to_add))

Which looks to me like imperative programming. Indeed, the
Monad answer that I posted is imperative programming, it
just happens to be done in Haskell. Stepwise transformation
of a state is, on some occasions, the right answer to a
problem. Unfortunately in this thread we haven't been told
what the problem is. The question is of the form how do I
make a hammer? when a hammer is rarely the most appropriate
tool. That's what I'd like to get away from.

  Jón


-- 
Jón Fairbairn [EMAIL PROTECTED]
31 Chalmers Road [EMAIL PROTECTED]
Cambridge CB1 3SZ+44 1223 570179 (after 14:00 only, please!)


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



Re: Writing a counter function

2002-06-30 Thread John Hughes

On Sun, 30 Jun 2002, Jon Cast wrote:


 Mark Carroll [EMAIL PROTECTED] wrote:
  On Sat, 29 Jun 2002, Samuel E. Moelius III wrote:
  (snip)
   Here's another not-exactly-what-you-wanted solution.  :)
  (snip)

  Do any of the experimental extensions to Haskell allow a
  what-he-wanted solution? I couldn't arrange one in H98 without
  something having an infinitely-recursive type signature.

 That's because the problem requires an infinitely-recursive type.

 Consider Haskell:

 self-apply f = f f

 The *typing algorithm* (the thing that didn't complain in Lisp)
 proceeds roughly as follows:

 f is applied to at least one argument, so f must have type a - b.
 Therefore, f's argument (f) must have type a.  So, we conclude:

 f :: a - b
 f :: a

 But f can only have one type, so we set its types equal:

 a = a - b

 This is clearly recursive, right?

  so I'm wondering if it could be at all sane for Haskell to allow
  such stuff

 Sure.  All it has to do is:

 1. Create its own newtype in response to such things as
 `self-apply' above.

 2. Ensure that

 self-apply f = f f

 and

 self-apply' g = g g

 have the same type.  I would *love* to hear ideas on how to do that,
 but it's difficult.


It isn't particularly hard to implement this. Haskell typecheckers use
unification to match types up; the only difference is that a graph
unification algorithm would be needed instead. Such algorithms exist ---
the only real difference is you have to remember what you're unifying to
avoid falling into a loop when unifying graphs with cycles.

The idea of adding this to Haskell has been proposed several times, but
never implemented. And the reason for THAT is that it would make type
errors significantly harder to understand.

Consider

f x y = if x==0 then y else f (x-1)

(where I forgot the second parameter in the recursive call). We expect
this to be a type error, and indeed it is --- BECAUSE recursive types are
not allowed. If they were, this definition would be well-typed, with the
type

f :: Num a = a - bwhere b = b - b

You wouldn't get an error message unless you tried to CALL f, and perhaps
not even then. For example,

f 1 2 :: Num b = b where b = b - b

is well-typed! So you would probably eventually, somewhere else in the
program, see an error message of the form

ERROR - Illegal Haskell 98 class constraint in inferred type
*** Type   : Num b = b where b = b - b

This is enough to scare most people off the idea.

Think of all the times you've seen the error message

unification would give infinite type

It's not the most common kind of type error, but it does happen regularly,
at least to me. In every such case, the type error would be deferred in
the way I describe.

If I remember rightly, OCaml allows type recursion of this sort, but
restricts it to object types precisely to avoid these problems.

John Hughes

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



RE: Writing a counter function

2002-06-30 Thread A./C. Luis Pablo Michelena

I adjunt some code that i supose is what are you locking for.
Is based in a previous message (by jefu on 13 of june) idea from the
Haskell acumulator thread.
the prueba function is the translation of your example.
By the way, what's the purpose of this coding? (this is the type of
question: ok, I have a hammer, now, for what kind of nail it is useful?)
Cheers,
Luis Michelena
- Original Message -
From: Shlomi Fish [EMAIL PROTECTED]
To: Hannah Schroeter [EMAIL PROTECTED]
Cc: [EMAIL PROTECTED]
Sent: Saturday, June 29, 2002 12:58 PM
Subject: Re: Writing a counter function


 On Sat, 29 Jun 2002, Hannah Schroeter wrote:

  Hello!
 
  On Sat, Jun 29, 2002 at 06:23:27PM +0300, Shlomi Fish wrote:
   [...]
 
   Actually, I'd like a more generalized counter. Something that would
return
   both the number and a handler to add another number, which in turn
would
   return the new sum and a new handler, etc.
 
  That's just what lazy lists are for. The handler thing is done
  automatically thanks to lazy evaluation.
 
  I.e. countFrom n = n : countFrom (n + 1)
  or just countFrom n = [n..]
 

 No. But I want to generate an irregular series, which I determine the
 intervals between two consecutive numbers myself. E.g:

 let (num1, next1) = (counter 5)
 (num2, next2) = (next1 100)
 (num3, next3) = (next2 50) in
 [num1,num2,num3]

 Will have the numbers [5, 105, 155].

 Regards,

 Shlomi Fish

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



 --
 Shlomi Fish[EMAIL PROTECTED]
 Home Page: http://t2.technion.ac.il/~shlomif/
 Home E-mail:   [EMAIL PROTECTED]

 He who re-invents the wheel, understands much better how a wheel works.







contador.hs
Description: Binary data


Re: Writing a counter function

2002-06-30 Thread Mark Carroll

On Sun, 30 Jun 2002, Jon Fairbairn wrote:
(snip)
 But there's the rub. It's not beautiful and it doesn't make
 much sense. I really wish we could get away from the How do
 I convert this imperative code snippet into Haskell
 questions into How do I solve this abstract problem?

The question as originally posed didn't seem like it particularly needed
something imperative though. For instance, the Perl isn't strongly
imperative - it's largely just a list of declarations and functions (some
anonymous) where you can think of the variables as being locally-declared
constants. For instance, the first bit is very similar to, say,

counter a = (a, \to_add - counter (a + to_add))

I think that's very different from asking people to translate into Haskell
things where variables have their value change and whatever. Jon Cast's
observation makes more sense to me - it's not a imperative/functional
issue so much as a weak or strong typing issue.

(snip)
 I guess that the last $next on the last line should have
 been $next3, but I'm not certain, and I certainly have no
 idea what the programme is /for/.

Yes, I'm sure you're right there.

Thanks very much for sharing the monadic approach - I was curious as to if
monads could be used to break the recursion, and I didn't see anyone else
mention that. I've certainly found Jon Cast's, John Hughes' and Andrew
Bromage's articles interesting - it seems like this is a well-known issue
and Haskell currently lies on an attractive point on the tradeoff between
making things awkward and opening cans of worms.

-- Mark

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



Re: Writing a counter function

2002-06-30 Thread Peter G. Hancock


 lmichele  wrote (on Sun, 30 Jun 2002 at 09:26):

 By the way, what's the purpose of this coding? (this is the type of
 question: ok, I have a hammer, now, for what kind of nail it is useful?)

I would guess that something like the asked-for counter could be
useful if one is allocating ranges of addresses to things, for example
heap nodes when compiling a function body to instructions to build a graph.

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) 

Rgds, 
Peter Hancock
___
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: Writing a counter function

2002-06-29 Thread Shlomi Fish

On Sat, 29 Jun 2002, Mark Carroll wrote:

 On Sat, 29 Jun 2002, Shlomi Fish wrote:
 (snip)
  counter n = (n,(counter (n+1)))
 (snip)

 This doesn't work because you seem to be defining an infinitely deep tuple
 (1,(2,(3,(4,() which is naughty.

 I'm not really sure what alternative to suggest beyond [n .. ] without
 knowing more about what you are trying to do.


Actually, I'd like a more generalized counter. Something that would return
both the number and a handler to add another number, which in turn would
return the new sum and a new handler, etc.

Regards,

Shlomi Fish

 -- Mark

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




--
Shlomi Fish[EMAIL PROTECTED]
Home Page: http://t2.technion.ac.il/~shlomif/
Home E-mail:   [EMAIL PROTECTED]

He who re-invents the wheel, understands much better how a wheel works.

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



Re: Writing a counter function

2002-06-29 Thread Hannah Schroeter

Hello!

On Sat, Jun 29, 2002 at 06:23:27PM +0300, Shlomi Fish wrote:
 [...]

 Actually, I'd like a more generalized counter. Something that would return
 both the number and a handler to add another number, which in turn would
 return the new sum and a new handler, etc.

That's just what lazy lists are for. The handler thing is done
automatically thanks to lazy evaluation.

I.e. countFrom n = n : countFrom (n + 1)
or just countFrom n = [n..]

Kind regards,

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



Re: Writing a counter function

2002-06-29 Thread Shlomi Fish

On Sat, 29 Jun 2002, Hannah Schroeter wrote:

 Hello!

 On Sat, Jun 29, 2002 at 06:23:27PM +0300, Shlomi Fish wrote:
  [...]

  Actually, I'd like a more generalized counter. Something that would return
  both the number and a handler to add another number, which in turn would
  return the new sum and a new handler, etc.

 That's just what lazy lists are for. The handler thing is done
 automatically thanks to lazy evaluation.

 I.e. countFrom n = n : countFrom (n + 1)
 or just countFrom n = [n..]


No. But I want to generate an irregular series, which I determine the
intervals between two consecutive numbers myself. E.g:

let (num1, next1) = (counter 5)
(num2, next2) = (next1 100)
(num3, next3) = (next2 50) in
[num1,num2,num3]

Will have the numbers [5, 105, 155].

Regards,

Shlomi Fish

 Kind regards,

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




--
Shlomi Fish[EMAIL PROTECTED]
Home Page: http://t2.technion.ac.il/~shlomif/
Home E-mail:   [EMAIL PROTECTED]

He who re-invents the wheel, understands much better how a wheel works.

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



Re: Writing a counter function

2002-06-29 Thread Jon Fairbairn

Shlomi Fish wrote:
 No. But I want to generate an irregular series, which I determine the
 intervals between two consecutive numbers myself. E.g:
 
 let (num1, next1) = (counter 5)
 (num2, next2) = (next1 100)
 (num3, next3) = (next2 50) in
 [num1,num2,num3]
 
 Will have the numbers [5, 105, 155].

What do you mean by determine?

You can write 

sequence = iterate step_counter 0

if the interval between successive numbers is determined by
the current number, or

sequence = map f [1..]

if it's determined by the index in the sequence.

or 

sequence =  map snd $ iterate step_counter (0,-7)
step_counter (a,b) = (a+1, f a b) 

if it depends on both.


  Jón
-- 
Jón Fairbairn [EMAIL PROTECTED]
31 Chalmers Road [EMAIL PROTECTED]
Cambridge CB1 3SZ+44 1223 570179 (after 14:00 only, please!)


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



Re: Writing a counter function

2002-06-29 Thread Samuel E. Moelius III

 No. But I want to generate an irregular series, which I determine the
 intervals between two consecutive numbers myself. E.g:

 let (num1, next1) = (counter 5)
 (num2, next2) = (next1 100)
 (num3, next3) = (next2 50) in
 [num1,num2,num3]

 Will have the numbers [5, 105, 155].

Here's another not-exactly-what-you-wanted solution.  :)

If you don't mind changing your example to

let (num1, next1) = out (counter 5)
(num2, next2) = out (next1 100)
(num3, next3) = out (next2 50) in
[num1,num2,num3]

then, you can do this:

newtype Counter = MkCounter Int

counter :: Int - Counter
counter n = MkCounter n

out :: Counter - (Int,Int - Counter)
out (MkCounter n) = (n,MkCounter . (n +))

Sam Moelius

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



Re: Writing a counter function

2002-06-29 Thread Samuel E. Moelius III

 No. But I want to generate an irregular series, which I determine the
 intervals between two consecutive numbers myself. E.g:

 let (num1, next1) = (counter 5)
 (num2, next2) = (next1 100)
 (num3, next3) = (next2 50) in
 [num1,num2,num3]

 Will have the numbers [5, 105, 155].

Here's another not-exactly-what-you-wanted solution.  :)

If you don't mind changing your example to

let (num1, next1) = out (counter 5)
(num2, next2) = out (next1 100)
(num3, next3) = out (next2 50) in
[num1,num2,num3]

then, you can do this:

newtype Counter = MkCounter Int

counter :: Int - Counter
counter n = MkCounter n

out :: Counter - (Int,Int - Counter)
out (MkCounter n) = (n,MkCounter . (n +))

Sam Moelius

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



Re: Writing a counter function

2002-06-29 Thread Mark Carroll

On Sat, 29 Jun 2002, Samuel E. Moelius III wrote:
(snip)
 Here's another not-exactly-what-you-wanted solution.  :)
(snip)

Do any of the experimental extensions to Haskell allow a what-he-wanted
solution? I couldn't arrange one in H98 without something having an
infinitely-recursive type signature. I'm sure it would have been easy in
Lisp, and he already gave a Perl equivalent, so I'm wondering if it could
be at all sane for Haskell to allow such stuff and if Haskell is somehow
keeping us on the straight and narrow by disallowing the exact counter
that was originally requested.

The beauty of his request was that it was so simple and seemed to make
sense; I went ahead and tried to fulfill it before realising I couldn't
do it either.

-- Mark

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