Saturday, December 14, 2013

Installing the Haskell Platform

It all started with the 2013 Christmas Tree Lecture. Professor Knuth challenged the audience to explore skew ternary trees and their relationship with a subclass of rooted planar graphs. I decided it might be fun to rewrite his SKEW-TERNARY-CALC program in Haskell, but in order to maximize its utility, it should target its front-end to the web browser. I learned out about the Fay monad and decided to give a try (see <future post>, hopefully). So as a first step, I tried to cabal install fay, only to find that I had a Dependency Mess™. Fine, I could use a fresh Haskell install. Unfortunately my laptop is currently stuck on Ubuntu 12.04, which is stuck at ghc-7.4. So I purged all my GHC and cabal data, temporarily installed a ghc-7.4 binary to bootstrap the new GHC, and went on building it. In light of the confusing package database issues, I figured it would be easiest to simply install everything to a user-writable directory, ~/local/opt/ghc-7.6.3 and ~/local/opt/haskell-platform-2013.2.0.0, so that I can then add --global as a default cabal-install option and operate out of a single package db.
$ cd ~/Downloads/ghc-7.6.3 $ sudo aptitude install ghc $ OPT=$HOME/local/opt $ ./configure --prefix=$OPT/ghc-7.6.3 $ make && make install
This went fine (though it took a few hours on my laptop), so I was now ready to install the Haskell platform. I eventually tracked down the right configure flags:
$ cd ~/Downloads/haskell-platform-2013.2.0.0 $ sudo aptitude purge ghc $ ./configure \ --prefix=$OPT/haskell-platform-2013.2.0.0 \ --enable-shared \ --enable-profiling \ --disable-user-install $ make && make install

Now the fun starts

Unfortunately, make failed. It turns out that scripts/build.sh sets GHC_PACKAGE_PATH in its build_pkg function when it builds with Cabal, and Cabal is incompatible with this option. Fine, we can fix that:
$ sed -i '/GHC_PACKAGE_PATH=/ s/^/#/' scripts/build.sh $ make && make install
Not surprisingly, this also fails, a little later in the process. This time, alex is failing to build without happy. But happy is supposed to be part of the Haskell platform, and it should be smart enough to build its dependencies in the right order. Indeed, there's a bug on this that's been open for a year (and the original reporter even included a patch!). I rearranged the dependencies and went on my way. Another error. Apparently happy also needs happy to build. Great, so there's no way around bootstrapping with a binary distribution. I found out right afterwards that alex has the same bootstrapping problem.
$ sudo aptitude install happy alex $ make && make install $ sudo aptitude purge happy alex
Now it looks like we're good to go. Cleaning things up a bit,
$ cd ~/local/opt $ ln -s ghc-7.6.3 ghc $ ln -s haskell-platform-2013.2.0.0 haskell-platform $ for a in ghc/bin/*; do ln -s ../opt/$a bin/ done $ echo PATH=$OPT/haskell-platform/bin:\$PATH \ >> ~/.bashrc $ . ~/.bashrc $ sed -i '/user-install/ s/.*/user-install: False/g' \ ~/.cabal/config

Installing Fay

Finally, it's time to actually install Fay.
$ cabal update $ cabal install fay
The first invocation of cabal update tells me to run cabal install cabal-install, but I'm a bit paranoid because ghc-pkg list tells me that Cabal-1.16.0 is installed, but the new cabal-install wants to bring in Cabal-1.18.0. Let's not start screwing up the dependencies just yet, thank you. However, there was a failure installing pretty-show. Cabal didn't give me a useful message, but attempting to install pretty-show directly reveals that it needs a higher version of happy. Happy doesn't need to install any libraries, so I'm not as worried about installing it.
$ cabal install happy $ cabal install fay
This works, but tells me I also need to install fay-base. No problem.
$ cabal install fay-base
Stay tuned for another post later about skew ternary trees!

Thursday, March 07, 2013

Obfuscated Life

f=lambda g,r,n,s:s if n==0 else'\n'.join([s,'='*50
,g(g,r,n-1,r(s))]);l=lambda q:'\n'.join([''.join([
'*'if x in(5,6,7) else' 'for x in a])for a in [map
(sum,zip(*b))for b in zip(*[[z[x:]+z[:x]for z in [
[(2-(1-abs(x))*(1-abs(y)))*w for w in r]for c in[[
[1 if s == '*' else 0 for s in p] for p in q.split
('\n')]]for r in c[y:]+c[:y]]] for x in(-1,0,1)for
y in(-1,0,1)])]]); iters=65 ;print(f(f,l,iters,"""
**************************************************
*                                                *
*         ***      ** **      ***    **          *
*         *  *    *  *  *    *       **          *
*         ***      *   *      **     **          *
*         *  *      * *         *                *
*         ***        *       ***     **          *
*                                                *
**************************************************
""".strip()))  # LIFE # 2013/3/7 # Stephen Hicks #
You can fill in any initial position you want (but make sure it is a rectangle (i.e. the same number of characters on every line) and that the first and last characters are not spaces (any non-asterisk will do to signify an empty cell)).