Tuesday, December 14, 2010

installing gtkglext Haskell bindings with gtk-osx

I just managed to install the Haskell bindings to gtkglext with the quartz-based gtk-osx, and I want to record the necessary steps so I don't forget. This assumes you have a working ghc (ghc-7), gtk-osx, and XCode. As a quick overview, I needed to do the following:
  1. install gtkglext (c library)
  2. install gtk (Haskell package)
  3. install gtkglext (Haskell package)
1. Install gtkglext (c)

I downloaded the "Quartz hack full patched source" and followed the instructions at http://answerpot.com/showthread.php?324502-GtkGLExt+OS+X+Quartz+hack+patch. There are a few problems:
The file "docs/reference/gtkglext/html/index.sgml" doesn't exist.
The headers aren't installed.
Several references are made to undefined constants. Unfortunately this error doesn't show up until much later, when GHC tries to link every symbol under the sun.
jhbuild shell
tar -xf gtkglext-1.2.0.osx-hack.tar
cd gtkglext-1.2.0
patch -p1 < gtkglext_c.patch
./configure && make
touch docs/reference/gtkglext/html/index.sgml
sudo make install

2. Install gtk (Haskell)

The Haskell package "gtk" currently (as of gtk-0.12.0) doesn't build with a quartz-based gtk+. I downloaded the source ("cabal unpack") and edited the file "Graphics/UI/Gtk/General/Structs.hsc" to disable the drawableGetID function.

jhbuild shell
cabal unpack gtk
cd gtk
patch -p1 < gtk.patch
cabal install
If you installed the gtkglext libraries to a standard folder this should be all that's necessary. If cabal can't find gdkglext-quartz or gtkglext-quartz, you'll need to add the library paths at this stage.

3. Install gtkglext (Haskell package)

This was painful.

There are a few different problems to deal with:
1. The gtkglext install didn't install the headers, so we need to specify them manually.
2. We're not using pkg-config, so we edit the gtkglext.cabal file, remove the pkg-config check, and specify the libraries to link to.
3. Several symbols are undefined in gtkglext, so we need to remove references to them from the Haskell source. The undefined symbols are:
  • gdk_gl_config_get_screen
  • gdk_gl_config_get_depth
  • gdk_gl_context_get_gl_config
  • gdk_gl_context_get_share_list
  • gdk_gl_context_is_direct
  • gdk_gl_context_get_render_type
AFAICT these were never defined in gtkglext, although they're listed in the headers.

There's also another argument to glWindowNew, which we need to add.

Finally, the demo program needs to be patched, otherwise it just sits there and doesn't update.

So execute the following, replacing PATH_TO_GTKGLEXT with wherever you unpacked/built gtkglext:

jhbuild shell
cabal unpack gtkglext
cd gtkglext-0.12.0
patch -p1 < gtkglext.patch
cabal install --extra-include-dir="PATH_TO_GTKGLEXT" --extra-include-dir="PATH_TO_GTKGLEXT/gdk" --extra-include-dir="$PREFIX/include/cairo/" --extra-include-dir="$PREFIX/include/glib-2.0/" --extra-include-dir="$PREFIX/lib/glib-2.0/include/" --extra-include-dir="$PREFIX/include/gtk-2.0/" --extra-include-dir="$PREFIX/include/pango-1.0/" --extra-include-dir="$PREFIX/include/atk-1.0/" --extra-include-dir="$PREFIX/lib/gtk-2.0/include/"
cd demo
make
./RotatingCube
And you should get a new window with a colorful cube, spinning in full OpenGL glory.

I don't know why it's necessary to specify all the gtk+ header locations manually here, when they're automatically found for building gtk.

The patch files can be downloaded from here.

Wednesday, December 9, 2009

*rant* - Microsoft, why do you do this to me?

(Recent discussions of the Windows platform have led me to disclose my opinion of a particular infelicity of ASP.Net)

Background: a few years ago, my day job consisted primarily of web development using ASP.Net v.2 and C#. Overall I quite enjoyed the experience. C# is IMHO a pretty decent language, and .NET is alright too. Everything works perfectly smoothly, until you travel off the beaten path.

If Perl's maxim is "There's more than one way to do it," then ASP.Net's is "There's more than one way to do it, but the likelihood of any given way working properly is inversely proportional to the number of ways to do it."

I had an interface, let's call it IHasData. This interface provided a function to pretty-print information associated with different types of events for a web calendar. So far so good. I wanted to display several different events in a GridView. "Simple," I said to myself, "just put them in a generic collection and assign the data source." So I did that, with code pretty much like this (apologies if the syntax is off; I haven't done C# for years):

GridView gv = new GridView();
ListSet events = new ListSet();

//code to fill the events set omitted.

gv.DataSource = events;

and everything should work like a charm. Except, now my page sometimes threw an exception.

It was an odd exception too, indicating that some particular IHasData instance didn't have an unrelated method (i.e. not exposed by IHasData) that wasn't supposed to be in that class anyway. My code was only using IHasData methods; the types ensured that nothing else could be accessed. So why was .Net trying to load something unrelated?

The actual problem was pretty clear. .Net was using reflection on the first element of the data source, and assuming that all remaining elements would have exactly the same type. .Net's reflection facilities are quite powerful, and once they're in play all members of a class are available, regardless of the type used to access it. Not necessarily a good idea for a generic list on interfaces. I have no idea why the GridView has this behavior, but it makes me sad. Particularly since it could have been done right and been that much more useful.

Ultimately this was only one of a host of problems that stemmed from trying to use NHibernate, persistent objects, and .Net built-in features like the ObjectDataSource. It would have been really slick if it worked as advertised, but there were some significant design flaws and the implementation was half-baked at best. I did eventually create a framework that filled most of the gaps, but I was making up for functionality the framework was supposed to provide and didn't. Not good.

Sunday, November 15, 2009

iteratee status

I haven't posted for a while, so I wanted to provide a small update. I've been working on the following updates:

1) Providing integrated pure and monadic iteratees. I've just implemented an iteratee class, but I don't yet know how performance compares to the original version. I'm also considering a GADT version, but I suspect it'll look ugly.

2) Exception and error handling. Haven't done much work, but I've been thinking about this and have some ideas to implement. Strings are not sufficient.

3) Reorganizing the modules. Most of this is done, although to some extent the final version will depend upon results of item 1.

4) Performance. I've been developing a benchmark suite utilizing Criterion. The ultimate goal is to use this suite to compare performance of multiple versions of the library.

5) Parsec integration. This resulted from a user request. It's useful enough that I'll probably integrate it into the main distribution.

Also, there's a trac instance available.

Wednesday, August 12, 2009

Restricted-element containers and maps

Given the perspective we have now, I think it's a little hard to imagine how ground-breaking the concept of type classes were when they were first introduced in Haskell. I think it says a lot that, after the Haskell Committee decided upon their inclusion, they made type classes an integral part of the language. Lest you think that's an exaggeration, can you imagine what Haskell would like like today without, e.g. Num, Functor, or Monad?

As a consequence of using a new idea, some areas that Haskell (and Haskellers!) currently struggle with are related to type classes. One area in particular are containers and type classes. A "Holy Grail" of sorts for Haskellers is the creation of a container type class that provides all the useful container functions. Ideally, all useful container types would be able to be instances of this class.

One package that provides this sort of functionality is John Goerzon's excellent ListLike package, http://hackage.haskell.org/package/ListLike.

ListLike provides (in addition to many others), the functions "map" and "rigidMap". Why two? The difference is in the types:

> class ListLike full item | full -> item where
> map :: ListLike full' item' => (item -> item') -> full -> full'
> rigidMap :: (item -> item) -> full -> full

The standard map (and Functor's fmap) allow mapping from a container of any element type to a container of any other element type. rigidMap requires that both the input and output elements and containers have the same type. This is very useful for monomorphic containers. If you provide an instance for ByteString Word8, you can't use the native 'map' because it only maps over elements of the same type since Word8 is the only valid element type. ListLike's default 'map' function builds a new container by destructing and reconstructing the old one. This is highly inefficient compared to native maps, but is the only way to write the function that satisfies the type signature. Even though "ListLike ByteString Word8" is the only instance that can exist, there's no way to prove it to the compiler. 'rigidMap', by further restricting the types, can use the native map, and is therefore much more efficient when it can be used.

Unfortunately there is another case, one that I expect will become more common as certain high-performance libraries become more widespread. Many interesting containers are polymorphic but require class contexts on their elements. Examples are the UVector and StorableVector packages, which require elements to be instances of UA and Storable respectively.

Here's the problem. Using StorableVector as an example, these packages often provide the following map:

> map :: (Storable item, Storable item') => (item -> item') -> Vector item -> Vector item'

How can we use this in ListLike? It could certainly be used directly for 'rigidMap', but what about 'map'? Unfortunately that isn't possible because of the class restriction on the output element type. The type variable for that element isn't mentioned in the class definition (i.e. it doesn't appear in the instance head). Since it's not in the instance head, it isn't possible to put a class context on it. If you fall back to the default 'map' instance any possible efficiency gains are lost.

One solution is to include the output item type in the class definition, but that would require users to put an extra type variable in every time the class context is used, which is a waste for something that is only used for one function.

I think the correct approach is to create a new type class, call it LooseMap, as follows:


> class (ListLike full item, ListLike full' item') => LooseMap full item full' item' where
> looseMap :: (item -> item') -> full -> full'
>
> --StorableVector instance
> instance (Storable el, Storable el') => LooseMap (Vector el) el (Vector el') el' where
> looseMap = Data.StorableVector.map

Of course completely polymorphic containers (e.g. List) could easily be made instances of this class as well. I would think that "map" should be completely supplanted by "looseMap", although rigidMap would still be necessary for monomorphic types.

As a side note, there is another possible solution. I experimented with using type families to encode Functors (and thus a polymorphic map) as RFunctors, using the same approach as in the RMonad package. This worked fine for map, but I couldn't figure out how to write a fold that satisfied the typechecker. I think it's impossible, and would love to hear from anyone who knows how to make it work.

Sunday, April 19, 2009

SEAMUS recap

The 2009 SEAMUS Conference is over, and the finale featured the coolest thing ever. A video of an earlier concert is on Youtube already, of course (I didn't see the most recent concert posted yet).

http://www.youtube.com/watch?v=aOZEpP_zzaw&feature=related

Thursday, March 12, 2009

future directions for iteratee

I have recently completed two major projects that were taking up nearly all of my time. Now that they are done, I'd like to work on the next version of the iteratee package. Here are a few ideas that I hope to include soon.

1. Remove the explicit Maybes
This was suggested by Oleg, and it seems to be a good idea. Every iteratee that produces a value other than () uses Maybe to represent the possibility of failure (always an option when doing IO). By incorparating the Maybe into the type of IterateeG, these will no longer need to be explicit. This will also make IterateeGM an instance of MonadZero to the extent that Maybe is an instance of that class.

Status: I've made a patch that does this, but it doesn't yet work properly with convStream. I haven't managed to track down the problem. Likely to be included, assuming I can solve this issue in a reasonable time frame.

2. Stream type class (and simplify StreamChunk)
I keep hoping for a ListLike type class to enter common use. Barring that, I have some ideas for breaking up the necessary functions of StreamChunk into separate type classes, such as the patch to use a monoid instance submitted by Bas van Dijk.

Status: Changes will be made, it is likely that StreamChunk will be broken into multiple smaller classes. Any addition of a Stream type class will wait until after point 4 is resolved.

3. More utility iteratees (foldl, filter, others?)
Status: Likely to be included. Changes to StreamChunk will make these easier to support.

4. Type-safe seeking
If iteratees are parameterized by Stream, the type of the stream should indicate if seeking is supported. I have an outline for how to implement this, but haven't done any work yet.

Status: Needs research, this will probably wait for the next major version bump.

5. Improved error handling
Bas van Dijk submitted a patch to change the type of a stream error from String to Error a. Others have suggested other possible changes as well.

Status: Needs more research, this will likely wait for the next major version bump.

enumerator/iteratees and output

I have recently received a few questions about writing output while using enumerator-based I/O. In some cases users have attempted to make enumerators (like enumFd) that will handle output as well, but have difficulty actually making it work.

I think these problems stem from an incorrect application of the enumerator model of I/O. When using enumerators, a file (or other data source) is a resource that can be enumerated over to process data, exactly as a list can be enumerated over in order to access the data contained in the list. Compare the following:

foldl f init xs

enumFd "SomeFile" ==<< stream2list

In the first function, 'xs' is the data to be processed, 'foldl' tells how to access individual items in the data collection, and 'f' and 'init' do the actual processing. In the second, "SomeFile" is the data, 'enumFd' tells how to access the data, and 'stream2list' does the processing. So how does writing fit in? The output file obviously isn't the data source, and it doesn't make sense to enumerate over your output file as there's no data there to process. So it must go within the Iteratee. It turns out that making an iteratee to write data is relatively simple:

> import Data.Iteratee
> import System.IO
> import Control.Monad
>
> writeOut :: FilePath -> IterateeGM [] Char IO ()
> writeOut file = do
> h <- liftIO $ openFile file WriteMode
> loop h
> where
> loop :: Handle -> IterateeGM [] Char IO ()
> loop h = do
> next <- Data.Iteratee.head
> case next of
> Just c -> liftIO $ hPutChar h c >> loop
> Nothing -> liftIO $ hClose h


Add some error handling and you've got a writer. This version could be polymorphic over different StreamChunk instances by generalizing the type (FlexibleContexts may be required as well). Other stream-specific versions could be written that would take advantage of the specific StreamChunk instance (e.g. using Data.ByteString.hPut instead of hPutChar).

I hope this will serve as a very basic introduction to output when using enumerators. In addition to a generic writer like this, it may frequently be beneficial to define special-purpose writers. In a future post I will show a writer that seeks within the output file using a threaded State monad.