Main

October 17, 2010

Installing Gtk2Hs on MacOS

After months of quiet yearning & frustration, I finally chewed into a big bullet and got Gtk2Hs installed on my Mac (OS 10.6.4 with GHC 6.12.3).

It was a long and harrowing affair. There were many confusing error messages. Ultimately, though, it was just a process of being patient with the various package managers and manually chasing down dependencies that are external to cabal. I had to use both Fink and MacPorts (and had to do lots of time-consuming update and selfupdate runs on these).

The Packages

Here are the packages I can remember having to install:

  • glib (from Fink)
  • gtk+2 (from Fink; NB -shlib and -dev packages)
  • freetype (??)
  • fontconfig (??)
  • cairo (from MacPorts)
  • pango (from MacPorts)

After all that, cabal install gtk just worked. I was able to run example programs from this Gtk2Hs tutorial and get the windows to pop up and work correctly.

Double-Fisting

Running Fink and MacPorts is like having bacon on your sausage; it's a little redundant and includes much cholesterol, but it's easy to do and feels good at the time. Why I did this, or felt I had to, is now lost to me as well.

Misc. Stumbling Blocks

It bears noting that gtk and gtk+ are essentially synonyms, so don't go hunting for one when you've got the other. On the other hand, a "2" suffix there is essential: gtk2 and gtk-2.0 have nothing to do with "gtk" or "gtk 1.x"; they're essentially different products.

Several times I thought I was set having installed, say, the gtk+2 and gtk+2-shlibs packages from Fink, only to receive a complaint that gtk+2.pc (the pkg-config data file which other packages use to locate gtk+2) was missing, which made me gnash my teeth. The fix was to also install gtk+2-dev, which apparently should be called gtk+2-without-which-nothing.

Wordsize Conundra

I've had a number of minor 32- vs 64-bit problems with GHC. It seems that Haskell Platform installs a 32-bit ghc. (Why would this be? GHC does run 64-bit on MacOS, doesn't it?). Sometimes package managers install fat versions of libraries, which is good, but when using both Fink and MacPorts, a library with 64-bit-only versions might shadow the other.

Somewhere in the darkness, I had a problem with zlib being 64-bit and hence unusable, and I couldn't determine which library was using it in order to muck with it (it wasn't gtk itself, glib, nor the Haskell zlib bindings). This was fixed by un- and re-installing GHC via Haskell Platform, which entailed a minor version upgrade as well as perhaps clearing any strange customizations that I can't deny making to the 32-bitness of my GHC install.

(I'm surprised there's not a better system for managing such library flavors on OS X. Couldn't we keep separate system paths like /usr/local/lib64 and such? Or would this be a greater nightmare in itself?)

Apologies

I wish this were a more helpful document. If you try this soon, and hit a snag, let me know and I'll either remember how I resolved it, or try to add to what's here.

September 9, 2008

motor sounds

Overheard on #haskell:

newsham: > let motor sounds = sounds "vroom! " in motor cycle

lambdabot: "vroom! vroom! vroom! vroom! vroom! vroom! vroom! vroom! vroom! vroom! vroo...

October 25, 2006

QuickCheck

Yesterday I had to prove that a certain algorithm (for a variation on lambda-lifting) was correct. I wasn't really sure that it was correct, so I took some time and coded it up in Haskell, then picked up enough knowledge of QuickCheck (the manual is more helpful than that raw interface file, but it uses HTML frames to crush your spirit) to write some randomized tests for the algorithm.

At first it caught some good bugs. Then it started succeeding on 100 random tests every time I ran it, so I feel reasonably certain that my algorithm is correct. I played around with the test-data generator to make sure it was generating terms that were deep enough and rich enough & to make sure that it never diverges, creating arbitrarily large terms. QuickCheck is reasonably nice this way.

So here's the Haskell code for my lambda-lifting algorithm, together with the QuickCheck tests (at the bottom). Note that there are some funny things in the syntax that aren't explained; they'll have to stay unexplained until I get done with the actual research I'm doing! Any day now...

February 15, 2006

3-body Problem in Haskell

So last week I implemented the n-body simulation in Erlang with message-passing, as an exploration of one-process-per-particle concurrency. Now I've got it up and running in Haskell, one version using STM and another using just MVars (individual atomic variables).

I found the shared-memory approach to be a more natural style than message-passing for this kind of physical model. My technique is simple: for each time step in simulation time, there is a shared vector of the states of the particles. Each process constantly tries to read the current moment values in sequence (blocking on those particles that are not filled in) and when it has read the whole thing, it performs its next-state computation on those states; it then writes its own next-state into the t+1 shared state vector. I want to reiterate that this technique works only because the processes necessarily work synchronously through simulation time.

Why MVars instead of STM? MVars implement a medium-power concurrency primitive—something like test-and-set—and it was plenty powerful enough to write this application without much fuss. Transactional memory is a significantly higher-level primitive, and its added flexibility wasn't necessary in this case. I'd like to make a loose argument that MVars are generally suffficient for the concurrency that's likely to be found in games.

The STM version works very similarly, but instead of just blocking on an unfilled particle-state, it retries. I believe that this is inefficient, because it's not necessary to repeat the reads that have already been performed at a given timestep: the variables in question are all single-assignment. Also, I suspect that the semantics of STM will lead to lots of retries, the threads tending to swarm around an unfilled variable and all of them retrying the whole transaction together. By contrast, the MVar implementation is efficient in the sense that when a state-variable is filled in, one waiting thread is woken, whose take/put action causes another waiting thread to be woken, etc.

Here's the code, for reference.

Continue reading "3-body Problem in Haskell" »

Crazy MacOS Header Values

For a while now, I've been getting horrible errors whenever I compile some package on my MacOS X machine. Some of the errors were of the form, MAC_OS_X_VERSION_MIN_REQUIRED must be <= MAC_OS_X_VERSION_MAX_ALLOWED. Others were complaining about some precompiled header being out of date.

It turned out that I had an environment variable, MACOSX_DEPLOYMENT_TARGET set to 10.3. I'd set this a long time ago because it alleviated problems that I seemed to have with every Perl module I tried to install.

I unset MACOSX_DEPLOYMENT_TARGET and ran the magical sudo fixprecomps. This fixed it.

December 6, 2005

Removing Duplicates From a Database

You've inserted multiple copies of the same data into a table. You want to get rid of all but one copy of each, and you want to keep the one with the lowest ID. You are using a DMBS with sub-selects, such as PostgreSQL.

You will do this:

select min(wine_id) as canonical from
        wine, (select distinct wine_name from wine) as names
        where wine.wine_name = names.wine_name
        group by names.wine_name;

If that looks right, you will proceed:

delete from wine where wine_id not in
    (select min(wine_id) as canonical from
        wine, (select distinct wine_name from wine) as names
        where wine.wine_name = names.wine_name
        group by names.wine_name);

More generally, if you have a table T with pkey T_ID and the desired data is unique on some column UNIQUE_COLUMN, it's:

select min(T_ID) as canonical from
        T, (select distinct UNIQUE_COLUMN from T) as equiv_classes
        where T.UNIQUE_COLUMN = equiv_classes.UNIQUE_COLUMN
        group by equiv_classes.UNIQUE_COLUMN;