I have a piece of code that converts coreference resolved OpenNLP output from one format to another. This is a piece of OpenNLP output, just a parse tree for the NP "the way"
(NP (DT the) (NN way))The assumption I'm going on is that categories that have a hash after them are coreference annotations. For example, this bracketed expression is the phrase "Nova Scotia" marked as an NP with coref identifier = 1
(NP#1 (NP (location (NNP Nova) (NNP Scotia)))
So far so good?
Here's a piece of Haskell code that extracts the id for a given category. It's just a three liner, nothing exotic here:
getCoref :: String -> Maybe String
getCoref s =
case break (== '#') s of
(_,"") -> Nothing
(_,x ) -> Just (drop 1 x)
To get an idea what this does,
getCoref "NP#42" == Just "42" and getCoref "NP" == Nothingspot the bug
What am I missing? SPOILERS BELOW.partial solution
Consider the phrase "#1" as in "#1 on the charts".It gets parsed as
(NP (# #) (CD 1))Get the idea?
full solution
The code above uses a standard library function "break" which splits a string on a delimiter. For example,break "/" "foo/bar" returns the pair ("foo","/bar"). (This is why I use drop 1; it lets me drop the delimiter). The assumption I was making is that for all categories in which a hash symbol occurs, the hash symbol is preceded by some non-empty string (which I ignore with the underscore). Tis assumption was incorrect. Sometimes you have a category "#" which is not a case of coreference annotation, but a vanilla category that we can ignore.So the current version of myself (Eric 2009-06-04T09:45+0100) thinks that the right way to write this function is
getCoref :: String -> Maybe String
getCoref s =
case break (== '#') s of
(_,[]) -> Nothing
("","#") -> Nothing -- specifically handle the "#" category
(_,"#") -> error ("unexpected category ending with just a hash: " ++ s)
(_,x ) -> Just (drop 1 x)
I've inserted two extra cases into my pattern-matching (Prolog folks should like ML and Haskell for the pattern matching if nothing else). The first extra case accounts for just the "#" category.
The second extra case accounts for any other unexpected uses of "#". As an aside, I'll say that this is an attempt to apply the "dead programs never lie" principle from The Pragmatic Programmer (a must-read). When I was a freshman, our programming prof tried to explain the idea of robust code and defensive programming. But being a dumb freshman, I walked away his lecture unknowingly confused. I had this idea that my code should somehow never fail. But there are cases (and maybe this is something he said, but dumb freshman Eric did not hear) where you should deliberately fail to avoid silently perpetuating errors and lies. Now that I am a dumb post-doc, I am slightly less confused about this point, although I probably am still confused and misguided about lots of other points.
Sorry for the distracting aside. The main point of this post was to show an example of the kind of bug that arises from an incomplete understanding the problem ("oh, just grab the string that follows the hash symbol") you're trying to solve.
.png)
