Archives

Creative Commons License
This blog is licensed under a Creative Commons License.

Journey into Haskell, part 3

| 3 Comments | No TrackBacks

Today I need a wrapper script to drop arguments from a command-line. I instinctively reached for bash, but then thought it would be a good exercise for my infant Haskell knowledge.

The task

The task at hand is to write a wrapper script for /usr/bin/ld that drops arguments beginning with -Wl,-rpath,. Since it must deal with arguments containing spaces, and I didn’t want to get into executing external programs with Haskell just yet, I wrappered the wrapper:

#!/bin/bash
$(dirname $0)/ld-wrapper "$@" | xargs -0 /usr/bin/ld

Here ld-wrapper is expected to return its arguments separated by NUL characters so I can feed it to xargs, and from there to /usr/bin/ld. I’m sure there’s an easy, all-in-one way to do this with Haskell, I just haven’t reached that chapter yet.

Haskell version

Anyway, here is the Haskell script:

import Data.List
import System.Environment

main = do
  args <- getArgs
  putStr $ intercalate "\0"
         $ filter (not . isPrefixOf "-Wl,-rpath") args

Pretty basic: it filters the input arguments, keeping each one which does not begin with the sought-for string, and joins the list together using NUL as the separator.

Ruby version

As a quick sanity check, I wrote the same thing in Ruby, since it has facilities for being just as succinct:

print ARGV.select {
  |y| !y.include?("-Wl,-rpath")
}.join("\0") + "\0"

I wanted to do this with an “inverse grep” instead of select, but couldn’t find a way to grep for the opposite of a pattern.

What’s interesting is that the Ruby version is marginally faster than the compiled Haskell one. For filtering 40,000 arguments, here are the averaged run-times over 20 invocations:

Language Speed
Haskell 0.00774523019791s
Ruby 0.00551697015762s

My guess is that Haskell is creating 40,000 different strings in memory as it constructs the final result, while Ruby is pasting one together as it goes. I don’t know which.

UPDATE: If I compile the Haskell version with -O2, it becomes a hair faster than Ruby, at 0.0049 compared to 0.0055. If I switch to lazy bytestrings, it drops just a hair to 0.0048.

No TrackBacks

TrackBack URL: http://www.newartisans.com/mt/mt-tb.cgi/2547

3 Comments

Ruby should never, ever be faster than compiled How are you compiling it? ghc -O2 ?

Also, you might want to look at using lazy bytestrings, a much more efficient string type.

Good point! I’ve updated the article.

Here is a shorter version of your code, and it looks nicer, IMHO:

import Data.List
import System.Environment
import Control.Monad

main = putStr $ intercalate "\0" $ filter (not.isPrefixOf "-Wl,-rpath") 
         =<< getArgs

Leave a comment

About this Entry

This page contains a single entry by John Wiegley published on March 18, 2009 7:59 PM.

Journey into Haskell, part 2 was the previous entry in this blog.

Updated site to use Blueprint CSS again is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Recent Comments

  • yoman: “Barfin”? “Slurping”? “Slime” “Hunchentoot” ??? What in the T.F. world read more
  • Bjorn Tipling: Why would you add instructions for installing an editor when read more
  • Mark Aufflick: sudo port install sbcl +threads If you previously installed sbcl read more
  • Alexander Lehmann: Thank. You. So. Much. – Clisp caused a lot of read more
  • Vetle: Btw, to get support for threading in SBCL, you have read more
  • ifade: I tried the same and get the same answer, but read more
  • Martial Boniou: Hi, I tried to install slime with MacPorts and I read more
OpenID accepted here Learn more about OpenID
Powered by Movable Type 4.261