Archive

Archive for July, 2008

Parsing annotated postfix operators with Haskell

July 23rd, 2008

I want to show you a neat trick method when constructing parsers with Haskell and Parsec.

While writing a parser for CCS, a process description language (don’t worry too much about it), I found I needed to parse constructs with a suffix operator. To provide a little context, the relevant grammar is this.

P ::= 0 | a.P | ... | P[f] | P \ S

where … indicates I’ve omitted some irrelevant stuff. Here, P is a process - the entity CCS is meant to describe. a is a so-called action label, just think of it as a generic label. a.P stands for a process that can perform an a action and then become the process specified after the dot. 0 (zero) stands for a special process that cannot do anything, the deadlocked process.

f is a mapping from such labels to labels, called a relabelling and is commonly specified with a list of pairs b/a,d/c,... which indicates that a maps to b, c to d etc. S is a set of such labels, represented in the normal manner with curly braces {a,b,c,...}. The construct P \ S is called a restriction, informally it means P cannot perform any of the actions in S.

In summary,

  • a.a.0 is a process that can do two a actions and then stop
  • P [b/a] is whatever P is, except any a performed by P will be changed to a b
  • P \ {a,b} is whatever P is, except a or b actions are not allowed

Now, [f] and \ S can be considered postfix unary operators on processes, with some additional structure, the f and the S. Since they are postfix there is no need to define their relative precedence, their order is enough. I.e.

a.0 [b/a] \ {b} [d/c,e/d] \ {e,g}

is unambiguous. Our Haskell ADT to represent the abstract syntax tree looks like this,

type Action = String
type Relabeling = Map.Map Action Action
type Restriction = Set.Set Action
 
data Process
    = Null
    | Prefix Action Process
    | ...
    | Relabel Process Relabeling
    | Restrict Process Restriction
    deriving (Eq, Show, Ord)

We want the example above to be parsed into this value (indented for clarity),

Restrict (
    Relabel (
        Restrict (
            Relabel (
                Prefix "a" Null
            ) (Map.fromList [("a","b")])
        ) (Set.fromList ["b"])
    ) (Map.fromList [("c","d"),("d","e")]
) (Set.fromList ["e", "g"])

My initial attempt at writing a parser for these constructs was ugly and complex. I was trying in one rule to parse a bunch of relabellings and restrictions and construct the appropriate value from the process that had already been parsed, cluttering the rules for other constructs with this logic. I thus went to the best documentation of Haskell, the #haskellirc channel, and asked for opinions. Christophe Poucet (vincenz) showed me the light and pointed out that a parser could well return a function,

April 13th, 2008
15:24 < vincenz> Arnar: what about...
15:24 < vincenz> process_adapter :== relabeling | restriction
15:24 < vincenz> and have those return the type
15:24 < vincenz> Process -> Process

And therein lies the trick. Instead of constructing the correct value, I simply parse a sequence of adapters, each of which can be a relabeling or a restriction, in each step returning the function that wraps a process in the relevant constructors.

relabeling :: Parser Relabeling
relabeling = do rs <- brackets $ commaSep1 rename
                return $ Map.fromList rs
                where
                  rename :: Parser (Action,Action)
                  rename = do s1 <- lexeme action
                              symbol "/"
                              s2 <- lexeme action
                              return (s2,s1)
 
restriction :: Parser Restriction
restriction = do symbol "\\"
                 ss <- braces $ commaSep1 action
                 return $ Set.fromList ss
 
process_adapter :: Parser (Process -> Process)
process_adapter = do restr <- restriction
                     return (\p -> Restrict p restr)
                  <|>
                  do rel <- relabeling
                     return (\p -> Relabel p rel)

Very simple, very clean. Now, parsing a process followed by a sequence of such adapters is trivial. We then feed the process through the adapter functions in order, i.e.

adaptedProcess :: Parser Process
adaptedProcess = do p <- simpleProcess
                    adapters <- many process_adapter
                    return $ foldr (flip (.)) id adapters p

I especially like that last line, foldr (flip (.)) id adapters p. Remember adapters has the type [Process -> Process], i.e. a list of adapters. If this list is [f1,f2,...,fN], then

foldr (flip (.)) id adapters

will give us the composition of these in the correct order, namely

\x -> fN ( ... (f2 (f1 (id x))) ...)

All that’s left to do is to apply this on the original process and out pops a correctly wrapped one.

I think this is very neat and it showcases the power of first-class functions. If you don’t see the beauty here, feel absolutely free to write me off as eccentric ;o)

You can find the complete code and a PDF writeup of the CCS project right here.

Arnar Programming , ,

Playing with Haskell’s lazy lists

July 21st, 2008

I love Haskell. I love many things about it, but one of its main attractions for me is that it is lazy. I guess I like that because I’m lazy myself.

Lazyness in Haskell means that we get infinite lists (or streams) for free - i.e. they don’t need any special handling over finite lists. Granted, other languages have infinite lists, but in Haskell any regular list has the natural potential of being infinite so we don’t need any specific syntax or constructors for them.

So, when I read about a Rutgers graduate student named Eric Rowland that recently discovered a simple prime-number generating formula, I decided to try it out in Haskell. Turns out it is extremely simple.

The generating formula is based on the sequence a(n) that you get by setting a(1) = 7 and then for n ≥ 2:

a(n) = a(n-1) + gcd(n,a(n-1))

In Haskell, running in interactive mode (GHCi), we define this by

Prelude> let a' = (1,7) : (map ( \(n,x) -> (n+1, x + (gcd (n+1) x))) a')
Prelude> take 10 a'
[(1,7),(2,8),(3,9),(4,10),(5,15),(6,18),(7,19),(8,20),(9,21),(10,22)]
Prelude> let a = map snd a'
Prelude> take 23 a
[7,8,9,10,15,18,19,20,21,22,33,36,37,38,39,40,41,42,43,44,45,46,69]

Note that each element of a’ is a tuple of the index n and the value a(n). By taking differences between successive values of this sequence, you always get either the number 1 or a prime number (proving this is Rowland’s contribution).

Prelude> let d = zipWith (-) (tail a) a
Prelude> take 23 d
[1,1,1,5,3,1,1,1,1,11,3,1,1,1,1,1,1,1,1,1,1,23,3]

So far, so good. Now in one step we remove the 1-s by using filter and get rid of duplicates by using nub (which is defined in the List module).

Prelude> :m +List
Prelude List> let primes = nub $ filter (/= 1) d
Prelude List> take 23 primes
[5,3,11,23,47,101,7,13,233,467,941,1889,3779,7559,15131,53,30323,60647,121403,242807,19,37,17]

Neat! The list primes is of course infinite and we could pluck the values off it as long as we like, and Haskell’s laziness will make sure values are only computed on demand. Rowland’s paper contains the details of the math.

Arnar Programming , ,

Adobe Lightroom 2 beta

July 9th, 2008

I know this is not programming, but one has to go out once in a while. Of course, after going outside, once I’m home I’m right back on the computer (my wife will be happy to tell you this).

I went on the Golden circle excursion with the ICALP attendees today. This is the “standard” tour given to most visitors and involves visiting the area around Geysir, Gullfoss and Þingvellir. After I got back I started selecting photos to put on the ICALP photo-webpage. I’ve been trying out Adobe’s new beta of Lightroom and I must say I like it. It has all the same features as the previous version, but feels considerably snappier.

One new feature is selective retouching, i.e. you paint a mask and can make some exposure/color changes to selected areas. Of course, performance goes out the window as soon as you do that but it is quite powerful and saves you from starting Photoshop.

While at Gullfoss, I took the following picture of Bláfell, a mountain north-east of there (if I’m incorrect and you know better, please correct me in the comments). The picture straight from the camera wasn’t that great…

… so I played with it for about a minute in Lightroom…

Edited version

While it is still not great, I think it is quite good less than 60 seconds of work. The correctios I made were exposure correction, removing the dirt from the lens with the spot tool and then I made the mountain and sky a little more pronounced by upping the saturation and using the clarity slider (which I think is just the high-pass sharpening technique).

So.. try it out yourself if you like photography.

Arnar Uncategorized

ICALP’08, pre-conference workshops and first day

July 8th, 2008

So ICALP 2008 is on. I’m fortunate enough that it is held at my school (Reykjavik University) and that I was offered the chance to sit in on the talks in return for helping a little with the organization and administration.

The activities started on Friday with the DYNAMO 2008 PhD school. I didn’t attend many of the lectures, but the ones I did were very interesting. To name one, Elias Koutsoupias gave informative talks on Game Theory and its use for example in online auctions.

Yesterday, Sunday, there were several workshops. I mostly attended SOS’08, a workshop on Structural Operational Semantics. Dale Miller, a hard-core logician, gave an excellent invited talk on formalizing SOS specifications in logic and although I didn’t understand half of it I somehow found it very interesting. His slides are available at his website.

Today was the first day of the conference proper and started off with an invited talk by Google’s S. Muthukrishnan, where he explained how Google runs auctions to decide what ads are displayed along with search results. Attendance to the talk was excellent, and while I had my hands full with other duties, I can safely say it was interesting on many levels.

After lunch I mostly attended track B, on logic, semantics and theory of programming. I’m afraid I can’t say much of merit about the talks as I had to do my best to understand them properly myself. I can say that this first day of ICALP went very smoothly in my opinion. As a bonus, the weather turned out to be very nice so in the afternoon and during the welcome reception, people could stand outside and enjoy the fresh air.

For photos from ICALP, check out our Picasa web album (updated at the end of each day). For more authoritative information on some of the talks, check out MohammadReza’s guest posts on Luca’s blog

Arnar Uncategorized