Parrot 0.2.2 Released

Parrot 0.2.2 has been released! Parrot is a versatile virtual machine for dynamic languages. Though originally designed for Perl 6, it's power and flexibility has generated a lot of interest in the language development community. Parrot is distributed with a number of sample compiler implementations at varying stages of completion, including partial compilers for common languages like lisp, scheme, tcl and python.

The latest release features grammar and rule support in PGE, the Parrot Grammar Engine. Parrot also comes with utilties that convert PIR (Parrot Intermediate Representation) and PASM (Parrot Assembly) into PBC (Parrot bytecode).

Those who are interested in learning how to implement languages for Parrot should start with the documentation. You may also be interested in my own (extremely feeble) attempt at implementing PIR generators in Haskell and Ocaml.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Pugs compiles Perl 6 to Parrot, too

A few weeks ago (June 18), I got the unit test framework (Test.pm) of Pugs compiling from Perl 6 and running on Parrot, using the GADT-based PIL intermediate language, as well as an abstracted PIR tree emitter.

It works pretty well -- we are working with the Python-on-Parrot people to see whether we can work toward unified ASTs. See my slides and paper for more information... I'd gladly hand out committer bits to new lambdacamels. :-)

autrijus, you have won...

autrijus, you have won yourself the right to be called by name, and it's a well deserved right, yessir!

Pugs is fascinating, (I gotta yet get the lastest version and I also gotta dig into the technical documentation). I see there are many things that aren't working quite yet, which is understandable, but it's already a really brilliant work (and an excellent proof by crafting of FPL on the works)

A quick question I have, however, that maybe you may brief for me (and the rest of us). Monads: all that out put and input, you are using them, right? How???

(N.B. obviously I'm just amateurish in Haskell)

thanks for your hard work, and keep it up!

Monads

Thank-you for your kind words. Yes, Pugs uses its own Eval monad and SIO monad, as well as use the ContT, ReaderT and eventually oleg's CC_2CPST subcontinuation monad transformers.

I'd like to refer you to the Pugs READTHEM file; in the "Some Online Haskell Resources" section there are numerous URLs that explains monads. :-)

on LtU

An honest question

Although I understand the concept of monads, and I have used them in projects, I don't understand how they can shelter me for introducing bugs in my code. So please consider this as an honest question: how do monads save me from bugs? and what kind of bugs do monads prevent?

An honest answer (I hope)

[See remark below, given my own opinions, I guess this is better answered by a true Haskell evangelist]

As far as I got it: separation of concerns by very explicitly dividing the program into impure parts which deal with the outside world, and pure parts which don't. This is good software engineering practice: the assumption being that it is easier to maintain strong invariants over pieces of code (sometimes, just by looking at the type) which are pure.

As far as I understand it, (a) as a rule of thumb this is an excellent practice, (b) it doesn't help if you don't separate, (c) separation isn't always that easily feasible or (imho) wanted, (d) it doesn't prevent you from introducing other bugs and (e), well, let's say it's an open question and a matter of belief whether you should use monads for that in a general purpose language. [P. Wadler once thought it was a good idea, so that's actually an opinion hard to disagree with]

Additionally...

...monads let you treat computations as first-class values. This lets you define new control structures by writing functions that manipulate computations. For example, you might have a monad type for computations that may fail:

type 'a m = unit -> 'a option

(* unit : 'a -> 'a m *)
let unit v = (fun () -> Some v)

(* fail : 'a m *)
let fail = (fun () -> None)

(* bind : 'a m -> ('a -> 'b m) -> 'b m
let bind v f = 
  (fun () -> 
    match v() with 
    | None -> None
    | Some x -> (f x)())

Now, you can define an operator "$" which takes two arguments, and tries the first one, and if it fails runs the second one and returns that:

(* ($) : 'a m -> 'a m -> 'a m *)
let ($) c c' = 
  (fun () -> 
    match c() with
    | None -> c'()
    | Some x -> Some x)

This kind of thing can make structuring your programs very pleasant, because you can manipulate the program with the operations that make sense with your semantics, rather than just the control structures you have lying around.

Monads? Again?

This question keeps popping up. What do you mean?

Informal explanation in short: [IO] monads are a typesafe manner of sequencing actions which interact with the outside world - the operational semantics of the monad make sure that they are sequenced in proper order.

Personally, I find it an abhorrent hack; but most people will fervently disagree with that view ;-P

(Former) Parrot design leader's blog

For those interested in the history of Parrot development (design decisions, etc), some interesting reading can be found at Dan Sugalski's blog. Until recently, Dan was the Parrot design lead:
http://www.sidhe.org/~dan/blog/

Mixing

One of the things I don't like at all about Parrot Assembly is the mixing between opcodes and API. That makes a lot bytecode to learn and remember, and does not clearly separate what is an optimized opcode or what is an API function.

This has got to be the silliest criticism I've seen levelled yet

The opcodes are parrot's API -- it's tough to interface with a machine, virtual or not, without using machine code.

If you dislike that much of what falls into a traditional runtime library is, instead, built into the machine... I've got to admit to a distinct lack of sympathy. The functionality has to go somewhere, and if you're writing compilers you need to know it all anyway. Where the functionality lives really doesn't matter, and while Parrot's got a relatively large amount of semantic stuffed into it that's because the minimum problem space it needs to guarantee coverage for.

When you're writing compilers for a target system you need to wrap your brain around the whole thing, CPU and runtime libraries. Where things live rarely matters, and when it does it only matters briefly. (If it matters for longer than that you've got some significant issues with your compiler)

The hard part is remembering what functionality is provided. Past that it's straightforward and not a big deal. (Broadsides levelled at documentation, or lack thereof, that makes finding the functionality is warranted, but that's a separate complaint)

The opcodes are parrot's API

Do you think that having the whole standard library into the language specification is a good thing ? I don't think so.

And actually most of the standard library itself could (should) be written in the language itself when possible. And when not possible, using the FFI is the way to go.