[Haskell-cafe] Python vs Haskell in tying the knot

Matthew Brecknell matthew at brecknell.net
Thu Jul 16 01:27:40 EDT 2009


Robert Greayer wrote:
> Isn't tying the knot (in the way 'fib' does) straightforward with closures
> a la Python/Ruby/Smalltalk (without mutation)?
> Even in a syntactically clumsy language like Java, a
> tying-the-knot implementation equivalent to the canonical Haskell one is
> not difficult, e.g.
> 
> static L fibs = new L() {
>     public int head() { return 1; }
>     public L tail() {
>         return  new L() {
>             public int head() { return 1; }
>             public L tail() {
>                 return new L() {
>                     public int head() { return fibs.head() +
> fibs.tail().head(); }
>                     public L tail() { return zip(fibs.tail(),
> fibs.tail().tail()); }
>                 };
>             }
>         };
>     }
> };
> 
> Given a definition of list L and zip...
> 
> interface L { int head(); L tail(); }
> static L zip(final L l0, final L l1) {
>     return new L() {
>         public int head() { return l0.head() + l1.head(); }
>         public L tail() { return zip(l0.tail(), l1.tail()); }
>     };
> }

Are you sure there's not a super-linear time complexity hidden in there?

Unless Java compilers are clever enough to memoize this kind of code, I
think each subsequent call to the head() will just recurse all the way
down to the bottom an exponentially increasing number of times.

To simulate laziness, I think you would need to actually store fibs *as
data* somewhere, and you'd presumably need to simulate the process of
replacing a thunk with its value on its first evaluation.

In python, for example:

class value:
  def __init__(self, *value):
    self.value = value
  def __call__(self):
    return self.value

class thunk:
  def __init__(self, susp):
    self.susp = susp
  def __call__(self):
    try: return self.result
    except:
      self.result = self.susp()
      del self.susp
      return self.result

def tail(xs):
  x,r = xs()
  return r

def zipWithPlus(xs,ys):
  x,xr = xs()
  y,yr = ys()
  return x+y, thunk(lambda: zipWithPlus(xr,yr))

fibs = value(0, value(1, thunk(lambda: zipWithPlus(fibs, tail(fibs)))))

def fibgen():
  g = fibs
  while True:
    x,g = g()
    yield x

Needless to say: I prefer the Haskell!




More information about the Haskell-Cafe mailing list