Monday, April 16, 2007
Saturday, March 31, 2007
Tuesday, March 20, 2007
It's official!
Not long ago, I was on the same flight to DC with Bud Cramer. When we reached the terminal at Reagan, I said to him, "Congressman, give my best to Ron Paul!" An honest man and perhaps the humble American republic's last hope, Dr. Paul is officially a candidate for president!
Notable quotes:
- "I'm very confident about the message of liberty and the constitution. I'm very confident that the American people are sick and tired of what they're getting. And I'm also very confident that the Republican party has gone in the wrong direction. We used to be the party of small government, but now we're the party of Big Government."
- "My main thrust would be I would emphasize my oath of office. As a congressman, I emphasize that. As president, I would emphasize that. And that is, to obey the constitution, which strictly limits the power of government. It strictly limits the power of the executive branch. It strictly limits the power of the congress -- and even the courts. That would be my goal: to shrink the size and scope of government, believing very sincerely that the benefits to people are far better off in a free society than in an authoritarian society. When government is involved in central planning, and running the world, running the economy, and running our personal lives, we're not better off: we're worse off."
- "If we don't get a handle on the entitlements, if we don't get a handle on all this foreign adventurism, this country is going broke. Actually, I think the country is insolvent. It's just the fact that the world still accepts our dollars that we can still get away with this. Yes, we can have full accountability, but the ultimate accountability has to be to make sure that we hold government under control -- that we not allow it to continue to grow or try to do everything conceivable at the central level."
- "Very simply, governments always like inflation, that is, the creation of money out of thin air to debase the value of your currency. This is the reason that we don't have a gold standard: because big-government conservatives and big-government liberals like to spend money. But they really don't like the taxes, and there's a limit to how much they can borrow... and every time they create new money, they devalue the money we have in our pockets. So it's a tax on us; it's a sinister, immoral tax..."
- "[Inflation is] so destructive because it's the most regressive of all taxes. Poor people and the middle class eventually get wiped out by rising prices. Now government tells us there's only a 2% inflation rate, but that's not true: the inflation rate for poor people and the middle class might be 6 or 8 or 10 percent. Who benefits the most? It's the wealthy class: the bankers, the domestic industries, the military-industrial complex."
- "The answer to this is gold and silver, and that's still the law of the land. Under the constitution, only gold and silver can be legal tender, yet it's been a good many years since we've completely forgotten about it. We've had no connection -- our dollar's had no connection to gold since 1971. If you look at the problems we've had since that time, they're definitely related."
- "I would come home [from Iraq] as soon as possible."
- "Liberty will provide the answers that we need."
Dr. Paul is for peace and friendships among nations. When he gives his solemn word to uphold and defend the constitution, he'll really do it: he won't merely be reading a script. A politician is actually making an issue of sound money!
Ron Paul is a true American. See the video below for more details.
Sunday, March 11, 2007
Wal-Mart, health care, and irresistable market forces
Bo's post today about Wal-Mart made me think of an excellent definition, thanks to Byrne's Eye View:
- capitalism
- Economic system under which any legitimate complaint can be rephrased as a decent business plan
Bo's complaint is about customer service: it can take a long time to get in and out of the place. In a free market, goods are allocated by price and by time. When we think of Tiffany & Co., for example, a price tag with many digits comes to mind, but if a customer walks in weary from hauling around so much cash, they'll graciously relieve him of that burden.
Wal-Mart chooses the opposite corner: low prices but slow service. Target's business model attracts customers with more money to spend, and they do it with features such as cleaner stores and better customer service, which their customers value more highly than the few extra dollars that they trade in return.
Even deeper in the corner of low price and long lines are the popular proposals for "free" health care. (As P.J. O'Rourke quipped, "If you think health care is expensive now, wait till it's free.") The "free" health care in Canada and the UK are characterized by long waiting lists -- which exist for exactly the same reasons as the bread lines in the Soviet Union.
Economist Ludwig von Mises wrote, "Even the most mighty government, operating with the utmost severity, cannot succeed in endeavors that are contrary to what has been called 'economic law.'" The mighty United States government has sort of a pilot program for "free," "single-payer" health care: the VA's frightening maze, and, boy, is it a success!
I'm confident that the calls for "free" health care are well-meaning, but their inevitable result would cruelly force everyone into the same trap -- while politicians insult everyone with unending proclamations of success. (Don't be surprised if members of the congress also give themselves a "special" health care system just as they did with Social Security.)
The lesson is simple: there ain't no such thing as a free lunch.
Saturday, March 10, 2007
Timeless political commentary
Insincerity. Gratuitous appeals to emotion. Tired clichés. Focus-groupped pablum. Wanton demagoguery.
Refuse to allow your mind to be filled with this trash! Instead, enrich your mind with reasoned, intellectual analysis:
What is the attitude of the democrat when political rights are under discussion? How does he regard the people when a legislator is to be chosen? Ah, then it is claimed that the people have an instinctive wisdom; they are gifted with the finest perception; their will is always right; the general will cannot err; voting cannot be too universal . . .
But when the legislator is finally elected — ah! then indeed does the tone of his speech undergo a radical change. The people are returned to passiveness, inertness, and unconsciousness; the legislator enters into omnipotence. Now it is for him to initiate, to direct, to propel, and to organize. Mankind has only to submit; the hour of despotism has struck.
The passage above comes from The Law by Frédéric Bastiat, available as a two-part audio book from FreeAudio.org.
Thursday, March 08, 2007
Waterfalls are bad, mmmkay?
42 Presidents in 10 Minutes
Adapted from 50 States in 10 Minutes.
You have 10 Minutes to remember as many of the 42 United States presidents as you can. After 10 Minutes, the correct answers will appear in this space so you can see which ones you've missed.
Give the first and last name separated by a space. Middle names are required only in cases of ambiguity.
|
42 presidents remain
|
|
Named so far:
None
|
Saturday, March 03, 2007
Ron Paul on CNN
In this appearance from February 26, Dr. Ron Paul talks about economics, foreign policy, immigration reform, and upholding the constitution.
Saturday, February 24, 2007
My first monadic program!
Problem 32 from Project Euler reads
The product 7254 is unusual, as the identity, 39 x 186 = 7254, containing multiplicand, multiplier, and product is 1 through 9 pandigital.
Find the sum of all products whose multiplicand/multiplier/product identity can be written as a 1 through 9 pandigital.
Not one of my brighter moments, the first approach I considered was applying goon-force to permute a list of eleven characters ('1' .. '9', 'x', and '=') -- a search space of almost 40 million -- looking for well-formed and valid statements.
Initially, I looked at using Text.Regex. As I was fishing for examples to crib from, I saw a suggestion that people may as well use Parsec, the monadic parser combinator library. So let's knock out the preliminaries:
> module Main where > > import Data.List hiding (map) > import Text.ParserCombinators.Parsec
A parser for the simple expressions reads easily:
> num :: Parser Int > num = do ns <- many1 digit > return $ read ns > > expression :: Parser (Int,Int,Int) > expression = do multiplier <- num > times <- char 'x' > multiplicand <- num > equals <- char '=' > product <- num > return (multiplier, multiplicand, product)
Generating permutations is no problem in Haskell:
> permutations :: [a] -> [[a]] > permutations [x] = [[x]] > permutations xs = > [ y : zs > | (y,ys) <- selections xs > , zs <- permutations ys > ] > > selections [] = [] > selections (x:xs) = (x,xs) : [(y,x:ys) | (y,ys) <- selections xs]
I'd been wanting to solve as a learning example one of the Project Euler problems using monads. As I tried to shoehorn the problem into a monadic solution, I remembered the characterization of the Maybe monad as being useful for computations that can fail, and I saw two possibilities for failure: garbage input (e.g., "x=123456789") and false statements (e.g., "1x2=3456789").
Having a particular permutation, check tests whether it's well-formed and valid:
check :: String -> Maybe Int
check s = do
result <- parseExpr s
p <- validProduct result
return p
parseExpr :: String -> Maybe (Int,Int,Int)
parseExpr s =
case parse expression "expression" s of
Left err -> Nothing
Right tuple@(mr,md,pr) -> return tuple
validProduct (mr, md, pr)
| mr * md == pr = Just pr
| otherwise = Nothing
The test goes just as you would describe it to someone else: parse the input to extract the components of the mulitiplication and then check whether the multiplication holds. Simple.
You wonder, 'But what about when the parse fails or when the statement is bogus?' Those checks are still happening, but the Maybe monad and the do-notation syntactic sugar are performing those checks implicitly! "Control" (to borrow an imperative concept) reaches the return p line only if both the parse and validProduct succeed. Otherwise, check bails and returns Nothing.
All that's left to do is feed it input and sum the result. Note: it's very s-l-o-w.
p32 = sum $ elems $ fromList $ catMaybes $ map check (permutations cs) where cs = ['1','2','3','4','5','6','7','8','9','x','=']
An obvious improvement is to use nub instead of (elems . fromList). Even better, lists are also monads, so Maybe distractions disappear with only a few very minor changes:
> p32 = sum (nub $ concatMap check (permutations cs)) > where cs = ['1','2','3','4','5','6','7','8','9','x','='] > > main = print p32 > > check :: (Monad m) => String -> m Int > check s = do > result <- parseExpr s > p <- validProduct result > return p > > parseExpr :: (Monad m) => String -> m (Int,Int,Int) > parseExpr s = > case parse expression "expression" s of > Left err -> fail (show err) > Right tuple@(mr,md,pr) -> return tuple > > validProduct :: (Monad m) => (Int,Int,Int) -> m Int > validProduct (mr, md, pr) > | mr * md == pr = return pr > | otherwise = fail "invalid product"
This works because failure in the list monad is the empty list, and concatMap gets rid of all the empties.
Saturday, February 17, 2007
Very touching short animation
I saw this video when my wife was in St. Louis at a baby shower for one of the girls she played volleyball with in college and my kids were at my mother-in-law's. So moving.
Thursday, January 11, 2007
A candidate worth supporting
Ron Paul filed papers to form an exploratory committee!
In an interview, Dr. Tom DiLorenzo said, "No one is proposing anything near constitutional government. I consider the act of voting to be treasonous to the Constitution." Unlike so many of his colleagues, Paul has read but also works diligently to apply the constitution properly.
Peace. Freedom. Property. Vote for Dr. Ron Paul.
Wednesday, January 03, 2007
Bo stole my line!
Bo stole my line! (Not really -- he gave an attribution and everything -- but "Bo follows MLA style" is a pretty lame headline.)
A relative of my wife's -- one of those baby-mama-sista-cousin kind of deals -- knows someone connected to the Bama athletic department and had been saying since around Thanksgiving that Nick Saban was a done deal.
Given Saban's strong denials, it didn't seem likely at all. Bill, I'm glad I was wrong!
Shula was a clown. He's gone, so it's morning in Alabama.
Thursday, October 05, 2006
Moral: a regular expression is a poor subsitute for a parser
A famous jwz soundbite is "Some people, when confronted with a problem, think 'I know, I'll use regular expressions.' Now they have two problems."
Snarky, yes, but a good sanity check.
Section 9 of the Perl FAQ addresses the issue of validating email addresses. RFC 2822 gives a specification for Internet email addresses, and the language is much broader than that matched by /^\w+@\w+\.\w+$/
The proper solution is to use a parser. To see why, consider the task of maintaining the following elegant -- but unit-tested! -- solution:
using System;
using System.Text.RegularExpressions;
using NUnit.Framework;
namespace Application
{
public interface SyntaxChecker
{
bool WellFormed(string input);
}
public class EmailAddressChecker : SyntaxChecker
{
// derivative of work with the following copyright and license:
// Copyright (c) 2004 Casey West. All rights reserved.
// This module is free software; you can redistribute it and/or
// modify it under the same terms as Perl itself.
// see http://search.cpan.org/~cwest/Email-Address-1.80/
#region dumped regular expression
private static string gibberish = @"
(?-xism:(?:(?-xism:(?-xism:(?-xism:(?-xism:(?-xism:(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^
\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))
|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+
|\s+)*[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+(?-xism:(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^
\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))
|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+
|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(
?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?
:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x
0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*<DQ>(?-xism:(?-xism:[
^\\<DQ>])|(?-xism:\\(?-xism:[^\x0A\x0D])))+<DQ>(?-xism:(?-xi
sm:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xis
m:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\
]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\
s*)+|\s+)*))+)?(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?
-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:
\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[
^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*<(?-xism:(?-xi
sm:(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^(
)\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(
?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))
|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<
>\[\]:;@\,.<DQ>\s]+(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]
+)*)(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))
|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:
(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s
*\)\s*))+)*\s*\)\s*)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?
:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x
0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xi
sm:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*
<DQ>(?-xism:(?-xism:[^\\<DQ>])|(?-xism:\\(?-xism:[^\x0A\x0D]
)))+<DQ>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\
]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-x
ism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+
)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))\@(?-xism:(?-xism:(?-xism:(
?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?
-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^
()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s
*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+(
?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+)*)(?-xism:(?-xism:
\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[
^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+)
)|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)
+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:
(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((
?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\
x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*\[(?:\s*(?-xism:(?-x
ism:[^\[\]\\])|(?-xism:\\(?-xism:[^\x0A\x0D])))+)*\s*\](?-xi
sm:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:
\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(
?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+
)*\s*\)\s*)+|\s+)*)))>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-
xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^
\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))|(?-xism:(?-x
ism:(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^
()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*
(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D])
)|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()
<>\[\]:;@\,.<DQ>\s]+(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s
]+)*)(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+)
)|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism
:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\
s*\)\s*))+)*\s*\)\s*)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((
?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\
x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-x
ism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)
*<DQ>(?-xism:(?-xism:[^\\<DQ>])|(?-xism:\\(?-xism:[^\x0A\x0D
])))+<DQ>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\
\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-
xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)
+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))\@(?-xism:(?-xism:(?-xism:
(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(
?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[
^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\
s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+
(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+)*)(?-xism:(?-xism
:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:
[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+
))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*
)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism
:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\(
(?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A
\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*\[(?:\s*(?-xism:(?-
xism:[^\[\]\\])|(?-xism:\\(?-xism:[^\x0A\x0D])))+)*\s*\](?-x
ism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism
:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:
(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))
+)*\s*\)\s*)+|\s+)*))))(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?
>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:
\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0
D]))|)+)*\s*\)\s*))+)*\s*\)\s*)*)"
.Replace("<DQ>", "\"")
.Replace("\t", "")
.Replace(" ", "")
.Replace("\r", "")
.Replace("\n", "");
#endregion
private static Regex mailbox =
new Regex(gibberish, RegexOptions.ExplicitCapture);
public bool WellFormed(string address)
{
return mailbox.IsMatch(address);
}
}
[TestFixture]
public class Test
{
private SyntaxChecker checker = null;
[SetUp]
public void SetUp()
{
checker = new EmailAddressChecker();
}
[Test]
public void SimpleAddress()
{
Assert.IsTrue(checker.WellFormed("foo@example.com"));
}
[Test]
public void MustHaveLocalAndDomain()
{
Assert.IsFalse(checker.WellFormed("justlocal"));
}
[Test]
public void AmpersandInLocalPart()
{
Assert.IsTrue(checker.WellFormed("\"foo & bar\"@example.com"));
}
[Test]
public void PhraseAndAngles()
{
Assert.IsTrue(checker.WellFormed("Joe <joe@example.com>"));
}
[Test]
public void AddressAndComment()
{
Assert.IsTrue(checker.WellFormed("joe@example.com (Joe)"));
}
[Test]
public void ContainsSingleQuoteInParenComment()
{
Assert.IsTrue(checker.WellFormed("oleary@example.com (Mr. O'Leary)"));
}
[Test]
public void ContainsSingleQuoteInBareComment()
{
Assert.IsTrue(checker.WellFormed("Mr. O'Leary <oleary@example.com"));
}
[Test]
public void ContainsSingleQuoteInLocalPart()
{
Assert.IsTrue(checker.WellFormed("o'leary@example.com"));
}
}
}
Thursday, October 06, 2005
Monday, October 03, 2005
Nicer parser notation
Continuing our parser improvements, we can follow Dominus's lead and use operator overloading to cut down the syntactical clutter:
Operators added to Parser
public static Parser operator -(Parser a, Parser b)
{
return new Concatenate(a, b);
}
public static Parser operator |(Parser a, Parser b)
{
return new Alternate(a, b);
}
public static Parser operator >(Parser p, ValuesTransform map)
{
return new T(p, map);
}
// C# forces us to overload < and > in pairs
public static Parser operator <(Parser p, ValuesTransform map)
{
return new T(p, map);
}
Add a few more static helpers, and we have the following much nicer looking generator.
static Parser MakeParser()
{
ParserStub exprstub = new ParserStub(new StubToReal(GetExpression));
ParserStub termstub = new ParserStub(new StubToReal(GetTerm));
ParserStub factstub = new ParserStub(new StubToReal(GetFactor));
expression =
termstub - _(Tokens.Operator, "+") - exprstub > TOpFirst |
termstub;
term =
factstub - _(Tokens.Operator, "*") - termstub > TOpFirst |
factstub;
Parser open = _(Tokens.Operator, "(");
Parser close = _(Tokens.Operator, ")");
Parser comma = _(Tokens.Operator, ",");
Parser arglist =
open - exprstub - new Star(comma - exprstub) - close;
factor =
_(Tokens.Identifier) - (arglist | new Nothing()) > TTagVarOrFunction |
open - exprstub - close > TStripParens |
_(Tokens.Integer);
return exprstub - new EndOfInput() > TOnlyExpression;
}
In Higher-Order Perl, Dominus overloads right-shift to generate a transformation instead of greater-than as above, but C# requires the second operand of >> to be an int. Note also that C# requires overloading both the less-than and greater-than operators if either is defined.
Using binary operators changes the structure of the AST. This has the effect of beating OpFirst with an ugly stick:
static private ArrayList OpFirst(ArrayList values)
{
ArrayList result = new ArrayList(3);
result.Add(((ArrayList)values[0])[1]); // ugh
result.Add(((ArrayList)values[0])[0]);
result.Add(values[1]);
return result;
}
Sunday, October 02, 2005
Poor Shula decision hurts Tide again
Alabama came up huge against Florida, only to have the great victory spoiled by a terrible injury to the gifted Tyrone Prothro.
Reminding us of Shula's stupid decision last year to leave Brodie Croyle in with a big lead over Western Carolina, which resulted in losing Croyle to a season-ending knee injury, now we've lost Prothro for the rest of the way. We had no business throwing at the end zone with the starters in the fourth quarter. You play more conservatively with a big lead because Tide tradition is winning with class -- we aren't out to embarrass other teams -- and so you don't risk injuries!
What a shame that Tyrone Prothro paid the price for Mike Shula's low-class move!