Hackfoofery

Alson Kemp

GitHub, ‘git’ and the forking fallacy

Written by alson

December 18th, 2008 at 1:04 am

Posted in Geekery,Haskell,Programming

Bookmark and Share

GitHub is a pretty sweet system. One of the best aspects of web 2.0 has been the focus on simple, straightforward web app usability/utility.  GitHub is a great example of some of web 2.0′s best attributes: a really interesting model coupled with straightforward usability and just a touch of AJAX.  I never would have tried Git without GitHub.

Git is pretty interesting, too. Turns out that git is effective at encouraging social involvement in coding. The Turbinado project has been forked a few times… ‘Forked’?! Wait! That’s what happens when projects are in deep trouble, right?!

Maybe so, but not necessarily in git. Since git is a decentralized revision control system (like our beloved darcs), ‘forking’ is roughly equivalent to ‘checking out’. A ‘fork’ is a good thing, so Rails’ fork count (398) is heroic.

with 3 comments

Thinking About Haskell*: You Know Lazy Evaluation; You Just Don’t Know It

Written by alson

December 16th, 2008 at 1:33 am

Posted in Geekery,Haskell,Programming

Tagged with

Bookmark and Share

[Post updated to reflect comments. ...too much late night typing...] Lazy evaluation is a very novel aspect of Haskell. Turns out that it’s not that difficult to think about.

A very common example of lazy-ish evaluation is ‘&&’ operators used in lots of languages (using C#):

if ( (obj != null) && (obj.someMethod() == somethingElse) ) {
  // do something
}

Read the rest of this entry »

with 15 comments

A HAML parser for Haskell

Written by alson

December 11th, 2008 at 1:56 am

Posted in Geekery,Programming

Tagged with , ,

Bookmark and Share

HAML‘s lovely. As I’ve been working with Turbinado, I’ve been having some issues with HSP. HSP is an insanely impressive piece of software, but its error messages can be a bit unclear. So I started playing around a bit with HAML. Got me wondering “How easy would be to write a HAML parser in Haskell?”

So I tried. Here’s a first-pass, to-be-updated [and somewhat incomplete] HAML parser for Haskell. Not all of the features are implemented, but it’s a start.  It generates HTML bits suitable for compilation by GHC.

Input

f = content
 
page = #content
         .left.column
         %h2 Welcome to our site!
         %p = print_information
         %p
           = print_inline
         .right.column
           = render
         [abba = ding, ding = abba] dinger

Output

f =
    (stringToHtml "content")
page =
       ((tag "div"![strAttr "id" "content"])
         ((tag "div"![strAttr "class" "left column"])
         ((tag "h2")
             (stringToHtml "Welcome to our site!")
         )
         +++
         ((tag "p")
            (stringToHtml print_information)
         )
         +++
         ((tag "p")
           (stringToHtml print_inline)
         )
         +++
         ((tag "div"![strAttr "class" "right column"])
           (stringToHtml render)
         )
         +++
         ((tag "div"![strAttr "abba" "ding", strAttr "ding" "abba"])
                                    (stringToHtml "dinger")
         )
         )
       )

le Code

module Main where
 
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Language
import Text.ParserCombinators.Parsec.Pos
import qualified Text.ParserCombinators.Parsec.Token as T
import Data.Char
import Data.List
import Data.Maybe
import System.IO.Unsafe
 
main = do s <- getContents
          case (parse mainParser "stdin" s) of
            Left  err -> putStrLn "Error: " >> print err
            Right hs  -> putStrLn hs
 
-- Try to parse HAML, otherwise re-output raw lines
 
mainParser = do whiteSpace
                ls <- many1 (hamlCode <|> tilEOL)
                return $ unlines ls
--
-- * HAML lexer
--
hamlLexer = T.makeTokenParser emptyDef
whiteSpace= T.whiteSpace hamlLexer
lexeme    = T.lexeme hamlLexer
symbol    = T.symbol hamlLexer
natural   = T.natural hamlLexer
parens    = T.parens hamlLexer
semi      = T.semi hamlLexer
squares   = T.squares hamlLexer
stringLiteral= T.stringLiteral hamlLexer
identifier= T.identifier hamlLexer
reserved  = T.reserved hamlLexer
reservedOp= T.reservedOp hamlLexer
commaSep1 = T.commaSep1 hamlLexer
--
-- * Main HAML parsers
--
 
-- hamlCode is just many identifiers (e.g. 'func a b c' followed by '=' followed by a hamlBlock
-- func a b c = %somehaml
hamlCode = try ( do is <- many1 identifier
                    symbol "="
                    currentPos <- getPosition
                    x <- manyTill1
                          (lexeme $ hamlBlock)
                          (notSameIndent currentPos)
                    return $ (concat $ intersperse " " is) ++
                             " = \n" ++
                             (concat $ (intersperse (indent currentPos ++ "+++\n")  $ filter (not . null) $ x))
                  )
 
-- A Block may start with some whitespace, then has a valid bit of data
hamlBlock   = do currentPos <- getPosition
                 bs <- manyTill1
                      (pTag <|> pText)
                      (notSameIndent currentPos)
                 return $ intercalate (indent currentPos ++ "+++\n") bs
 
pTag    = do    currentPos <- getPosition
                try
                    (do t  <- lexeme tagParser
                        ts <- (isInline currentPos >> char '/' >> return []) <|>
                              (hamlBlock)
                        return $ intercalate "\n" $ filter (not . null) $
                          [ (indent currentPos) ++ "((" ++ (if (null ts) then "i" else "") ++ t  ++ ")"
                          , if null ts then [] else ts
                          , (indent currentPos) ++ ")\n"]
                    )
 
pText = lexeme stringParser
 
notSameIndent p = (eof >> return []) <|>
                  (do innerPos <- getPosition
                      case (sourceColumn p) == (sourceColumn innerPos) of
                                True  -> pzero
                                False -> return []
                  )
 
--
-- * Various little parsers
--
 
tagParser :: CharParser () String
tagParser = do     t <- optionMaybe tagParser'
                   i <- optionMaybe idParser
                   c <- optionMaybe (many1 classParser)
                   a <- optionMaybe attributesParser
                   if (isJust t || isJust i || isJust c || isJust a)
                     then
                       do return $ "tag \"" ++ (fromMaybe "div" t) ++ "\"" ++
                           (if not (isJust i || isJust c || isJust a) then "" else
                              concat $
                               [ "!["
                               , intercalate ", " $ filter (not . null)
                                   [ (maybe "" (\i' -> "strAttr \"id\" \"" ++ i' ++ "\"") i)
                                   , (maybe "" (\c' -> "strAttr \"class\" \"" ++ (intercalate " " c') ++ "\"") c)
                                   , (maybe "" (\kv -> intercalate ", " $ map (\(k,v) -> "strAttr \"" ++ k ++ "\" \"" ++ v ++ "\"") kv) a)
                                   ]
                               , "]"]
                           )
                     else pzero
 
tagParser' :: CharParser () String
tagParser' =  do char '%'
                 many1 termChar
 
idParser :: CharParser () String
idParser = do char '#'
              many1 termChar
 
classParser :: CharParser () String
classParser = do char '.'
                 many1 termChar
 
attributesParser :: CharParser () [(String, String)]
attributesParser = squares (commaSep1 attributeParser)
 
attributeParser :: CharParser () (String, String)
attributeParser = do k <- identifier
                     symbol "="
                     cs <- many1 identifier
                     return (k, intercalate " " cs)
 
stringParser :: CharParser () String
stringParser = do   currentPos <- getPosition
                    modifier <- optionMaybe (char '=' <|> char '-')
                    whiteSpace
                    c <- alphaNum
                    cs<- tilEOL
                    case modifier of
                      Just '-' -> return $ (indent currentPos) ++ "-" ++ c:cs
                      Just '=' -> return $ (indent currentPos) ++ "(stringToHtml " ++ c:cs ++ ")"
                      Nothing  -> return $ (indent currentPos) ++ "(stringToHtml \"" ++ c:cs ++ "\")"
 
--
-- * Utility functions
--
 
isInline     p = do p2 <- getPosition
                    case (sourceLine p  ) == (sourceLine p2) of
                      True -> return []
                      False -> pzero
isSameIndent p1 p2 = (sourceColumn p1) == (sourceColumn p2)
 
tilEOL = manyTill1 (noneOf "\n") eol
eol = newline <|> (eof >> return '\n')
 
termChar = satisfy (\c -> (isAlphaNum c) || (c `elem` termPunctuation) )
termPunctuation = "-_"
indent p = take (sourceColumn (p) - 1) (repeat ' ')
 
manyTill1 p e =  do ms <- manyTill p e
                    case (null ms) of
                      True  -> pzero
                      False -> return ms

Golly, but I wish that I’d cleaned up the code, but there it is in all of its raw, un-thought-through glory…

with 2 comments

ANNOUNCE: Turbinado V0.2 “Still Ugly”

Written by alson

November 26th, 2008 at 2:11 am

Posted in Geekery,Programming,Ruby On rails,Work

Bookmark and Share

More progress on Turbinado. Look! A whole “+0.1″!

Progress continues on Turbinado.  Turbinado can be found at:
 http://www.turbinado.org

The source can be found at:
 http://github.com/alsonkemp/turbinado/tree/master
   (see the /App directory for the code for www.turbinado.org)

New in V0.2:
  * A better "Environment" type (rather than using Dynamics) (-> a 50%
speed boost?  That's unpossible!);
  * A functional early version of an ORM for PostgreSQL (note: still
needs to handle updates; hdbc-postgresql has a bug with sensing
nullable columns);
  * A prettier website;
  * Licensing -> BSD.

Expect V0.3 in the next week or so with:
  * More view helpers;
  * An ORM which handles INSERT/UPDATE...;
  * A little CMS built using the ORM.

Future release:
  * Separate the website out from the framework.  For now, they're
evolving together, so live together. 

without comments

ANNOUNCE: Turbinado V0.1

Written by alson

November 18th, 2008 at 2:10 am

Posted in Geekery,Programming,Ruby On rails

Tagged with

Bookmark and Share

Posted to the Haskell mailing list:

I'd like to announce Turbinado, a very young and raw MVC web framework
for Haskell.  While the framework doesn't exactly copy Ruby on Rails,
it certainly rhymes...  It's very early days for Turbinado, but the
framework is moving along nicely.  There are still issues to be ironed
out and architectural details to be decided, so help/contribution would be
very much appreciated.

Turbinado can be found at:
<a rel="nofollow" href="http://www.turbinado.org/" target="_top">http://www.turbinado.org</a>

The source can be found at:
<a rel="nofollow" href="http://github.com/alsonkemp/turbinado/tree/master" target="_top">http://github.com/alsonkemp/turbinado/tree/master</a>
(see the /App directory for the code for www.turbinado.org)

Turbinado:
* Provides a fast web server (based on HSP; see
<a rel="nofollow" href="http://turbinado.org/Home/Performance%29;" target="_top">http://turbinado.org/Home/Performance);</a>
* Provides a straightforward organization for your website (courtesy
of Rails);
* Uses simple HTML-like templating (courtesy of HSX);
* Is easily extensible (courtesy of an Environment built out of _Map
String Dynamic_, not the most type-safe of beasties; Help!);
* Configurable routing (see Config/Routes.hs).

Turbinado is currently lacking:
* Documentation...
* An easy install...
* A database ORM based on HDBC (visibly incomplete and ugly in
Turbinado/Database/ORM);
* Many more HTML helpers;
* Controllers for partials (lightweight "controls" ala ASP.NET);
* Strong error reporting and handling;
* Lots of functionality and plugins;
* ... the favorite feature that you want to develop for Turbinado ...

without comments

Commentary: “RMS hates cloud computing; says you should too”

Written by alson

October 3rd, 2008 at 10:35 am

Posted in Business

Tagged with ,

Bookmark and Share

See here for a much discussed article on how RMS has said he hates cloud computing.  I’m usually pretty on board with what RMS says (after I filter out the uber-geek-bias), but I’m on the fence about this issue.

My counter argument to RMS’s argument is: Damn!, but online services are just too handy to leave aside in order to maintain software development philosophical purity.  Would you give up online e-mail, social networks, etc?

Besides, I love having fewer applications installed on my computer.  I install and focus on the applications I really, really need and the other needs are served out there in the cloud.

RMS’s comment strikes me as purely academic with little consideration for What Really Works.  I hope that online e-mail doesn’t go away, but I’d love to know how to make it more GNUy.

without comments

Further evidence that newspapers are in trouble…

Written by alson

October 1st, 2008 at 1:02 pm

Posted in Business

Tagged with

Bookmark and Share

BusinessWeek has more column inches on the pressing subject of the decline of newspapers…  I wrote a bit about this last week, concluding that we should probably be more worried about what to do with all those big-brained reporters than about what to do with newspapers.  Jon Fine focuses a bit on the topic of what to do with the reporters, but (probably courtesy of not looking very hard) I haven’t generally seen much discussion about what to do with the reporters, which are the big asset in the newspaper biz.  And if we have had loads of discussion about how to fix the industry, then why are we still writing articles about the fact that the industry is dying?

without comments

Pretty Firefox: ‘Chrome Package’

Written by alson

September 26th, 2008 at 10:19 pm

Posted in Tools

Tagged with , ,

Bookmark and Share

I’m comfortable with Firefox.  Stable, loads of developer tools, etc., but Google’s Chrome looks awful nice and is screen space efficient.  Fortunately, some lovely fellow has made a Firefox add-on to make Firefox look like Chrome:

Chrome Package

This add-on hides the Firefox toolbar (as opposed to Chromifox, which only provides colors and images).

without comments

Newspapers are dying… and?

Written by alson

September 23rd, 2008 at 10:27 pm

Posted in Business,Work

Tagged with

Bookmark and Share

Scoble opines on whether we can re-’kindle’ the newspaper industry:

“For example, the Times‘ software architect Derek Gottfrid showed me his Times Machine, an app that lets you search and read old copies of the paper. I’d pay for that.”

I’m sure that the Times Machine is super cool, but I’m a bit puzzled by these articles.  I’m an old man (when measured in Internet years) and I have no idea why/how articles on how the newspaper industry can thrive/survive are relevant to me.  Scoble has to fill column inches, but he’s kinda trod this ground before.

There are lots of good [old] articles out there that do a nice job of thinking through the newspapers’ dilemma.

Big Juicy Brains

Seems that what we really care about is how we keep all of those big-brained investigative journalists employed gathering news…  And a Times Machine app doesn’t seem to be the solution to that problem.  Blogging doesn’t feel right, either.  Loads more fun certainly, but blogging usually serves up derivative works, not the original, investigative pieces of the big newspapers.

I’m not strong on the history of the Associated Press (or any of the other news production aggregators), but the Newspaper vs. Blog situation certainly points in the AP’s direction.  Newspapers mix advertising and content origination (reporting) together in one big package.  They also pay the AP for larger pieces of content that they’re happy to share with all of the other newspapers: international news; local stories which have high national relevance; random science stories; etc.  Basically, anything that the paper wants to report on, but doesn’t want to hire the people to do the reporting.  The Newspaper v. Blog situation suggests to me a complete decentralization of news production and news distribution, as opposed to the current situation in which newspapers mix the two.

So now we’re in the glorious future in which the AP produces news, legions of bloggers distribute the news and you subscribe to the feeds of 4-5 of your favorite bloggers so that you get both their news selections and their news interpretations.  Lovely.  So how does the AP make money?  Naturally, the bloggers are all making money on advertising.  So the AP should get a cut of the advertising revenues, but the AP can’t trust me to accurately report my advertising revenues.

The AP could create a partnership with a large advertising network or two and adopt a Publish-My-Content, you Publish-My-Ads business model.  Adopt a rev share (60% to publisher, 40% to AP ?) and let the blogosphere go nuts with their content.  (Probably need to hire a brigade or two of lawyers to make examples of a few people who’re abusing the system.)  I’ll get the bloggers I love feeding me digested bits of AP content with the particular spin I love.  I’m happy to be advertised to and the blogger will probably be happy to share revenue with the paper in order to get access to primo content.

Lots of wrinkles (e.g. how’s copyright affect this idea?) and implementation details (e.g. dude, you should totally use AJAX) left as an exercise to the reader, but it certainly feels like the newspaper industry is going to be decentralized.  The sooner the big papers (read: NYTimes, LATimes, WSJ, etc) get out in front of the decentralization the better.

Throw Away Line For Those Writing Hand-Wringing Articles About The Death Of The Newspaper Industry

Won’t someone write an article expressing deep concern about the health of the printing press industry?

with one comment

Pretty URLs – how-tos & guides

Written by alson

September 10th, 2008 at 2:09 pm

Posted in Best Practices

Tagged with , , ,

Bookmark and Share

Since we run a membership-fee-based service, we’ve focused on providing security for our inside-the-walled-garden URLs. It’s been important to protect the content generated by our members for our members from being scooped out by unscrupulous operators. That said, we’re probably getting to the point at which we should pretty up our URLs, if only to enhance our member experience and ease with which members can find their content.

In searching around for guidance on how to go about switching to pretty URLs, I’ve found the following helpful:

  • A Report on one company’s experience with switching to pretty URLs
  • An analysis of that report here.
  • A bunch of solid advice on how to think about pretty URLs.
  • Nuts & bolts about setting up Apache for URL rewriting.

without comments