.editrc Tidbit for ghci

Paul R. Brown @ 2008-12-03T05:48:03Z

The only thing that I lost in the transition between readline in GHC 6.8 and editline in GHC 6.10 was backwards history search in ghci bound to ^R. I use that particular feature quite a bit, so that had a big negative impact on my productivity.

Here's how to get it back. Create a file in your home directory called .editrc with the following contents:

edit on
bind ^R em-inc-search-prev

The analogous setting for forward search (bind ^S em-inc-search-next) doesn't work for some reason, but that's not one that I'm going to miss.

(comment bubbles) 1 comment

The Haskell Platform and Lessons Learned Elsewhere

Paul R. Brown @ 2008-10-02T20:19:43Z

Duncan Coutts posted some slides from ICFP about the developing Haskell platform — a set of "known good" and well-maintained libraries — and it is indeed on its way. (Compare with the "batteries included" effort for OCaml.) Here's the stack from slide 13:

Haskell PlatformLinux Distro
GHCkernel
HackageSourceForge
Cabal.rpm/.deb
cabal-installyum/apt-get

It's not in the charter for the Haskell Platform to make general improvements to Hackage, but looking at the stack diagram I couldn't help but thing about a comparison against a language stack like Java (JDK, Maven, Codehaus, JCP) or Ruby (C ruby, rake, RubyGems, RubyForge) instead of Linux. Quality, collaboration, and liveness are important aspects to assess for a project, but that's next to impossible without publicly accessible (and relatively standardized) bug tracking, source control, and discussion. (Things like continuous integration are niceties but provide somewhat lower utility than the big three I just mentioned.) With 754 libraries, there's a lot of meat and a lot of mystery that's impossible to assess at a glance from the current HackageDB package list web interface. The "heuristic" requirements for libraries in the Haskell platform does include a bug tracker and good basic hygeine (build portably with standard tools, proper releases, maintainer), but it's missing those other touchpoints.

Lest I be perceived as casting stones, my experience is that even in the current circumstances and in spite of the lack of visibility, the Haskell community is vibrant and active. The Cafe and IRC are bustling, and troll-free and flame-free with very rare exceptions. Community leaders are friendly and approachable. Where I've found issues with libraries (resource leak in HTTP, QName equality bug in HXT, attribute qualification issue in "light" xml), maintainers have been helpful and receptive. It would be even better if it was straightforward to collaborate with other users on dedicated mailing lists, post or consume bug fixes via darcs or git branches (the good kind of fork), and track updates. (Use of distributed VCS tools like Darcs and git exponentially increases the utility of a publicly available project VCS.) There is no reason that this should be limited to just a blessed core, as it will help in the growth and refinement of other libraries as well. Posting to Hackage should entail the creation of a mailing list, the provisioning of a bug tracker, and either a check-in of the source for the posted library to a central repository or a reference to a publicly available git or darcs repository.

More than most and less than some, I appreciate the difficulties in providing community infrastructure, having observed Bob and Ben in action at the Haus and watched a top-level project at Apache (ODE) from proposal through graduation. I also appreciate the role of the infrastructure in creating and reinforcing community — it's no accident that a fair proportion of the most widely used open souce libraries on the Java platform have grown either at Apache or at the Codehaus.

(comment bubbles) 2 comments

perpubplat now on github

Paul R. Brown @ 2008-08-28T06:22:18Z

With GHC switching from darcs to git, I decided to move perpubplat over to git (and specifically to github) as well. (For the reasons that GHC decided to move, see this wiki page.) The new landing page for the perpubplat repository is here.

At least if you've already got git, GHC 6.8.3, and cabal-install, building perpubplat is about as simple as it can get:

$ git clone git://github.com/prb/perpubplat.git
$ cd perpubplat
$ cabal install

As far as near-future feature development, I'll be adding github activity feeds to "stream of consciousness" aggregation and improving the configuration and control of aggregation in general.

(comment bubbles) 0 comments

Beust Sequence Ruminations

Paul R. Brown @ 2008-07-03T06:10:59Z

Cédric posted a nice puzzle on his blog:

[W]rite a counter function that counts from 1 to max but only returns numbers whose digits don't repeat.

Bob tweeted about a minimal solution in terms of execution time, although (like the guy in the cartoon) I still like my Haskell version of the sequence (up to some details with use of Data.Int.Int64 and typing the enumeration):

f k = [ n | n <- [1..k], (length . show $ n) == (length . nub . show $ n) ]

And the function to compute the maximum gap:

drop_tail k = reverse . (drop k) . reverse
by_pairs u = zip (drop 1 u) (drop_tail 1 u)
g k = maximum . map (uncurry (-)) . by_pairs . f $ k

This approach, while visually appealing, is unacceptably slow, even with some of the usual optimizations applied. The fact is that any solution that is implemented in terms of testing all of the numbers between 0 and k will perform orders of magnitude more poorly than the recursive style that Bob's using. But how would I know that...?

Subfactorials, Derangements, and Chooses

A derangement is a permutation with no fixed points, e.g., (123) is a derangement of the set {1,2,3}, but (12) is not because it maps 3 to 3. Like the number of permutations of an n-element set (n!), the number of derangements has its own function called the subfactorial and written !n. MathWorld has a decent write-up, with the major takeaway for present purposes being that !n ~ n!.

The number of elements in Cédric's set, for a fixed radix n is the sum from k=0 up to n of !k (n choose k), and that's much smaller than nn. (This reminds me of the whole "bad shuffle" meme from a long time ago.)

Just how much less work does the enumeration approach require than the iteration approach? Here's a quick snippet to compute the number of derangements and the corresponding Beust number for a given radix:

fac :: Integer -> Integer
fac 0 = 1
fac n = n * (fac (n-1))

choose :: Integer -> Integer -> Integer
choose n k = (fac n) `div` ((fac k) * (fac (n-k)))

d :: Integer -> Integer
d 1 = 0
d 2 = 1
d n = (n-1) * ( d (n-1) + d (n-2) )

b :: Integer -> Integer
b n = sum [ (d k) * (n `choose` k) | k <- [ 1..n ] ]

Then, b10 is 3628799, so a solution like Bob's should have around a 2500-fold advantage over a more brute force method. And that advantage gets huge in short order. As reminder of how much bigger nn is than n! and friends, 2626 is roughly 15,264,691,107 times larger than b26...

(comment bubbles) 0 comments

A Simple Asynchronous Handler for hslogger

Paul R. Brown @ 2008-05-29T18:34:23Z

The hslogger package provides a few handlers, e.g., for files and for Syslog, but the implementation of the file logger uses an MVar as a lock for writing log events. This isn't a bad thing, per se, since the GHC runtime will do a good job of queuing waiters for that lock, but it had a noticable impact on performance for perpubplat when I added some initial logging.

To decouple the log event dispatch and disk access, I whipped up a quick AsyncLogHandler (source) that does the job. Here is a quick tour in snippets, starting with a base data structure:

type Timestamp = String

type LogMessage = String

data AsyncLogHandler
    = AsyncLogHandler { channel :: Chan (LogRecord, LogMessage, Timestamp)
                      , level :: Priority }

An admittedly imperfect instantiation for the LogHandler type class:

instance LogHandler AsyncLogHandler where
    setLevel alh p = alh { level = p }
    getLevel alh = level alh
    emit alh lr msg = do { n <- now
                         ; writeChan (channel alh) $! (lr,msg,n) }
    close _ = return () -- make this better

This is less than perfect because it doesn't deal with altering the priority level or closing the stream on the fly, but I'm not concerned with either of those things for the moment. (To make that work, I'd need an additional level of encapsulation on the Chan that wraps log messages and control requests.) I'm on the fence with the necessity of making the writeChan strict in the second argument, but I believe it's necessary to ensure that the timestamp is computed when the message is dispatched as opposed to when it's output.

Setup just requires forking a lightweight thread to pull log messages out of the channel:

asyncHandler :: Int -> Handle -> Priority -> IO AsyncLogHandler
asyncHandler n h pri = do { c <- newChan
                          ; forkIO $ append n 0 h c
                          ; return $ AsyncLogHandler { channel = c
                                                     , level = pri } }

And then a tail-recursive function to pull the events, format output, and periodically (every n messages) flush the stream:

append :: Int -> Int -> Handle -> Chan (LogRecord, LogMessage, Timestamp) -> IO ()
append n i h c = do { ((p,m),l,ts) <- readChan c
                    ; (hPutStrLn h $ ts ++ " [" ++ (show p) ++ "] " ++ l ++ " - " ++ m)
                      `CE.catch` (printex h)
                    ; if i == n then
                          do { (hFlush h) `CE.catch` (printex h)
                             ; append n 0 h c }
                      else
                          append n (i+1) h c }

printex :: Handle -> CE.Exception -> IO ()
printex h e = hPutStrLn System.IO.stderr $ "Error writing to log handle "
              ++ (show h) ++ ": " ++ show e

And that's it.

(comment bubbles) 1 comment

There are Apparently Lots of Haskell Jobs...

Paul R. Brown @ 2008-02-23T23:55:23Z

... and some of them even involve trees.

A while ago, Rod Johnson asserted that Spring had overtaken EJB as a job requirement for Java developers, supported by some charts from indeed.com. (For follow-on analysis, see an article on InfoQ.) I'd call the Spring or EJB decision a false dichotomy in any case.

On a lark, I decided to try a three-way competition between Haskell, Erlang, and OCaml, with Lisp and Pascal thrown in just because, and the results surprised me, since I expected Erlang to beat both Haskell and OCaml:

chart of Haskell, OCaml, and Erlang job counts

So, what are these Haskell jobs...?

haskell job listings

Ah. A more reasonable query (like "haskell and functional") gives the expected results of a few jobs in financial services. The most intersting thing about the query is that twelve jobs is about 0.00025% of the total number of jobs in the engine, so I'll guess that they have on the order of 4.8 million jobs and thus that there are around 9,600 jobs (0.2%) listed for "spring and java" as requirements.

(comment bubbles) 0 comments

New Features for Perpubplat and Ruminations on Service APIs for the Web

Paul R. Brown @ 2008-02-18T20:02:39Z

I've added some new features to perpubplat, and each one presented a nice exercise in Haskell, working with Haskell libraries, and the design and consumption of web APIs.

Collage of Random Flickr Photos

Flickr Sidebar screenshotThe first feature is the collage of photos that uses the Flickr JSON API. The collage appears at the bottom of the sidebar under the "Photos" heading.

The implementation of the collage (Blog.Widgets.FlickrCollage; source here) uses a polite (i.e., supports conditional GET) HTTP poller (Blog.BackEnd.HttpPoller; source here) to call flickr.people.getPublicPhotos (docs here) every fifteen minutes and pull down the data for my most recent 500 photos. (I'll discuss the HTTP poller below.) To deal with concurrency — many readers (HTTP requests) and one writer (the polling thread) — an MVar holds the list of photos, with the writer taking the old value and putting the new and the reader taking the old value and then putting it right back. The implementation of MVar ensures that waiters are awakened in FIFO order, so this should (and does) work great.

The JSON parser that I've been using uses Haskell's datatype polymorphism to model polymorphism in JSON, and this means that you work with wrapped (JSON Array wrapped around a list, JSON String wrapped around a Haskell String, etc.) primitive values instead of primitive values. To make things a little more ergonomic, I've bundled up some one-line utility functions in Blog.Widgets.JsonUtilities (source here). My favorite of the bunch is </>:

(</>) :: J.Value -> String -> J.Value
(J.Object o) </> s = o M.! s
(J.Array a) </> s = J.Array $ map (flip (</>) $ s) a

This makes it possible to compactly express access to nested JSON objects. For example, from the Flickr integration:

to_photo :: J.Value -> FlickrPhoto
to_photo m = FlickrPhoto { photo_id = uns $ m </> "id"
                         , owner = uns $ m </> "owner"
                         , secret = uns $ m </> "secret"
                         , server = uns $ m </> "server"
                         , photo_title = uns $ m </> "title"
                         , farm = unn $ m </> "farm" }

The uns function pulls the value out of a wrapped JSON String, and the unn function pulls the value out of a wrapped JSON Number. With a bit more thought, someone could probably come up with a nice library for JSON handling along the lines of Jaql or something like Pig Latin.

HTTP Polling

My rough cut at an HTTP polling library built on top of Network.HTTP is Blog.BackEnd.HttpPoller (source here), and it supports the bare minimum of features that I needed:

  • Call a supplied function with signature String -> IO () with the body of a 200 response and ignore others.
  • Use "conditional GET" (RFC 2616, section 9.3) via ETag/If-None-Match and Last-Modified/If-Modified-Since.
  • Support for basic authentication via a header configured on the template request passed to the poller.
  • Tolerant of temporary failures but able to gracefully exit.
  • Detailed-enough logging in case APIs, endpoints, or policies change. (I omitted redirect support on purpose.)

del.icio.us Bookmarks on an Entry

The second feature is integration with del.icio.us bookmarks pointing to an entry via the del.icio.us JSON API, and it shows up as a trailer on entries in the detail view:

del.icio.us entry trailer screenshot

I've already blogged about most of the interesting stuff from integrating with the del.icio.us JSON API using Network.HTTP; see Haskell, del.icio.us, and JSON (encodings and non-standard JSON) and A Short Adventure with simpleHTTP (unclosed sockets).

The part I didn't cover was how to schedule queries against del.icio.us, and I'll probably go back to both simplify and enhance it. As present, it's a bit convoluted; three threads interact as follows:

  1. The driver triggers the scheduler on a fixed interval.
  2. The scheduler manages an ordered list of scheduled times and entries. In response to a trigger from the driver, if the head of the list is past due, the scheduler pops the head of the list, refreshes the data about bookmarks for that entry, sends it to the controller, and schedules the next refresh for that entry based on its age in days. The scheduler also receives information about new entries and adds them to the schedule.
  3. The controller manages a Data.Map of data about bookmarks per entry and either updates data in response to the scheduler or returns the current data for rendering a response.

The current design is in-memory only, so it gets repopulated each time the service is booted. I intend to add simple file-based persistence along the same lines used for entries and comments. The other major missing features are support for conditional GET and grouping requests into groups of 15, as allowed by the del.icio.us API.

I would have liked to use the delicious API, but Network.HTTP doesn't currently support HTTPS.

Personal Aggregation

StreamOfConsciousness Sidebar screenshotThe third feature is aggregation of my del.icio.us bookmarks (via RSS feed), Google Reader shared items (via Atom feed), and Twitter "tweets" (via JSON API). The aggregated flotsam, jetsam, dross, and detritus shows up in the sidebar under the "Stream of Consciousness" heading in the sidebar.

The feature is a bit like Moveable Type's Action Streams plugin, but the perpubplat implementation benefits from the fact that a Haskell FastCGI application can have background threads (so no crontab hacking).

The implementation is in the Blog.Widgets.StreamOfConsciousness.* modules:

  • Thought is a data structure that represents a tweet, post, shared item, etc. — date, link, content.
  • Twitter, GoogleReader, and DeliciousPosts encapsulate access to the respective services and parsing data into lists of Thoughts. Each worker uses an HTTP poller (same as with the Flickr collage) to poll a feed.
  • Controller manages the aggregate data structure and a pre-rendered HTML fragment.

To handle the multiple writers and multiple readers, I implemented a lightweight version of multi-version concurrency control where readers can always get data but writers may have to repeat a computation if someone else updated the data in the meantime. Here's a fragment from B.W.S.Controller (full source here):

commit :: SoCController -> [Thought] -> IO ()
commit socc new_items =
    do { snap <- get_data socc
       ; let items' = take (max_size snap) $ merge new_items $ items snap
       ; let rendered' = thoughts_to_xhtml items' 
       ; let snap' = snap { items = items'
                          , rendered = rendered' }
       ; ok <- update socc snap'
       ; if ok then
             return ()
         else 
             do { threadDelay collision_delay
                ; commit socc new_items }
       }

loop :: Chan SoCRequest -> Snapshot -> IO ()
loop ch snap = 
    do { req <- readChan ch
       ; snap' <- case req of
                   GetHtmlFragment c ->
                       do { putMVar c $ rendered snap
                          ; return snap }
                   GetData h ->
                       do { putMVar h snap
                          ; return snap }
                   Update ok snap'' ->
                       if (version snap) == (version snap'') then
                           do { putMVar ok True
                              ; let snap' = snap'' { version = (version snap) + 1 }
                              ; return snap' }
                       else
                           do { putMVar ok False
                              ; return snap }
       ; loop ch snap' }

The commit function runs in the HTTP polling thread doing the updating, and it's responsible both for merging the items into the sorted data and for updating the HTML representation that will get handed to the page rendering process.

The other interesting nut to crack was extracting data from XML using Haskell. I could have used the del.icio.us JSON feed and the JSON feed that the Google Reader shared items Javascript widget uses, but those lack the timestamps that I need to fold the streams together.

Extracting Data from RSS and Atom

I followed the standard trail for learning HXT, which involves building from source, reading the gentle introduction, and trying some of the practical examples. The only issue I had was with namespace handling.

Here's a code fragment from B.W.S.DeliciousPosts (source here) to read the RSS feed of my del.icio.us bookmarks:

import Text.XML.HXT.Arrow

handle_posts :: SoCController -> String -> IO ()
handle_posts socc body = do { posts <- runX ( readString parse_opts body >>> getItems )
                            ; commit socc posts }

parse_opts = [(a_validate, v_0), (a_check_namespaces,v_1)]
                                
atElemQName qn = deep (isElem >>> hasQName qn)
text = getChildren >>> getText
textOf qn = atElemQName qn >>> text

rdf_uri = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
rdf_RDF = QN "rdf" "RDF" rdf_uri

rss_uri = "http://purl.org/rss/1.0/"
rss_item = QN "rss" "item" rss_uri
rss_title = QN "rss" "title" rss_uri
rss_link = QN "rss" "link" rss_uri

dc_uri = "http://purl.org/dc/elements/1.1/"
dc_date = QN "dc" "date" dc_uri


getItem = atElemQName rss_item >>>
          proc i -> do
            t <- textOf rss_title -< i
            u <- textOf rss_link -< i
            d <- textOf dc_date -< i
            returnA -< Thought Delicious d u t

getItems = atElemQName rdf_RDF >>>
           proc r -> do
             items <- getItem -< r
             returnA -< items

HXT uses arrow notation; the quick and dirty explanation is that proc is like λ (but for arrows instead of functions), the <- is the usual monadic "bind" operator, and the -< feeds a value to the expression on the shaft of the arrow.

The first time I ran this against the RSS from del.icio.us, I got nothing back, so after looking at the XML for the RSS, I switched the prefix for the RSS QNames to the empty string to match the input file, and it worked. Grrr... That means that the (==) for QName is broken, and a quick look at the source in Text.XML.HXT.DOM.TypeDefs showed why:

data QName = QN { namePrefix    :: String
ualified name \"namePrefix:localPart\"
                , localPart     :: String
ed name \"namePrefix:localPart\"
                , namespaceUri  :: String
i
                }
             deriving (Eq, Ord, Show, Read, Typeable)

The derived (==) will just and together the (==) for the three components (prefix, local, uri), but XML QNames are equal if their local parts and URIs (as strings) are equal. It's easy to fix by dropping the derivation of Eq and supplying a good version:

-              deriving (Eq, Ord, Show, Read, Typeable)
+              deriving (Ord, Show, Read, Typeable)
+ 
+ instance Eq QName where
+     q1 == q2 = ((localPart q1) == (localPart q2))
+                && ((namespaceUri q1) == (namespaceUri q2))

After which, it works according to my expectations for namespace handling.

Couldn't You Do All That With JavaScript...?

Yes. I could. I didn't. Here are a few of the reasons that I chose not to:

  • My experiments showed that page loads would be several seconds instead of a fraction of a second. Other people have had the same experience. (It reminds me of the opening scene of I'm Gonna Git You Sucka where Junebug dies of an OG. Don't let your blog die of an OW...)
  • Some of the widgets are just plain fugly, IMHO. I'm looking at you, Google Reader shared item "clip" and Twitter Flash widget, although the availability of JSON for the Google Reader shared item "clip" (look in the JavaScript) and Twitter would allow me to come up with something more pleasing (to me).
  • Even though it's not a good idea — e.g., IE7 is broken, Firefox <3 doesn't do incremental display, etc. — I would like to be able to serve application/xhtml+xml, and document.write doesn't work.
  • The availability of background threads on the server side means that Javascript on the client side isn't the only option.

Other Integrations and Aggregations

The other two features that I'd like to add are backlinks to other blogs and backlinks to posts on community sites like Reddit and DZone. (I'm on the fence about implementing trackback support; you could twist my arm.)

Nonetheless, I'm on the fence about directing people to comment threads in other locations, i.e., Reddit. (My reasons are similar to Reg Braithwaite's.) It would be a simple matter to sniff referring URLs, deduce where an entry is posted on Reddit, and then integrate the comments together, but Reddit's draconian User Agreement forbids it:

The content, organization, graphics, text, images, video, design, compilation, advertising and all other material on the Website, including without limitation, the "look and feel" of this website, are protected under applicable copyrights and other proprietary (including but not limited to intellectual property) rights and are the property of Website Provider or its licensors. The copying, rearrangement, redistribution, modification, use or publication by you, directly or indirectly, of any such matters or any part of the website, including but not limited to the removal or alteration of advertising, except for the limited rights of use granted hereunder, is strictly prohibited.

Someone should implement a community hub that integrates discussion threads, followup posts, and blog comments on an original entry in a transparent and open fashion...

Postmortem

My first observation from this experiment is that APIs are preferable to feeds are preferable to widgets when it comes to integration of services on the web. (Note that I didn't say web serivces...) Even listing widgets is somewhat questionable in my opinion, since it's more of a "put my stuff on your page" than a "use my service".

My second observation is nothing new, but I now have experimental evidence — JSON is preferable to XML, whether or not the target client runs in a browser. If I were building a service, I'm not sure that I'd bother with supporting an XML API.

My third observation is that I would use Haskell to build a product or service, and I mean that in the sense that I can see how to train a team and build processes (prototyping, implementation, quality, deployment, support) around Haskell. The language does have a relatively steep learning curve (q.q. Kevin Scaldefarri's post on the subject and the comments that follow or Reg Braithwaite's general ruminations on learning languages), but the real problem is collectively getting through the challenges once. It reminds me of learning spectral sequences as a graduate student; fifteen minutes with my advisor to work an example was better than a week of staring at otherwise incrutable notation. As a measure of the view from my current location on the learning curve, I coded up a working rough cut of the "stream of consciousness" feature in an evening plus an afternoon cup of coffee, and I wouldn't regard myself as being fully around the curve yet (FFI, custom monads/transformers, etc. await).

(comment bubbles) 1 comment

Posts tagged ["haskell"] contains 31 items in 5 pages of 7 items each:
1 2 3 4 5