Tuesday, August 18, 2009

Posixy stuff and Haskell

The GHC Haskell compiler and library set it comes with has a nice bit of POSIX functionality. Today, however, I found myself really wanting for a program that could popen a program, giving me back a pair of handles to communicate with the external program, and allow me to do Expect-like things with the interaction.

Essentially I need a bot. The bot needs to talk to a device that speaks SMASH CLP, and my initial thoughts were to write some Haskell code around the useful function interact, or rather, a close relative of interact.

Interact has the signature

interact :: (String -> String) -> IO ()

This just means that it takes a function which takes a String as input and produces a String as output, and the result of interact is an IO action that returns ().

What this gives me is the ability to process input strings, to produce output strings, which get read in and written out by the IO action that is the result of interact. It interleaves the pure functional processing around the input to create output.

The way it works is by calling the function getContents, which lazily reads all the input from stdin and processes it through the provided (String -> String) function, to produce output.

At first glance, this is not seemingly a very advantageous function, except when you take into account all the ways you can set up the IO before calling interact to get some nice behaviors.

For example, if one sets the handles for stdin and stdout to "LineBuffer" based buffers before calling interact, you can get linewise input by doing the following inside the (String -> String) processing function.

lineId = unlines . lines

The function lineId breaks up the lazy input string into lines, then re-assembles them by composing the function lines and unlines together.

The type of the function lines is:

lines :: String -> [String]

The type of the function unlines is

unlines :: [String] -> String

One would think that these two functions would just negate each other, and they do when combined as "unlines . lines" returning the original input to lines, however, if I add further behaviors to the function composition expression that operate on the [String] result of lines before running unlines I have the opportunity to work on each member of the list.

This gives me guaranteed linewise input evaluation of commands, and the ability to interpret line-oriented protocols, strings or what have you.

Now think of how useful interact can be?

Now, interact by itself is only dealing with stdin and stdout. Perhaps I want to open a connection to a remote service, or even a stream of in and out data. It is not terribly hard to write a relative to interact that can handle those sources of data.

hInteract :: Handle -> Handle -> (String -> String) -> IO ()
hInteract inp out f = hPutStr out . f =<< hGetContents inp

This function can take a handle for input, a handle for output, and a function of String -> String, and uses them to lazilly read input from the input handle, pushing data through the String -> String function, to finally output the result string to the output handle.

All of the interesting parts of this function are still contained in f.

The part that's kind of exciting now is that I don't have to limit myself to just line based input if I consider using functions like words and unwords.

I think I'm nearly ready to write an almost IO free, pure version of my Expect-like code bot in Haskell.

Monday, August 10, 2009

Keepin Busy

Been trying to get a handle on "nice looking Haskell" network code. I've got some tasks at work that might actually require me to do some network coding in Haskell so that feeds nicely into my 9p implementation in Haskell, but, at the same time, I'm very concerned about data sizes and understanding how Haskell programs garbage collect, and understanding the waxing and waning of data allocation sizes in a lazy language.

I've not revisited 9p in general in a while. Still hoping to get a native Plan 9 box up and running somewhere that I can play around with.

I do want to get back to this project though. Every once in a while, I look at things like Facebook's Thrift, or other RPC mechanisms that are meant to be language neutral, and I think "this could have been 9p". It's interesting to try anyway just to understand the limitations of one thing vs another.


Tuesday, July 14, 2009

Need a new machine

I recently posted to 9fans that I think I would like to get a new dedicated plan 9 box.

Here's my wish list:

  • Small footprint
  • Low power consumption
  • Connection to a large amount of storage, perhaps a 1TB disk external if I can configure it as such.
  • Good Plan 9 support
  • Low cost
I'm finding people are migrating towards dual core Intel Atom boards. This seems like a reasonable start. SATA disks would be nice, and Solid State Disk (SSD) would be even better on the SATA interfaces. Sound support is really not needed, as I'm never in my office, and there's plenty of good USB sound devices out there it seems, like these Turtle Beach Audio Advantage Devices. So adding that later isn't going to be very difficult.

I was kind of disappointed recently to find my old trusty AMD box's CMOS battery was dead, and that I had to do a lot of interesting memory searching to remember some of the configuration I had in the BIOS to even get FreeBSD running again. Then when I tried to load a recent Plan 9 (new 9load based) it wouldn't even find anything to boot from but bios0 and fd0.

This machine's floppy drive is shot, and bios0 is the first hard disk in the machine, so that's not going to work when I'm trying to boot/install from a CD....

The key is I've got to get a low-cost machine... I just don't have a ton of money to throw around these days.

In the meantime I've been doing well with VMWare Fusion 2.x on Mac OS X to get a terminal server running. But I don't like using that for long term stuff.

One day, I might see what it would take to get Plan 9 ported to what seems like will be inevitable quad core ARM servers. Then perhaps I'll take a swing at a port. Plan 9 seems like a great OS for a platform such as that. Might be easier to get Inferno going though depending on the hardware.

Fun Distraction


As you can tell I like Plan 9. I recently have been trying to catch up with the latest developments in that OS. There's been a new USB driver, new 9load bootloader (which probably ought to be replaced with just the main kernel, and that is currently a summer of code project for google), and linuxemu.

That last one is really interesting. Apparently Russ Cox, and cinap_lenrek have each taken a swipe at making Plan 9 emulate Linux system calls. This is pretty cool in that we can now run a lot of linux programs directly on plan 9, and, in fact, are able to even run Debian complete with apt-get inside a little sandbox.

On top of that fgb actually ported an X11 server to APE (the POSIX compatibility layer for Plan 9) to use libdraw as a graphics backend. (it's called "equis"). Put that together with linuxemu and you can run Mozilla, Firefox, Opera etc, right in Plan 9.

I got some help getting it up and running from cinap, and after getting font files I was missing, I've got Mozilla up in Plan 9. I told him I was reasonably impressed with the speed, though he informed me that each Linux system call ends up being 4 on plan 9. I'm not sure what can really be done about that at the moment, but this instantly gives plan 9 users a capability they didn't have before - reasonable web browser access.

Now I wonder if when Google's Chrome OS comes out if we'll be able to use that and not need X at all....



Wednesday, July 8, 2009

Not quite dead

http://code.google.com/p/9ph/ is where I've stored what I've got so far for my 9p in Haskell implementation. It's incredibly larval, if not fetal at this point and doesn't do much.

In fact, I'm not even convinced I like what I've written at all so far, but it is true, that I can negotiate the TVersion/RVersion client-connect requests of a 9p2000 client to a 9p2000 server.

I've been having a very busy summer, full of family fun, and various work projects. I've been having to spend any of my extra time that does crop up on work related work as there's always more to do...

I'm still hopeful for this project, plus the new capabilities of cross compiling Haskell code from the JHC compiler to the iPhone (it can use a gcc backend that is the native iPhone compiler). If JHC would support more of GHC's capabiliteis, I'd be in business to do some interesting 9p related projects from the iPhone to varying Plan 9 or Inferno or any 9p2000 service.

It's rather exciting really. Especially when you consider how I'd really like to have a litghtweight IRC filesystem client (uses 9p2000) to my Inferno box, running on a Linksys router. Two lightweight systems running a distributed application with a sane protocol in between == beauty.

... I'll get there one day.

Wednesday, June 3, 2009

Success

Made progress on Tversion/Rversion comms. It works. It was a matter of using the correct decoder... big D'oh, on my part.

Next is the hard stuff.

And first I have business travel to contend with, for the first time in a while.

Monday, June 1, 2009

Progress

Sometimes I just need to RTFM closer.

I just discovered the problem in my 9P haskell lib is really just that the data portion of every 9p "s" message has it's own size header (16bit).

Tversion encode and send now works via Nine.hs as a client. I am able to get the Rversion reply back and verify that it is NOT Rerror, but only visually by inspecting a hex dump as my instance of "Binary" does not succeed in "get"ting the response appropriately.

Still, I consider this progress.

I've decided to call this little project 9ph for now, (9p in haskell)