Haskell's Parsec. Newbie 1st class.

I'm currently studying haskell's Parsec library. The main difference between Parsec and C's Yacc you need to be aware of is that in Parsec there is no gap between the syntactic rules - the grammar - and the actual use of it. It's all done with regular <awesome> haskell code. 

So let's play. First, I'll need to parse a simple number.


First of all, I need to import Parsec (import Text.ParserCombinators.Parsec). Then, I create a number "rule", explaining what is a number. My explanation is in fact flawed (00000 is not a number) but I'll keep it this way for simplicity's sake. First I say what is the type of my rule. It's number :: Parser Integer. This means I'll write in it some monadic parser code, and spit out an integer. Don't worry if you don't know what "monadic" means. No one really gets it. For our purposes you can think about it as "lines of code inside a do statement".

The oneOf function (oneOf "0123456789") means that it will match a "0", or a "1", or a "2", and so on 'till "9". This is like regex's [0-9]. The many function, as the name makes clear, will match any quantity of the things passed to it. So in our case, it will match one or more characters from 0 to 9. It will match as many as it finds (greedy). In the end, I associate the result of this match to the variable "n" (n <- many (oneOf "0123456789") and return it as a number (return (read n)).

Let's test it. Open ghci and load the file. I'll call it operation.hs.

$ ghci
Prelude> :l operation.hs
[1 of 1] Compiling Main             ( operation.hs, interpreted )
Ok, modules loaded: Main.

Now, we'll use the Parsec's parseTest helper function:

*Main> parseTest number "9"
9
parseTest number "04040"
4040

As you can see, our program is capable of receiving a number string input and returning an evaluated number. Yeah, I admit it is not that impressive. So let's move on. Now, I'll think about operators. Let's use just operators that can work easily with Integers, like plus (+), minus (-), mult (+) and power (^).


The definition of it is really simple. An operator is a char (operator :: Parser Char). It is one of "+", "-", "*" or "^" (o <- oneOf "+-*^"). And it returns the character matched (return (o)). Let's reload the file and test it:

Main> :l operation.hs
[1 of 1] Compiling Main             ( operation.hs, interpreted )
Ok, modules loaded: Main.
*Main> parseTest operator "+"
'+'
*Main> parseTest operator "-"
'-'
*Main> parseTest operator "&"
parse error at (line 1, column 1):
unexpected "&"

As you can see here, it will just match what we told it to match. If we pass "&" to it, it will explode (but the error messages are really helpful).

Now we're getting in the cool part: operations. Operations are, basically, numbers interspersed with operators, like "1+2", "5^2" or "1+2*3-8". In our example, I'll deal only with operations with one operator.

Obviously, the type of operation is Parser Integer, since operating integers will always return an integer unless we use division (and we're not). The code is quite self explanatory. We have a number, that we call "n1" (n1 <- number), then we have an operator that we call "o" (o <- operator), and finally we have another number, that we call "n2" (n2 <- number). And we'll return the result of the function runop passing the operator and the numbers. But we don't have this function yet. So I'll do it using haskell's pattern matching:


The runop function receives a char and two integers and spits out an integer. Its implementation doesn't need more comments. Now we can see if all things hang out together.

Main> :l operation.hs
[1 of 1] Compiling Main             ( operation.hs, interpreted )
Ok, modules loaded: Main.
*Main> parseTest operation "13-26"
-13
*Main> parseTest operation "2+31"
33
*Main> parseTest operation "4*5"
20
*Main> parseTest operation "5^2"
25

Yeah. Thing are fine. Here is the full code:

This example is very very simple. It will not handle operations like "1+2*8", it doesn't allow the use of spaces nor parens. It also can't have state and workout the value of variables, like in "1+x". This is what we're going to see soon.

googbye serialize, hello hstore

Estou finalizando uma gem para trabalhar com hstore, que é um tipo de campo do postgresql (contrib) para armazenamento de hashes. Isso é útil quando você precisa de campos dinâmicos, mas também precisa poder pesquisar nestes.

Quem se interessar (estou precisando muito de alpha testers) pode conferir em:

Qualquer dúvida, manda pelo twitter @joaomilho

Enjoy.

Palestra na TargetTrust no dia 4 de Agosto sobre Rails3

Esquentando os motores para o lançamento do Rails 3 e do RS on Rails, neste dia 4 estarei apresentando uma palestra na TargetTrust. Para se inscrever basta ligar para 3325.2596. O ingresso é um agasalho que será doado.

Para saber mais sobre o Rails 3, escreví um breve artigo sobre ele e sobre a comunidade que foi publicado no Baguete, o principal veículo de TI aqui do estado.

Te vejo lá!

dicas para os pais

Tem muito barbeiro por aí. Por isso, veja as dicas da semana:
  1. Quando andar no auto-choque, segure o seu filho.
  2. Se o seu filho estiver com ânsia de vômito, não insista em levá-lo ao barco Viking.
  3. Retire seu filho da cacunda pela frente.
  4. Não sirva cerveja na festa do seu filho. Muito menos Skol, Polar e essas outras feitas de mijo de cavalo.
  5. Mesmo que você ensine, o seu filho irá correr para o meio da rua.
  6. Não, fandangos não é comida. Bolacha recheada não alimenta. Refrigerante não hidrata.
  7. Babás não sustituem você.
  8. Ser alcoólatra e falar palavrão não é um bom exemplo.
  9. Antes de dar um computador para seu filho, estude sobre filtros de internet.
  10. Quando andar no auto-choque, não deixe o seu filho comer pirulitos compridos.

connecting to mongohq (a great mongodb online service) with Haskell

Connecting to mongohq with Haskell is really simple.

1. Create yout account at https://mongohq.com

2. Install mongodb via cabal:

cabal install mongodb

3. Check this code:

This connects, logs in, inserts and then retrieves a document in a collection. Runnin' main will print something like this:
[[(Chunk "_id" Empty,BsonObjectId 23543969989857644967178010624),(Chunk "author" Empty,BsonString (Chunk "Jo\195\163o Milho" Empty)),(Chunk "text" Empty,BsonString (Chunk "Hello MongoHQ World!" Empty))]]

Your document will also be visible in the mongohq page.

4. More info here: http://github.com/srp/mongoDB/

Enjoy!