Re: [Haskell-cafe] Re: Why binding to existing widget toolkits doesn't make any sense

2009-02-01 Thread Antony Courtney
>> My primary claim for success is that the
>> representation of Picture in Haven type checks and doesn't appeal to
>> IO; IO only creeps in when we attempt to render a Picture.
>
> You did something much more meaningful to me that what you say here.
>

Thanks. ;-)

> [...]
>
> I think what you did in Haven (based on memories of our conversations at the
> time and looking at your slides just now) is substantively different.  You
> gave precise, complete, and tractably simple *denotation* to your types.
> Complete enough to define the correctness of the rendering process.
>
>> Does the Haven API live up to your goal of semantic purity for a
>> vector graphics library?  If not, where specifically does it fall short?
>
> Yes, if my understanding about denotational precision and completeness is
> correct.  Is it?
>

Yes and no.

"Yes" in the sense that every type in Haven had a simple definition
using Haskell's type system and I used these types to specify
signatures of a set of functions for 2D geometry that was relatively
complete.

"No" in the sense that I never bothered to implement the various
geometric functions directly in Haskell; I depended on the underlying
implementation to do so.  For simple things like points, lines and
affine transforms I don't think this should be too controversial, but
it's a bit less clear for clipping and constructive area geometry on
complicated Bezier paths.  From a library user's point of view there
isn't much distinction between what I did and a pure implementation,
but I can't really claim it's a rigorous or complete semantics without
a pure reference implementation, and there's obviously no way to prove
claims such as "Shapes form a monoid" without giving a direct
definition of the composition and clipping operators.

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


Re: [Haskell-cafe] Re: Why binding to existing widget toolkits doesn't make any sense

2009-02-01 Thread Antony Courtney
Hi Conal,

On Sat, Jan 31, 2009 at 12:10 AM, Conal Elliott  wrote:
>> Hopefully some enterprising Haskell hacker will wrap Cairo in a nice
>> purely functional API.
>
> Jefferson Heard is working on such a thing, called Hieroglyph. [...]
>
> In the process, I realized more clearly that the *very goal* of making a
> purely functional wrapper around an imperative library leads to muddled
> thinking.  It's easy to hide the IO without really eliminating it from the
> semantics, especially if the goal is defined in terms of an IO-based
> library.  Much harder, and I think much more rewarding, is to design
> semantically, from the ground up, and then figure out how to implement the
> elegant semantics with the odds & ends at hand (like Cairo, OpenGL, GPU
> architectures, ...).

Exciting!

I was very much trying to achieve this with Haven back in 2002:

   http://www.haskell.org/haven

As the slides on that page state pretty explicitly, I tried to focus
on the semantics and to design a purely functional representation of a
vector graphics scene that was not tied to any particular
implementation.  My primary claim for success is that the
representation of Picture in Haven type checks and doesn't appeal to
IO; IO only creeps in when we attempt to render a Picture.

Does the Haven API live up to your goal of semantic purity for a
vector graphics library?  If not, where specifically does it fall
short?

I look forward to seeing and reading more about Hieroglyph.  The
typography and visual presentation of Jefferson's online booklet looks
fantastic.  A high quality, purely functional vector graphics API for
Haskell with portable and robust implementations will be a great thing
for the Haskell world.

Regards,

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


Re: [Haskell-cafe] Re: Why binding to existing widget toolkits doesn't make any sense

2009-01-30 Thread Antony Courtney
On Fri, Jan 30, 2009 at 4:25 PM, Bryan O'Sullivan  wrote:
> On Fri, Jan 30, 2009 at 1:11 PM, Antony Courtney 
> wrote:
>>
>> A 2-D vector graphics library such as Java2D ( or Quartz on OS/X or
>> GDI+ on Windows ) supports things like computing tight bounding
>> rectangles for arbitrary shapes, hit testing for determining whether a
>> point is inside or outside a shape and constructive area geometry for
>> shape compositing and clipping without dropping down to a raster
>> representation.
>
> These are the kinds of capabilities provided by Cairo, which is very
> pleasant to use (PDF-style imaging model) and quite portable. There are
> already Cairo bindings provided by gtk2hs, too.
>

Hi Bryan,

Nice to hear from you!  Been a while...

Just had a quick look and it does indeed appear that Cairo now
supports some of the features I mention above (bounds calculations and
hit testing).  Cairo has clearly come a long way from when I was last
working on Fruit and Haven in 2003/2004;  back then it looked like it
only provided a way to render or rasterize vector graphics on to
bitmap surfaces and not much else.

It's not clear to me if the Cairo API in its current form supports
vector-level clipping or constructive area geometry, and it looks like
the API is still pretty render-centric (e.g. is it possible to obtain
the vector representation of rendering text in a particular font?).
That might make it challenging to use Cairo for something like the
Haven API, but maybe one can live without that level of generality.

In any case: delighted to see progress on this front!  Hopefully some
enterprising Haskell hacker will wrap Cairo in a nice purely
functional API.

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


Re: [Haskell-cafe] Re: Why binding to existing widget toolkits doesn't make any sense

2009-01-30 Thread Antony Courtney
On Fri, Jan 30, 2009 at 3:50 PM, Achim Schneider  wrote:
> Antony Courtney  wrote:
>
>> One issue I think you may encounter, though, is that last time I
>> looked, there was still no high-quality, widely available
>> cross-platform 2-D vector graphics library in C or C++! [...]
>>
> Xrender. It appears to map exceptionally well onto FP, is available
> everywhere X is available (that includes Windoze and OS X) and usually
> is heavily hardware-accelerated. Additionally, we already have a pure
> Haskell implementation of the client-side protocol included in XHB.
>

According to Wikipedia:

The X Rendering Extension (Render or XRender) is an X Window System
extension to implement Porter-Duff image compositing in
the X server.

Porter-Duff image compositing is cool and useful, but it's at a much
lower level than what I meant by 2-D vector graphics library.

A 2-D vector graphics library such as Java2D ( or Quartz on OS/X or
GDI+ on Windows ) supports things like computing tight bounding
rectangles for arbitrary shapes, hit testing for determining whether a
point is inside or outside a shape and constructive area geometry for
shape compositing and clipping without dropping down to a raster
representation.  Pretty clear how to build a 2-D Scenegraph library
like Piccolo on top of Java2D or Quartz or GDI+; much less clear to me
how to build something like that directly on top of XRender.

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


Re: [Haskell-cafe] Re: Why binding to existing widget toolkits doesn't make any sense

2009-01-30 Thread Antony Courtney
On Fri, Jan 30, 2009 at 2:21 AM, Evan Laforge  wrote:
>> Conal> As Meister Eckhart said, "Only the hand that erases can write the
>> Conal> true thing."
>>
>> Nicely said...
>>
>> I'm sure you're not the only one desiring to write GUI in "genuinely
>> functional" toolkit, but, being realistic and considering how many people
>> are working on bindings for those "legacy libraries", I doubt we'll see
>> something written from the scratch and usable for "Real World Haskell"
>> soon ;)
>
> I'm vaguely aware that there has been a line of functional-style
> widget libraries, from fudgets down to developments like arrows and
> FRP and the various libraries built on that.  The fact that the
> libraries have continued to be research projects and beget further
> research projects implies that they've had some critical flaws that
> needed further research.  Is there a description somewhere of what the
> critical flaws have been and are, and what the current problems are to
> solve before we can finally have a practical declarative and
> compositional UI library?

Here is a message I sent to Conal and the yampa-users list about a
year ago with my thoughts on this very topic.  Hope this helps.

Kind Regards,

 -Antony

Date: Fri, 22 Feb 2008 09:35:48 -0500
From: "Antony Courtney" 
To: "Conal Elliott" 
Subject: Re: Fruit
Cc: Yampa-Users 

Hi Conal (and Paul and Henrik and everyone else!),

Apologies for the delay in replying.  Paul is quite right about my day
job keeping me quite busy, although I've been enjoying watching the
discussion.

I think there are several reasons that Fruit never really caught on.

First and foremost, Fruit never provided anything close to the full
suite of GUI components found in modern UI toolkits (buttons, sliders,
scrollbars, check-boxes, text fields, combo boxes, split panes, tabs,
menus, toolbars, etc. etc.).  I never got much further than
implementing labels, buttons, text fields and maybe one or two other
components.   This wasn't quite as limiting as one might think as
Fruit subsumed everything that was possible to do in Fran and had a
very powerful vector graphics library underneath (Haven) so one could
use Fruit to implement quite sophisticated interactive animations and
combine them with the library of other GUI components.  But one
couldn't realistically expect to download and install Fruit and just
start using it to write the next great full-fledged GUI app. in
Haskell.

This is related to the second reason Fruit didn't catch on, which is
that Fruit was built directly on an interactive graphics library, not
a standard GUI toolkit.  I think that this was the right first step
for our research goals of giving a rigorous answer to the question of
"What is a formal model of a GUI?".  But from both a pragmatic and
research point of view, the next interesting research problem to solve
would be:  "How can we present the Fruit programming interface (which
offers a clean, simple, pure semantic model of a GUI), but implement
the individual GUI components using a standard GUI toolkit?".  This is
actually an interesting implementation challenge since Yampa's
switching and dynamics collections mean that absolutely anything can
happen to the widget hierarchy from one time step to the next.  You
really, really don't want to destroy and rebuild the entire widget
hierarchy of the application at every time step, so figuring out how
to do some kind of sample-to-sample differencing of the widget
hierarchy would be essential.  It's not obvious how to do this, which
is probably why FranTk and wxFruit took a bit more of a pragmatic
approach and exposed bits of the imperative programming model of the
underlying toolkit for widget creation and destruction.

Another important point is that even the bits of fruit that were
implemented involved a number of different dependent parts, so it was
always a bit more work to download and install than I would have
liked.  I was hell-bent on using a vector graphics library as the
foundation. Unfortunately there was no widely-available cross-platform
vector graphics library implemented in C.  So I chose to use Java2D,
which meant that I had to build my own system for Haskell/Java
interoperability (GCJNI, later hsjni) and a Haskell vector graphics
library (Haven) on top of that.  So if one wanted to play with fruit,
it was necessary to download and install Java, gcjni, haven, yampa and
fruit.  And in the early days one also had to grab greencard and the
arrows preprocessor!  I think we did a reasonable job of packaging
these given the severe limits of Haskell packaging and build tools at
the time, but it was a ton of work and still never made it easy enough
for others to experiment casually.

Apart from the practicalities of the impl

Re: [Haskell-cafe] Problems with building GCJNI 1.2

2005-02-21 Thread Antony Courtney
Hi,
Sorry for not jumping in on this discussion sooner.
I am the author of GCJNI.  GCJNI was developed back when Hugs was the
dominant Haskell implementation and GreenCard was the easiest/best way
to do foreign language bindings for Haskell because the FFI proposal
was still in the formative stages.
These days, the Haskell FFI addendum is stable and widely implemented,
ghc has become much more widely available and easy to install and use,
and (without wishing to sound harsh), GreenCard's FFI code generator
was broken and useless the last time I tried to use it (a few years
ago).
I actually ported GCJNI to the Haskell FFI a few years ago, getting
rid of ALL use of GreenCard.  I used ghc's 'hsc2hs' tool to help with
the marshalling, and made no attempt to port to hugs.  I called this
newer system 'hsjni'.  It worked very well for my needs (using the 
Java2D rendering engine as the back-end for a prototype Haskell GUI 
system).  I never released hsjni simply due to lack of time while 
finishing my thesis.

I invested a little effort in trying to test hsjni with the latest JDK
and get a release together in December, but it got snagged on a silly
little bug in hsc2hs's handling of paths which have embedded spaces.
A minor bug, to be sure, but since the default installation location for 
the JDK under Windows is under "C:\Program Files", the bug meant hsjni 
couldn't work out-of-the-box for the most common installation of the 
prerequisites.  Simon Marlow has since fixed this bug in CVS head;  I'm 
just waiting for the next release of ghc with this fix available before 
I try again.

If you think you'd be interested in having a shot at building 'hsjni'
(or you are interested in maintaining it), let me know, and I'll make
the sources available for you.  Caveat is that I haven't tested it
since JDK 1.3, because of this hsc2hs issue.
My appologies for not mentioning any of the above on the GCJNI web page. 
 Hopefully the whole GCJNI release and web pages can be deprecated 
soon, with hsjni offered in its place.

Kind Regards,
-Antony
--
Antony Courtneyemail: [EMAIL PROTECTED]
New York, NY WWW: http://www.apocalypse.org/~antony
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Problems with building GCJNI 1.2

2005-02-21 Thread Antony Courtney
Hi,

Sorry for not jumping in on this discussion sooner.

I am the author of GCJNI.  GCJNI was developed back when Hugs was the
dominant Haskell implementation and GreenCard was the easiest/best way
to do foreign language bindings for Haskell because the FFI proposal
was still in the formative stages.

These days, the Haskell FFI addendum is stable and widely implemented,
ghc has become much more widely available and easy to install and use,
and (without wishing to sound harsh), GreenCard's FFI code generator
was broken and useless the last time I tried to use it (a few years
ago).

I actually ported GCJNI to the Haskell FFI a few years ago, getting
rid of ALL use of GreenCard.  I used ghc's 'hsc2hs' tool to help with
the marshalling, and made no attempt to port to hugs.  I called this
newer system 'hsjni', but never released it due simply to lack of time
while finishing my thesis.

I invested a little effort in trying to test hsjni with the latest JDK
and get a release together in December, but it got snagged on a silly
little bug in hsc2hs's handling of paths which have embedded spaces. 
Simon Marlow has since fixed this bug in CVS head;  I'm just waiting
for the next release of ghc with this fix available before I try
again.

If you think you'd be interested in having a shot at building 'hsjni'
(or you are interested in maintaining it), let me know, and I'll make
the sources available for you.  Caveat is that I haven't tested it
since JDK 1.3, because of this hsc2hs issue.  One can easily work
around the hsc2hs path handling issue by installing the latest JDK in
a location without a space in the filename; but since the default
install location under Windows is under "C:\Program Files", I wasn't
interested in shipping a release that wouldn't work with the most
common default case.

Please accept my sincere appology for not mentioning any of the above
on the GCJNI web page.  Hopefully it will just all be replaced with
hsjni in the near future.

Kind Regards,

 -Antony

On Fri, 18 Feb 2005 20:45:14 +0100, Lemmih <[EMAIL PROTECTED]> wrote:
> On Fri, 18 Feb 2005 20:37:35 +0100, Dmitri Pissarenko
> <[EMAIL PROTECTED]> wrote:
> > >>>Did you import Foreign.GreenCard?
> >
> > Now, I replaced "import StdDIS" by "import Foreign.GreenCard".
> 
> The library apparently wasn't designed for newer versions of GreenCard
> and it may be too old to fix easily.
> 
> --
> Friendly,
>  Lemmih
> ___
> Haskell-Cafe mailing list
> Haskell-Cafe@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
> 
>
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Yet Another Monad Tutorial

2003-08-14 Thread Antony Courtney
Peter G. Hancock wrote:
Jeff Newbern wrote (on Tue, 12 Aug 2003 at 17:20):
?
> The functions exported from the IO module do not
> perform I/O themselves. They return I/O actions, which describe an I/O
> operation to be performed. The I/O actions are combined within the IO
> monad (in a purely functional manner) to create more complex I/O
> actions, resulting in the final I/O action that is the main value of the
> program. The result of the Haskell compiler is an executable function
> incorporating the main I/O action. Executing the program "applies" this
> ultimate I/O action to the outside world to produce a new state of the
> world. 

That seems to me the wrong thing to say.  There is no application.  Whether
or not the word is put in quotes, it is something involving a function
and an argument.  An IO action is not a function.
So then, in your view, what *is* an IO action?

One conceptual model is that an IO action with type (IO a) denotes a 
function of type World -> (World,a).  Given that model, "applying" an IO 
action to the external world seems like a perfectly reasonable account 
of executing such an action.

	-antony

--
Antony Courtney
Grad. Student, Dept. of Computer Science, Yale University
[EMAIL PROTECTED]  http://www.apocalypse.org/pub/u/antony
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: idiom for producing comma-seperated lists?

2003-08-14 Thread Antony Courtney
Ketil Z. Malde wrote:
Antony Courtney <[EMAIL PROTECTED]> writes:


-- Example: format a list of strings, using a comma as a seperator:
mkSepStr :: [String] -> String
mkSepStr xs = foldrs (\x s -> x ++ ", " ++ s) "" xs
t0 = mkSepStr []   -- ==> ""
t1 = mkSepStr ["hello"]-- ==> "hello"
t2 = mkSepStr ["10","20","30"] -- ==> "10, 20, 30"
What do the rest of you do to solve this particular problem?


Uh, concat and intersperse?

Yep, that'll do the trick.

Thanks for all the lightnin-fast responses.  Appologies for overlooking 
this!

	-antony

--
Antony Courtney
Grad. Student, Dept. of Computer Science, Yale University
[EMAIL PROTECTED]  http://www.apocalypse.org/pub/u/antony
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


idiom for producing comma-seperated lists?

2003-08-11 Thread Antony Courtney
I often need to format a list of strings using some character as a 
*seperator* rather than a terminator for the items.  Is there some 
simple combinator or idiom from the Prelude or standard libraries that 
could be used for this purpose?

I ended up defining my own variation on foldr1 to solve this (code 
below), but I'd be much happier using some more standard solution:

-- A variation on foldr1 that takes an extra argument to be returned if
-- the list is empty.
foldrs :: (a -> a -> a) -> a -> [a] -> a
foldrs f z [] = z
foldrs f _ xs = foldr1 f xs
-- Example: format a list of strings, using a comma as a seperator:
mkSepStr :: [String] -> String
mkSepStr xs = foldrs (\x s -> x ++ ", " ++ s) "" xs
t0 = mkSepStr []   -- ==> ""
t1 = mkSepStr ["hello"]-- ==> "hello"
t2 = mkSepStr ["10","20","30"] -- ==> "10, 20, 30"
What do the rest of you do to solve this particular problem?  If there 
isn't a standard solution, perhaps something like foldrs would be a 
useful addition to the Prelude.

Thanks,

	-antony

--
Antony Courtney
Grad. Student, Dept. of Computer Science, Yale University
[EMAIL PROTECTED]  http://www.apocalypse.org/pub/u/antony
___
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 Antony Courtney
Hi Sarah,

Representing cyclic structures is indeed somewhat tricky in a pure 
functional language.  The obvious representation (representing the link 
structure implicitly in an algebraic data type) doesn't work, because 
you can't obvserve cycles.

I recommend checking out two pieces of work in this area:

1.  Martin Erwig's work on inductive representations of graphs:

  Inductive Graphs and Functional Graph Algorithms, Martin Erwig
  Journal of Functional Programming Vol. 11, No. 5, 467-492, 2001
available from:

  http://cs.oregonstate.edu/~erwig/papers/abstracts.html#JFP01

2.  Koen Claessen and David Sands' work on observable sharing:

  Observable Sharing for Functional Circuit Description,
Koen Claessen, David Sands, published at ASIAN '99, in Phuket, Thailand
available from:

  http://www.math.chalmers.se/~koen/Papers/obs-shar.ps

Hope that helps,

	-Antony

--
Antony Courtney
Grad. Student, Dept. of Computer Science, Yale University
[EMAIL PROTECTED]  http://www.apocalypse.org/pub/u/antony
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: Ex 9.9 in Paul Hudak's book

2002-03-31 Thread Antony Courtney

Ludovic Kuty wrote:
> The exercise is short.
> 
> First, he defines a "fix" function:
>   fix f = f (fix f)
> Which has the type (a -> a) -> a
> 
> Then the function "remainder":
>   remainder :: Integer -> Integer -> Integer
>   remainder a b = if a < b then a else remainder (a - b) b
> 
> The function fix, has far as i understand the matter, has no base case.
> So if someone wants to evaluate it, it will indefinitely apply the function f
> to itself, leading the hugs interpreter to its end.

As a hint (but not a solution), attached are my own notes from when I 
was puzzling through fixed points myself a few years ago.  This is a 
literate Haskell script that you can load into hugs and run.  Note that 
my 'y' is the same as your 'fix'.  I use y to derive a factorial 
function (fact) in terms of y that does terminate.

("Malkovich" is an obscure reference to the scene in the film "Being 
John Malkovich" where Malkovich goes through his own portal... :-))

-antony

-- 
Antony Courtney
Grad. Student, Dept. of Computer Science, Yale University
[EMAIL PROTECTED]  http://www.apocalypse.org/pub/u/antony



A definition of the Y combinator in Haskell.

Valery calls this the "stupid" definition of the Y combinator since
it uses Haskell's recursion.

Of course, if it's the "stupid" definition, and it's not immediately
obvious to me why it works, wellthere's only one conclusion.  
Thankfully, however, I have other redeeming qualities.  :-)

Here was Valery's original formulation:

   y = \f -> let x = f x in x

But, of course, Paul pointed out that this definition of y 
can be simplified to:

>
> y f = f (y f)


Now let's define a generator to test out y:

> factGen = \f -> \n -> if n==0 then 1 else n * f (n-1)
> fact = y factGen

Sure enough, if we run this under Hugs, it works:

Main> fact 3
6
Main>

Wow.  mind-blowing.  

Unfortunately, I don't have "stepper" for Haskell, so I better walk
through this myself to figure out what's going on.

First, some types:

y :: (a -> a) -> a
factGen :: (Integer -> Integer) -> Integer -> Integer
(Note, though, that since -> associates to the right, this is the same as:
   (Integer -> Integer) -> (Integer -> Integer)
fact :: Integer -> Integer

which all makes sense.

Now let's trace through an evaluation like:

fact 3
==> (y factGen) 3
==> ((\f -> let x = f x in x) factGen) 3
==> (let x = factGen x in x) 3
(OK, I think this is the crucial step:
==> (let x = factGen x in (factGen x)) 3
==> (let x = factGen x in ((\f -> \n -> if n==0 then 1 else n * f (n-1)) x)) 3
==> (let x = factGen x in (\n -> if n==0 then 1 else n * x (n-1))) 3
==> let x = factGen x in (if 3==0 then 1 else 3 * x (3-1))
==> let x = factGen x in (3 * x (3-1))
==> let x = factGen x in (3 * x 2)
==> let x = factGen x in (3 * (factGen x) 2)
==> let x = factGen x in (3 * (factGen x) 2)

The above was with the original definition of y.
Of course, this should be easier to follow with Paul's definition:
fact 3
==> (y factGen) 3
==> (factGen (y factGen)) 3
==> ((\f -> \n -> if n==0 then 1 else n * f (n-1)) (y factGen)) 3
==> if 3==0 then 1 else 3 * ((y factGen) 2)
==> 3 * ((y factGen) 2)
which obviously works.

Ok, so what's going is this:

x is bound to (factGen x).
(factGen x) unfolds to: ((\f -> \n -> if n==0 then 1 else n * f (n-1)) x)
which reduces to: \n -> if n==0 then 1 else n * x (n-1)
but the "x" in the above will itself just unfold to (factGen x), yielding
yet another recursive call!

Note, too, that x has "type" Integer->Integer, although it is really a
name for a *computation* that produces such a function when evaluated.

mind-blowing.

Another way to think of it:  If f is Malkovich, then:
x
<--> (Malkovich x)
<--> (Malkovich (Malkovich x))
<--> (Malkovich (Malkovich (Malkovich x)))
<--> (Malkovich (Malkovich (Malkovich (Malkovich ... (Malkovich x)
i.e. x unfolds to as many applications of "Malkovich" as we need to
eventually reach Malkovich's fixed point.

Of course, I used <--> just to indicate equivalence, not an actual
reduction sequence.  In normal order evaluation, we only unfold x when
it's value is needed.  But we'll keep doing that until we hit a fixed
point (or diverge).