<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6892477962078801717</id><updated>2011-11-27T16:06:54.101-08:00</updated><category term='blocks'/><category term='9p haskell'/><category term='documentation'/><category term='pipe dreams'/><category term='plan9'/><category term='community'/><category term='Go programming'/><category term='Apple'/><category term='concurrency'/><category term='Snow Leopard'/><category term='Haskell'/><category term='meta'/><category term='9ph 9p Tim Newsham google code'/><category term='practical'/><category term='Functional Programming'/><category term='Monad'/><category term='9ph Haskell 9p Tim Newsham google code'/><category term='libdispatch GCD prime sieve concurrency Snow Leopard'/><category term='optimization'/><category term='Lazy'/><category term='weird'/><category term='project ideas'/><category term='performance'/><category term='9ph'/><category term='closures'/><category term='Scheme'/><category term='Y combinator'/><category term='9ph 9p Tim Newsham'/><category term='CSP'/><title type='text'>Cool Blog Title Goes Here</title><subtitle type='html'>Stuff I care about, or at least thought about once, that I felt like writing down.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>49</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-4950690016627677124</id><published>2011-04-07T09:15:00.001-07:00</published><updated>2011-04-07T09:19:20.571-07:00</updated><title type='text'>Object Relational Impedance Mismatch Thought</title><content type='html'>Stop trying to make a serialized form of data the same thing as the "live" data.  Serialized data is a recipe for the live data, not the same thing.&lt;br /&gt;&lt;br /&gt;Solving a problem can be easier when you realize the question was incorrect to begin with.&lt;br /&gt;&lt;br /&gt;I don't think of programs running in memory to be the same thing as the source code I wrote either.  There's too many steps between my fingers, the disk, the compiler, and the OS that can make this assumption horribly wrong.&lt;br /&gt;&lt;br /&gt;I realize that having the code eventually tell the computer to do what you mean is the point of a language, but we can't be naive to the way computers actually work, if we want to understand why this assumption can be dangerous and break down.&lt;br /&gt;&lt;br /&gt;I feel this is a similar situation for ORMs.  Perhaps the best way to code is not to pretend an ORM can be perfect.  &lt;br /&gt;&lt;br /&gt;I believe this is one of the things NoSQL will have taught us when we're all ready to jump on the next "new hawtness"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-4950690016627677124?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/4950690016627677124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2011/04/object-relational-impedance-mismatch.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4950690016627677124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4950690016627677124'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2011/04/object-relational-impedance-mismatch.html' title='Object Relational Impedance Mismatch Thought'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-4886168125343104655</id><published>2010-12-14T09:01:00.001-08:00</published><updated>2010-12-14T09:07:19.438-08:00</updated><title type='text'>The D2 Programming Language</title><content type='html'>Just began looking at this one last night.  It's available, with source,  from Digital Mars (http://www.digitalmars.com/d/2.0/), and it's quite interesting.&lt;br /&gt;&lt;br /&gt;It is definitely a general purpose programming language, and addresses many areas where people want to pull out their hair with C++.  It seems it can directly compete with Go (Google's programming language), in the areas of concurrency, has a system of generics and is what I would call a "more than complete" language :-).&lt;br /&gt;&lt;br /&gt;It's actually pretty big, and many people might claim that you don't have to understand what you don't use.  That's only true if you're the only one authoring code in this language, or have a set of restrictions to a subset of the language that you go by.&lt;br /&gt;&lt;br /&gt;Go, on the other hand, is pretty small, and fairly simple.  One can understand the entire language fairly quickly by just reading the specification.  It's quick to learn, the tools are quick, and the code runs reasonably fast.&lt;br /&gt;&lt;br /&gt;D2, at least with the Digital Mars compiler, is pretty fast too.  It can be executed as a "script" of sorts, making it nice for system administrative tasks where you often need the source to be right there.&lt;br /&gt;&lt;br /&gt;Both languages seem to do quite well at achieving their stated goals and philosophies, and I expect them both to become more important to know as time goes on.&lt;br /&gt;&lt;br /&gt;I hope to see both grow in popularity in the not too far off future.&lt;br /&gt;&lt;br /&gt;Dave&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-4886168125343104655?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/4886168125343104655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/12/d2-programming-language.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4886168125343104655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4886168125343104655'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/12/d2-programming-language.html' title='The D2 Programming Language'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-6413731675131772761</id><published>2010-11-28T19:18:00.000-08:00</published><updated>2010-11-28T19:46:21.817-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='closures'/><category scheme='http://www.blogger.com/atom/ns#' term='Go programming'/><title type='text'>Goroutines vs function literals (closures)</title><content type='html'>Goroutines are a kind of heavy way to deal with a situation where you just want some kind of lazy evaluation.  Say I would like to process a file line by line and the basic guts of it looks like this with a goroutines:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;func lineStreamer (out chan &lt;- string) {&lt;br /&gt; file, err := os.Open("/usr/share/dict/words", os.O_RDONLY, 0666)&lt;br /&gt; if err != nil {&lt;br /&gt;  panic("Failed to open file for reading")&lt;br /&gt; }&lt;br /&gt; defer file.Close()&lt;br /&gt;&lt;br /&gt; reader := bufio.NewReader(file)&lt;br /&gt; for {&lt;br /&gt;  line, err := reader.ReadString(byte('\n'))&lt;br /&gt;  if err != nil {&lt;br /&gt;   break&lt;br /&gt;  }&lt;br /&gt;                // Do something interesting here perhaps other than returning a line&lt;br /&gt;  out &lt;- line&lt;br /&gt; }  &lt;br /&gt; close(out)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This greatly simplifies the act of opening the file, dealing with bufio, and gives me an interface I can just read lines from (or processed lines from) on a channel.  But it seems kind of slow, running at about 2.04 to 2.07 seconds on my macbook pro with no runtime tuning.  If I raise GOMAXPROCS to 2 I'm getting between 1.836 seconds to 1.929 seconds.  GOMAXPROCS at 3 is getting me fairly regular 1.83 seconds.&lt;br /&gt;&lt;br /&gt;This got me thinking about how I'd so something like this in other languages.  I don't think I'd need coroutines to do it in Scheme for example, as I could do some delay/force thing to get stuff evaluated in chunks.&lt;br /&gt;&lt;br /&gt;This led me to the following, possibly non-idiomatic version of a Go program using function literals.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;type Cont func()(string, os.Error, Cont)  // string, error, and a function returning the next&lt;br /&gt;&lt;br /&gt;func lineStreamer (file *os.File, reader *bufio.Reader) (string, os.Error, Cont) {&lt;br /&gt; line, error := reader.ReadString(byte('\n'))&lt;br /&gt; return line, error, func () (string, os.Error, Cont){&lt;br /&gt;  return lineStreamer(file, reader)&lt;br /&gt; } &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To evaluate all the lines I can do something like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; s,err,next := lineStreamer(file, reader)&lt;br /&gt;&lt;br /&gt; for err == nil{&lt;br /&gt;  fmt.Printf("%s", s)&lt;br /&gt;  s,err,next = next()&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And my run times are down to about 1.2 seconds.&lt;br /&gt;&lt;br /&gt;I guess my question is, is this idiomatic or not.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-6413731675131772761?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/6413731675131772761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/11/goroutines-vs-function-literals.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/6413731675131772761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/6413731675131772761'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/11/goroutines-vs-function-literals.html' title='Goroutines vs function literals (closures)'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-3965320708540979191</id><published>2010-06-01T23:31:00.000-07:00</published><updated>2010-06-01T23:58:32.881-07:00</updated><title type='text'>OMG C++?</title><content type='html'>I had an interesting problem to solve involving some code that was essentially driven this way:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;while(getline(cin, string) {&lt;br /&gt;   // process string&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A coworker of mine suggested that this would only process a line at a time, which it will, but I was wondering if it was reading a line at a time as well as just serializing activity based on lines read.  In essence I wondered if the input was buffered for cin.&lt;br /&gt;&lt;br /&gt;On my platform I'm testing with, Mac OS X Snow Leopard, it appears that no buffering is really going on.  &lt;br /&gt;&lt;br /&gt;Here's some code to show what I mean:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;void show_stats () {&lt;br /&gt;    if (in) {&lt;br /&gt;        cout &amp;lt;&amp;lt; &amp;quot;Stream is broken or closed\n&amp;quot; &amp;lt;&amp;lt; endl;&lt;br /&gt;    }&lt;br /&gt;    else {&lt;br /&gt;        cout &amp;lt;&amp;lt; &amp;quot;Availble bytes buffered: &amp;quot; &amp;lt;&amp;lt;cin.rdbuf()-&amp;gt;in_avail() &amp;lt;&amp;lt; endl;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This looks at cin's underlying streambuf implementation and looks to see if there's any available bytes in the buffer.  When there's no bytes in the buffer, the istream calls on the internal streambuf's "underflow" function to go get more data, and adjust the buffer for some number of "put back bytes".&lt;br /&gt;&lt;br /&gt;What I found was that at no point was I seeing any buffered input coming in for cin, so I decided to write my own streambuf and subsequent istream classes to deal with both buffering and any file descriptor (unix pipe, socket, file etc).&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;#include &amp;lt;cstring&amp;gt;&lt;br /&gt;#include &amp;lt;streambuf&amp;gt;&lt;br /&gt;#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;&lt;br /&gt;class fd_inbuf_buffered : public std::streambuf &lt;br /&gt;{&lt;br /&gt;protected:&lt;br /&gt;  int fd;&lt;br /&gt;  const int bSize;&lt;br /&gt;  char * buffer;&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;  fd_inbuf_buffered (int _fd, int _bSize=10) : fd(_fd), bSize(_bSize) &lt;br /&gt;  {&lt;br /&gt;    buffer = new char [bSize];&lt;br /&gt;    // The get pointer should not be at the beginning of the buffer, because&lt;br /&gt;    // it limits the ability to do put back into the input stream should &lt;br /&gt;    // there be a need to.  Ideally that situation does not come up, but we &lt;br /&gt;    // leave room for 4 bytes, by pointing all 3 locations to 4 beyond the &lt;br /&gt;    // beginning of the buffer.&lt;br /&gt;    // 4 was the size used in an implementation in Josuttis' "The C++ Standard Library"&lt;br /&gt;    setg(    buffer + 4,  // beginning of putback area&lt;br /&gt;            buffer + 4,  // read position&lt;br /&gt;            buffer + 4); // end position&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  ~fd_inbuf_buffered ()&lt;br /&gt;  {&lt;br /&gt;    delete [] buffer;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;protected:&lt;br /&gt;  // Underflow is what fills our buffer from the fd.&lt;br /&gt;  // if we don't override this, we get the parent, which just returns EOF.&lt;br /&gt;  virtual int_type underflow ()&lt;br /&gt;  {&lt;br /&gt;    //read position before end of buffer&lt;br /&gt;    if (gptr() &amp;lt; egptr())&lt;br /&gt;    {&lt;br /&gt;        return *gptr();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    int numPutback = gptr() - eback();&lt;br /&gt;&lt;br /&gt;    //must limit the number of characters previously read into the putback&lt;br /&gt;    //buffer... 4 maximum&lt;br /&gt;&lt;br /&gt;    if (numPutback &amp;gt; 4)&lt;br /&gt;    {&lt;br /&gt;        numPutback = 4;&lt;br /&gt;    }&lt;br /&gt;    // Copy up to the putback buffer size characters back into the putback&lt;br /&gt;    // area of our buffer.&lt;br /&gt;    std::memcpy (buffer + (4 - numPutback), gptr() - numPutback, numPutback);&lt;br /&gt;&lt;br /&gt;    // read new characters&lt;br /&gt;    int num;&lt;br /&gt;retry:&lt;br /&gt;    num = read(fd, buffer + 4, bSize - 4);&lt;br /&gt;    if (num == 0)&lt;br /&gt;    {&lt;br /&gt;        return EOF;&lt;br /&gt;    }&lt;br /&gt;    else if (num == -1) {&lt;br /&gt;        switch (errno) {&lt;br /&gt;            case EAGAIN:&lt;br /&gt;            case EINTR:&lt;br /&gt;                goto retry;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    //reset buffer pointers&lt;br /&gt;    setg(buffer + (4 - numPutback), buffer + 4, buffer + 4 + num);&lt;br /&gt;&lt;br /&gt;    return *gptr();&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;struct fd_istream : public std::istream&lt;br /&gt;{&lt;br /&gt;protected:&lt;br /&gt;  fd_inbuf_buffered buf;&lt;br /&gt;public:&lt;br /&gt;  explicit fd_istream (int fd, int bufsz) : buf(fd, bufsz), std::istream(&amp;amp;buf) {}&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now I can declare an istream like so:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;fd_istream my_cin(0, 1000);&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Where 0 is the numeric file descriptor for stdin and 1000 is the buffer size in bytes.&lt;br /&gt;&lt;br /&gt;Because I went with the standard IOStream library, as opposed to just writing C style IO directly, I can use it in the same way I'd use any istream.  I can use it with iterators or algorithms from the standard library, and I can even use it with getline as you can see below.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;void show_stats () {&lt;br /&gt;    if (!my_cin) {&lt;br /&gt;        cout &amp;lt;&amp;lt; &amp;quot;Stream is broken or closed\n&amp;quot; &amp;lt;&amp;lt; endl;&lt;br /&gt;    }&lt;br /&gt;    else {&lt;br /&gt;        cout &amp;lt;&amp;lt; &amp;quot;Availble bytes buffered: &amp;quot; &amp;lt;&amp;lt; my_cin.rdbuf()-&amp;gt;in_avail() &amp;lt;&amp;lt; endl;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main  () {&lt;br /&gt;    string line;&lt;br /&gt;    while (getline(my_cin, line)) {&lt;br /&gt;        cout &amp;lt;&amp;lt; line &amp;lt;&amp;lt; endl;&lt;br /&gt;        show_stats();&lt;br /&gt;    }&lt;br /&gt;    show_stats();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In an example run, such as "cat /usr/share/dict/words | ./a.out" I see something like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;Availble bytes buffered: 12&lt;br /&gt;Pinacoceras&lt;br /&gt;Availble bytes buffered: 0&lt;br /&gt;Pinacoceratidae&lt;br /&gt;Availble bytes buffered: 980&lt;br /&gt;pinacocytal&lt;br /&gt;Availble bytes buffered: 968&lt;br /&gt;pinacocyte&lt;br /&gt;Availble bytes buffered: 957&lt;br /&gt;pinacoid&lt;br /&gt;Availble bytes buffered: 948&lt;br /&gt;pinacoidal&lt;br /&gt;Availble bytes buffered: 937&lt;br /&gt;pinacol&lt;br /&gt;Availble bytes buffered: 929&lt;br /&gt;pinacolate&lt;br /&gt;Availble bytes buffered: 918&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;showing how the buffer grows each time I make it read a certain number of bytes, and flows back down to 0.  At 0 it calls underflow again, and I can get more data if available or when I hit EOF, I return that from underflow, causing the stream to terminate.&lt;br /&gt;&lt;br /&gt;This stream will work for pipes, sockets and files as long as the file descriptor is provided to the constructor.  Now because I have a putback buffer size of at least 4, I will have to have allocated at least 4 bytes in my streambuf to make room for the pointers to work properly.  There are possibly better ways to deal with it, but for demonstration purposes, this works nicely.&lt;br /&gt;&lt;br /&gt;C++ isn't always so bad after all.  It just depends on how it's written.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-3965320708540979191?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/3965320708540979191/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/06/omg-c.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3965320708540979191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3965320708540979191'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/06/omg-c.html' title='OMG C++?'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-8078470176906165755</id><published>2010-05-31T10:15:00.000-07:00</published><updated>2010-05-31T10:16:49.246-07:00</updated><title type='text'>Not usually a fan of IDEs... but</title><content type='html'>I'm thinking of trying to use Leksah as my primary Haskell development environment on the Mac.  I like that they seem to be willing to incorporate Yi as their editing environment to some extent, and I'd like to see where that goes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-8078470176906165755?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/8078470176906165755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/05/not-usually-fan-of-ides-but.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/8078470176906165755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/8078470176906165755'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/05/not-usually-fan-of-ides-but.html' title='Not usually a fan of IDEs... but'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-4597302853914350131</id><published>2010-05-26T21:06:00.000-07:00</published><updated>2010-05-26T21:10:49.572-07:00</updated><title type='text'>PLT Scheme is easy</title><content type='html'>Lots of nice frameworks too.  A friend showed me some code he was working to use the Twitter APIs over http to look at people's tweets (if they're not protected).&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I thought this was cool, it was 7 lines of code.  So I thought I'd wrap it up in a GUI.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Keep in mind I'm NOT a GUI programmer by trade, and that this was my very first venture into PLT GUI programming.  It's easy to pick up, and now I've got something hideous that works.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="font-family:monospace;font-size:100%;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span"   style="font-family:Georgia, serif;font-size:130%;"&gt;&lt;span class="Apple-style-span" style="font-size: 16px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#lang scheme/gui (require net/url xml)&lt;br /&gt;(define (u screenname) (string-&amp;gt;url (string-append &amp;quot;http://api.twitter.com/1/statuses/\&lt;br /&gt;user_timeline.xml?screen_name=&amp;quot; screenname)))&lt;br /&gt;(define (f v) (match v (`(text ,_ . ,v) `(,(string-append* v)))&lt;br /&gt;                (`(,_ ,_ . ,v) (append-map f v)) (else '())))&lt;br /&gt;(define g (compose f xml-&amp;gt;xexpr document-element read-xml))&lt;br /&gt;;(call/input-url (u &amp;quot;omgjkh&amp;quot;) get-pure-port g)&lt;br /&gt;&lt;br /&gt;(define dialog (new dialog% &lt;br /&gt;                    [label &amp;quot;Twitter Screen Name Activity Grabulatrixatronulator&amp;quot;]&lt;br /&gt;                    [width 600]&lt;br /&gt;                    [height 100]))&lt;br /&gt;&lt;br /&gt;(define textfield (new text-field% [parent dialog] [label &amp;quot;Enter a Screen Name&amp;quot;]))&lt;br /&gt;(send textfield set-value &amp;quot;omgjkh&amp;quot;)&lt;br /&gt;(display (send textfield get-value))&lt;br /&gt;(newline)&lt;br /&gt;&lt;br /&gt;(define newframe (new frame% &lt;br /&gt;                      [label &amp;quot;Results&amp;quot;]&lt;br /&gt;                      [width 1000]&lt;br /&gt;                      [height 600]&lt;br /&gt;                ))&lt;br /&gt;(define tf (new text-field% [parent newframe] [label &amp;quot;&amp;quot;] [min-height 500]))&lt;br /&gt;&lt;br /&gt;(define (appender los) &lt;br /&gt;  (cond ((null? los) &amp;quot;&amp;quot;)&lt;br /&gt;        (else (string-append (car los) &amp;quot;\n&amp;quot; (appender (cdr los))))))&lt;br /&gt;&lt;br /&gt;(new button% [parent dialog]&lt;br /&gt;                    [label &amp;quot;GITERDUN&amp;quot;]&lt;br /&gt;                    [callback (lambda (button event) &lt;br /&gt;                                (let ((text (appender (call/input-url (u (send textfield get-value)) get-pure-port g))))&lt;br /&gt;                                  (display text)&lt;br /&gt;                                  (newline)&lt;br /&gt;                                  (send tf set-value text)&lt;br /&gt;                                  (send dialog show #f)&lt;br /&gt;                                  (display &amp;quot;here&amp;quot;)(newline)&lt;br /&gt;                                  (send newframe show #t)&lt;br /&gt;                                  (display &amp;quot;here2&amp;quot;)(newline)))])&lt;br /&gt;                                                  &lt;br /&gt;(send dialog show #t)&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-4597302853914350131?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/4597302853914350131/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/05/plt-scheme-is-easy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4597302853914350131'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4597302853914350131'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/05/plt-scheme-is-easy.html' title='PLT Scheme is easy'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-7464791751698338588</id><published>2010-05-26T11:48:00.000-07:00</published><updated>2010-05-26T12:24:01.053-07:00</updated><title type='text'>Current Plan 9 Environment... and loving it!</title><content type='html'>I've got a Plan 9 CPU server running in VMWare Fusion on Mac OS X Snow Leopard.  I ran into a few problems with the setup of this as VMWare Fusion's emulation of IDE disks didn't agree much with Plan 9.  Changing to SCSI disks made all the difference in the world.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I followed and updated a little the Plan 9 wiki's instructions on setting up a CPU/Auth server, and then used it with drawterm, a unix program that works like a little Plan 9 terminal to connect to CPU servers, and all was good.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's a project out there called vx32 which implements a sandboxing/virtualization in userspace library that has been used for a port of the Plan 9 kernel.   I grabbed the latest Mercurial snapshot of this code base, and compiled it (after patching it up so Snow Leopard didn't complain about the deprecated ucontext.h stuff), and now I have a Plan 9 kernel (almost, it's not 100% the same) running as a terminal to connect to my Fusion CPU server.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, now what?  Well I may take a crack at the port of the Go language to Plan 9... when I get time to do this again.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-7464791751698338588?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/7464791751698338588/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/05/current-plan-9-environment-and-loving.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/7464791751698338588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/7464791751698338588'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/05/current-plan-9-environment-and-loving.html' title='Current Plan 9 Environment... and loving it!'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-2135883224154904879</id><published>2010-05-19T09:17:00.000-07:00</published><updated>2010-05-19T09:20:32.847-07:00</updated><title type='text'>Developing for the iPhone</title><content type='html'>The last time I used Objective-C, it wasn't 2.0.  As such, I'm needing to brush up quite a bit on my skills.  I'm not used to having the compiler generate my properties for me, or the dot syntax etc.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm also not a big fan of mixing garbage collection with no garbage collection, I feel that's a recipe for disaster, however I'm going to cautiously proceed anyway.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I will say that the Xcode tools have shown immense improvement since the last release.  I wasn't a fan of them at all, and I was surprised that my muscle memory for emacs keybindings isn't wasted completely in the Xcode editor.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If I can keep my interest level high in this area, I may just splurge for that 99 dollar license to deploy applications.  &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-2135883224154904879?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/2135883224154904879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/05/developing-for-iphone.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2135883224154904879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2135883224154904879'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/05/developing-for-iphone.html' title='Developing for the iPhone'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-3665310191705988865</id><published>2010-05-17T20:29:00.001-07:00</published><updated>2010-05-17T20:29:30.017-07:00</updated><title type='text'>No more Facebook for me.</title><content type='html'>I decided I didn't want to be a part of their product...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-3665310191705988865?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/3665310191705988865/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/05/no-more-facebook-for-me.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3665310191705988865'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3665310191705988865'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/05/no-more-facebook-for-me.html' title='No more Facebook for me.'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-3981480855238961649</id><published>2010-05-10T12:50:00.001-07:00</published><updated>2010-05-10T12:50:18.008-07:00</updated><title type='text'>Thoughts on Lazy Evaluation...</title><content type='html'>... I'll do it later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-3981480855238961649?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/3981480855238961649/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/05/thoughts-on-lazy-evaluation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3981480855238961649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3981480855238961649'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/05/thoughts-on-lazy-evaluation.html' title='Thoughts on Lazy Evaluation...'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-959666326430080851</id><published>2010-05-10T08:36:00.000-07:00</published><updated>2010-05-10T08:58:55.779-07:00</updated><title type='text'>Stuff...</title><content type='html'>So I got an iPad.  I've had it about one month.  I've been paying a lot of attention to the talk about how it doesn't do Flash, why it doesn't do Flash, how Apple is committing war crimes against humanity by disallowing applications authored in 3rd party tools etc etc.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As a developer who's spent a good bit of time working on different projects that scale from tiny little machines, to medium sized computers to giant supercomputing clusters (yes, I've been on several of the top 10 of the top500 list, writing software to squeeze performance out of them) I can tell you that flexible tool chains, great documentation, and great support do not always go hand in hand.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My opinion on that is that it's a bit sad that I won't be writing and running Haskell code on a non-jailbroken i(Phone|Pod|Pad) but that that's not a deal breaker for most people.  Cocoa is a nice framework, with many years behind it making it great.  Objective-C is a pretty cool language, (though I feel they should have kept it simpler, no garbage collection, all this automatic atomic update stuff can be confusing etc).  Grand Central Dispatch and the libdispatch stuff is powerful, even in a raw C programming context, though some folks I know don't think it's well served to use it outside the realm of Objective-C.  Having suffered programming with threads and locks, (even implementing my own locks on certain platforms) I'd say that this is a big step forward in thinking about concurrency and parallelism by means of organizing program code at a low level.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Yes, when you buy Apple's stuff, it's a bit more about doing things "their way" than doing things "your way".  The limits Apple places on the hardware it supports with its operating systems, or the limits placed on programmers via the tool chains, are all really there for 2 reasons (in my opinion).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. It keeps Apple from losing control of its own platform.&lt;/div&gt;&lt;div&gt;2. Apple can focus their engineering and support efforts on making a product that seemingly "just works" with all supported stuff, because the space of stuff to support is a lot smaller!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To me, neither of these things are inherently "evil", as some folks might like to convince you.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I should note I've used my iPad every day since I got it at least one time/day.  To pay for it I began selling some of the stuff I intend not to need anymore, such as my old iPod touch, and my old laptop.  So far it's been a great trade!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-959666326430080851?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/959666326430080851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/05/stuff.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/959666326430080851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/959666326430080851'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/05/stuff.html' title='Stuff...'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-4906265925571954735</id><published>2010-04-14T07:46:00.001-07:00</published><updated>2010-04-14T07:57:11.751-07:00</updated><title type='text'>Just a thought or two on strictness</title><content type='html'>I've noticed that a lot of times when it comes to profiling programs in any language, that it is often surprising where the big cost centers are.  Maybe it's just due to experience, but a lot of times I at least feel like I'm not as surprised in imperative languages when I recognize a cost center or my tool chain does.  With functional languages, I'm often surprised that certain implementations of functions are as costly as they are, while others are not.  This is even more true in "lazy" functional languages like Haskell.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When you're dealing with strict evaluation by default, you can basically just read the program top down and get a good idea for what happens when, and how data much a particular chunk of code ought to be using, and for the most part you'll get this right with experience.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With a language like Haskell, sometimes, all bets are off unless you know very well how a particular library of functionality is implemented.  There's both strict and non-strict versions of Control.Monad.State for example.  The non-strict version almost requires you to read the code, then think about how much stuff can be deferred to the last minute, and realize that those little deferred computations will have to be evaluated later.  This can not only change the order of evaluation and thusly the data size of your program, but can also change the behavior a great deal.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Data.Map has operations within it for update that will be deferred (non-strictly evaluated) and some that are strict.  It's important to read the documentation.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My advice to beginners is to try to understand strictness vs non-strictness (often called laziness) in Haskell as early as possible.  It will give you great leverage to expressing some really beautiful solutions to problems, and save you from pulling all of your hair out or suffering any existential crises when trying to figure out why a program doesn't do what you thought.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All of that said, it's pretty easy for me to see why some people will decide that non-strict functional programming languages are not for them.  It certainly takes a little mind bending to see the value in it if all you've ever done is imperative or strict functional programming, but I promise you the value is truly there.  I also find that by challenging myself to learn how to think in these new paradigms I am simultaneously strengthening my understanding of the older paradigms a good deal more, so give it a shot and don't give up!  There's help out there for you.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-4906265925571954735?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/4906265925571954735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/04/just-thought-or-two-on-strictness.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4906265925571954735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4906265925571954735'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/04/just-thought-or-two-on-strictness.html' title='Just a thought or two on strictness'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-8547030697123607533</id><published>2010-02-20T16:54:00.000-08:00</published><updated>2010-02-20T16:55:28.628-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='9p haskell'/><title type='text'>NineP is on hackage!</title><content type='html'>I'm excited about it.  There's still work to be done, but now I think there's a good chance to get a lot more feedback about the module as it's in experimental, and hopefully we can get some of these folks interested in distributed systems to use this nice, simple protocol.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-8547030697123607533?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/8547030697123607533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/02/ninep-is-on-hackage.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/8547030697123607533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/8547030697123607533'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/02/ninep-is-on-hackage.html' title='NineP is on hackage!'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-5835085844902553309</id><published>2010-02-19T20:35:00.001-08:00</published><updated>2010-02-19T20:39:05.128-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='9ph'/><title type='text'>9ph package for cabal/hackage</title><content type='html'>The &lt;a href="http://9ph.googlecode.com"&gt;9ph&lt;/a&gt; code repository now has a fully &lt;i&gt;&lt;a href="http://www.haskell.org/cabal/"&gt;cabalized&lt;/a&gt;&lt;/i&gt; module, and I'm waiting on a response to get permission to upload stuff to &lt;a href="http://hackage.haskell.org"&gt;Hackage&lt;/a&gt;.  This will be my first shared contribution to the Haskell community, though all I've done is create a simple test program and some of the administrative work around wrapping this code up.   If anyone likes this, the credit should go to &lt;a href="http://thenewsh.blogspot.com"&gt;Tim&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've got some ideas for enhancements, and ways to make a nice server/client API on top of this lovely encoding/decoding library that Tim created on top of the very excellent binary package for Haskell and the lovely Applicative module.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-5835085844902553309?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/5835085844902553309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/02/9ph-package-for-cabalhackage.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/5835085844902553309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/5835085844902553309'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/02/9ph-package-for-cabalhackage.html' title='9ph package for cabal/hackage'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-1814974988347556495</id><published>2010-02-08T22:37:00.000-08:00</published><updated>2010-02-08T22:44:31.631-08:00</updated><title type='text'>9ph works!</title><content type='html'>Finally, since last September, I've gotten around to messing with 9ph again.  That's the 9P2000 implementation in Haskell that Tim Newsham basically wrote and sent to me to play around with.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had started such a project on my own at one point, but Tim totally beat me to it, and rather than just re-implement the wheel, I figured I'd check out what he'd done and checked it in.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Today, I wrote a function that runs an IO program yielding a socket that's connected to a local 9P2000 server (or error'd out actually) running on 127.0.0.1:6872.  From there I was able to create messages for Tattach, Topen, and Tread, and could explore the errors and successes of the server I was talking to.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For my experiments I just used the Inferno operating system with&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new', serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;"styxlisten -A 'tcp!*!6872' export /"&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new', serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;This just exports the local / namespace that the process running the styxlisten command can see to the world on TCP protocols listening on port 6872.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial, serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial, serif;"&gt;This library should be enough to write scripts for what is quickly becoming my favorite X11 window manager (if you must use one) wmii.  wmii actually exposes a bit of functionality via a 9P server that you can mount from v9fs, Inferno, or any other 9P client.  It'd be nice to be able to write some Haskell to configure wmii I figured, so this might be my first use for this library.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial, serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial, serif;"&gt;I'm hoping to get back to this again before long.  This was good progress.  I'm going to check in on Tim and see if he's got any more updates he feels he'd like to push.  If not I'll just work from this fork.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial, serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial, serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-1814974988347556495?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/1814974988347556495/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/02/9ph-works.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/1814974988347556495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/1814974988347556495'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/02/9ph-works.html' title='9ph works!'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-2801652509365075996</id><published>2010-02-03T14:41:00.000-08:00</published><updated>2010-02-04T15:28:08.439-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>Iteratee</title><content type='html'>&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Iteratee really looks promising on paper, and people using it seem to think it's really great.  I've been put off a bit by what looks like a rather complex interface, but decided last night to take a crack at it.  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;What I've written below is an iteratee wrapper around "cat /etc/passwd" output using &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;runInteractiveCommand&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;module Main where&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;import Control.Monad.Trans&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;import Data.Iteratee.Base&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;import Data.Iteratee.Base.StreamChunk (ReadableChunk (..))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;import Data.Iteratee.IO.Handle&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;import System.Process&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;import System.IO&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;-- For some reason this signature is wrong, but I'm not sure why...&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;--handleDriver :: (MonadIO m, ReadableChunk s el) =&gt; IterateeG s el m a -&gt; Handle -&gt; m a&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;handleDriver iter h = do&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;  result &lt;- enumHandle h iter &gt;&gt;= run&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;  liftIO $ hClose h&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;  return result&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;main :: IO ()&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;main = do&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;  (_, outp, _, _) &lt;- runInteractiveCommand "/bin/cat /etc/passwd"&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;  handleDriver (stream2list :: IterateeG [] Char IO String) outp &gt;&gt;= putStrLn&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;handleDriver&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt; just runs &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;enumHandle&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt; with an iteratee (in my case &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;stream2list&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;) over the &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Handle&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;, in blocks (not character by character) that are specified by the implementation, returning the result.  That result is then printed to stdout by &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;putStrLn&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;This is a little bit like &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;interact&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt; for &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Handle&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt; in that I could have used something more advanced than &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;stream2list&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt; to process the result of "/bin/cat /etc/passwd".&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;I'm not too excited about the fact that I got the type signature on &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;handleDriver&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt; wrong, and I'm also a little bit put off by the type signature on &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;stream2list.&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;So what's the difference between this approach and an interact-like styled approach?  For one iteratees work like the function that's supplied to a fold operation over a collection of data.  In this case the collection is being produced dynamically via the enumerator.  The iteratees themselves work like little parsers that can be composed in a monadic sense.  Errors in IO and termination of a stream get propagated automatically up through the system nicely.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Why is lazy IO then not so great?  Look at the signature for interact:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;interact :: (String -&gt; String) -&gt; IO ()&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Interact&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt; is a function that takes a function of String to String and produces &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;IO&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;.  This means it, ostensibly consumes all the input on stdin, applies the provided function to convert the whole String to a String, then prints that string to stdout.  Now it doesn't have to read the whole of input in one shot, because of lazy evaluation.  Strings are [Char], and the list structure in Haskell is non-strict in its construction.  It's like pausing the construction of that list to do some processing on it, and going back to it with coroutines, except that the system is doing it behind the scenes.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;What happens in interact when an error occurs?  How does the pure function of type (String -&gt; String) even know about exceptions in the processing?  This is where iteratee is an improvement on traditionally lazy IO.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Let's assume we wanted to write a lazy version of interact for a handle called &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;hInteract&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;hInteract :: Handle -&gt; (String -&gt; String) -&gt; IO ()&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;I believe this function could be used safely as follows:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;withFile "/etc/passwd" ReadMode ((flip hInteract) id)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;withFile&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt; uses &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;bracket&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt; internally to ensure that &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;hClose&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt; is called on the handle and all seems well.  I don't think we necessarily understand how resources get used.   Oleg, the father of Iteratee, posts &lt;/span&gt;&lt;a href="http://www.haskell.org/pipermail/haskell-cafe/2008-September/047738.html"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;this message&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt; a few years back explaining more of the benefits of Iteratee.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;However, it seems that there is now a &lt;/span&gt;&lt;a href="http://groups.google.com/group/fa.haskell/browse_thread/thread/693fb86993089c6c/2e940a6765b9d5e9"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;new lazy IO mechanism available that is safe&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;.  I've not had any time to check into this, but I plan to in the next coming days.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Having written an Expect-like Monad, I'm interested in the aspects of error handling and precise resource control, because the code I'm writing really needs to be able to run to as close to forever as I can get.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-2801652509365075996?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/2801652509365075996/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/02/iteratee.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2801652509365075996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2801652509365075996'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/02/iteratee.html' title='Iteratee'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-6382850527990648664</id><published>2010-01-15T09:49:00.000-08:00</published><updated>2010-01-15T09:57:50.209-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>When types and definitions aren't enough.</title><content type='html'>Was in #haskell on freenode a bit this morning, and someone mentioned something about how they were not exactly excited about the new rules for code formatting on if-then-else expressions.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I mentioned that I try to avoid if-then-else and case as much as possible by using types like Maybe that have 2 kinds of constructors, namely Nothing  and "Just a" (for Maybe a).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I said that I can use the MonadPlus instance for Maybe a to get a lot of what is available in if-then-else clauses.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;let x = someExpression&lt;/div&gt;&lt;div&gt;in if x == Nothing&lt;/div&gt;&lt;div&gt;    then 9&lt;/div&gt;&lt;div&gt;    else fromJust x&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;could be written as&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;let x = someExpression&lt;/div&gt;&lt;div&gt;in fromJust $ x `mplus` Just 9&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;mplus is defined for Maybe as evaluating the first parameter, and if it is not Nothing, it returns it, otherwise it will return the second parameter.  It's essentially an "or" operator.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;However, someone pointed out that there's absolutely no requirement for mplus to be written this way.  It can still live up to all the rules and restrictions of MonadPlus by short-circuiting evaluation on the second argument instead of the first.  Sure, it's sort of a de-facto first then second sequencing of evaluation, but it is not as safe as say "if-then-else".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I wonder now about the Applicative module as well, and specifically Alternative for the Maybe class.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I could just as easily write&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;let x = someExpression&lt;/div&gt;&lt;div&gt;in fromJust $ x &lt;|&gt; Just 9&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But do we fall into the same trap of no guarantees?  Is there a rule in Applicative enforcing the short-circuit of the first argument before the second? &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Much code is written in the Applicative style for Parsec, so I really hope this is well defined.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-6382850527990648664?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/6382850527990648664/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/01/when-types-and-definitions-arent-enough.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/6382850527990648664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/6382850527990648664'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/01/when-types-and-definitions-arent-enough.html' title='When types and definitions aren&apos;t enough.'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-1786946039183894291</id><published>2010-01-11T07:08:00.000-08:00</published><updated>2010-01-11T07:30:49.497-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='documentation'/><category scheme='http://www.blogger.com/atom/ns#' term='community'/><category scheme='http://www.blogger.com/atom/ns#' term='optimization'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>What's Missing in the Haskell Community?</title><content type='html'>Documentation is often sighted as possibly the #1 item that needs to be improved with respect to Haskell.  It depends on what modules we use, but I have to agree.  It's quite difficult to uphold the claim that you don't need to understand Category Theory in order to employ a Monoid or Monad, but when you run into Monoid instances like "endo" and don't know what to make of it because the documents don't really describe how to use it, you're probably going to suffer in that that implementation of Monoid is likely useful for some kind of programming that you want to do, and you'll end up struggling with a solved problem.  Some people have been stepping up to improve the documentation, and that's really wonderful, but I think there's still some work to be done there.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The best way to learn Haskell in general for me has been to get the great books that are available out there.  &lt;a href="http://www.amazon.com/Real-World-Haskell-Bryan-OSullivan/dp/0596514980/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1263222722&amp;amp;sr=8-1"&gt;Real World Haskell&lt;/a&gt; is &lt;a href="http://book.realworldhaskell.org/read/"&gt;freely available online&lt;/a&gt;. (But please support the authors and get a copy if you're finding it useful).  Search for Haskell on Amazon.com and you'll find that the reviews are a really good guide to picking which ones might be right for you.  If you're really new to the language.  &lt;a href="http://www.amazon.com/Programming-Haskell-Graham-Hutton/dp/0521692695/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1263222902&amp;amp;sr=1-1"&gt;Dr. Graham Hutton's book&lt;/a&gt; is outstanding.   There's even been &lt;a href="http://channel9.msdn.com/shows/Going+Deep/C9-Lectures-Dr-Graham-Hutton-Functional-Programming-Fundamentals-Chapter-11-of-13/"&gt;a series on MSDN's channel 9&lt;/a&gt; walking through the chapters of this book, explaining how to solve some problems and think like a functional programmer. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To keep up to date with Haskell developments, &lt;a href="http://reddit.com/r/haskell"&gt;reddit&lt;/a&gt; has been invaluable.  You'll find blog posts, updates about new Haskell packages, and general community news and related discussion topics there.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So what's still missing?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I can tell you that over the years I've been messing around with Haskell, trying to understand how it works, why it's appropriate for certain kinds of problem solving, and to really get a good appreciation of why people seem to really like it so much, that I feel like the community has been pretty amazing with respect to fueling the flames of curiosity.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Where I think we might be needing a little more help is in the following areas of Haskell.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Explaining where laziness or non-strict evaluation is an advantage over strict evaluation. Perhaps this requires learning to think about the code we write differently, in much the same way it can be a leap to get to recursive programming, I feel this might be a slightly wider gap to cross mentally.  (But then again maybe I'm just getting old... )&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Show more examples of unintended data-growth or space leakage due to the lack of strict evaluation.  In languages like C, you're in direct control of when memory is allocated or deallocated.  This is generally considered a "bad thing" for a lot of tasks, including systems programming if you are signed up with the Go camp.   A side effect of non-strict by default seems to be that you have to understand how the code you're writing will be evaluated from a bit of a wider view than you might need to care about malloc and free, or new or delete.  It seems that unless you've somehow been taught how to recognize the patterns that could cause a a space leak, you're basically doomed to run into some sharp corners that others already seem to understand how to avoid.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Real World Haskell has a great chapter on optimization, but perhaps it's time for an "Optimizing Haskell" book too?  There's lots of good advice scattered all over the web, and the experts are not shy to offer you help should you ask.  Sometimes I think it's difficult to even ask the right questions when you're confused though, and I suspect this may turn some folks off to Haskell.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-1786946039183894291?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/1786946039183894291/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/01/whats-missing-in-haskell-community.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/1786946039183894291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/1786946039183894291'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/01/whats-missing-in-haskell-community.html' title='What&apos;s Missing in the Haskell Community?'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-3205528953500914438</id><published>2010-01-06T23:39:00.001-08:00</published><updated>2010-01-07T00:31:45.001-08:00</updated><title type='text'>L4 and Plan 9 or Inferno or both?</title><content type='html'>Some folks already started in on a Plan 9 port to L4 it seems &lt;a href="http://lsub.org/iwp9/cready/lp49_iwp9_camera_ready.pdf"&gt;(PDF)&lt;/a&gt;, but I'm not sure how far they've gotten with it.  I've been sort of peeping at L4 on and off for a long time now, and OKL4 has been successfully shipped in a few ARM phones, successfully being used to host Linux and a Qualcomm OS that drives the phone's radios and such.  Neat stuff.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Been wondering if Plan 9 or Inferno and L4 are really a good marriage and what benefits could be added by leveraging Plan 9's namespace based resource management and L4's powerful IPC mechanisms.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As I've had a little more spare time lately, I've been digging around looking into L4 again, and I'm interested in exploring some ideas a little more deeply.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's a few different implementations of L4 to look at...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;OKL4 is now basically an ARM only platform in it's latest releases.  Fiasco is a Pentium targeted L4 implementation that has a userland implementation that might be fun to work with &lt;a href="http://os.inf.tu-dresden.de/fiasco/ux/using.shtml"&gt;(Fiasco-UX&lt;/a&gt;), and Pistachio is still being worked by at least a few people, with the latest changes coming in as of yesterday.  Pistachio also supports a lot of architectures.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm tempted to play with each of these, but my problem has always been one of focus when it comes to these spare time projects as free time for me is usually at a premium.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://thenewsh.blogspot.com/"&gt;Tim Newsham&lt;/a&gt; has been following the seL4 stuff, and OKL4 is migrating towards those APIs.    His vote is I shoot for OKL4, so I believe that's where I'm going to start.  There's a good community around that implementation, and a commercial pressure to keep things working nicely.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But as they say, talk is cheap...  Let's see what I learn.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(UPDATE!)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Looks like a lot of &lt;a href="http://research.nii.ac.jp/H2O/LP49/LP49-e.html"&gt;progress&lt;/a&gt; was made by others who have already started this work!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-3205528953500914438?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/3205528953500914438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2010/01/l4-and-plan-9-or-inferno-or-both.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3205528953500914438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3205528953500914438'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2010/01/l4-and-plan-9-or-inferno-or-both.html' title='L4 and Plan 9 or Inferno or both?'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-7832139577256553731</id><published>2009-12-16T08:10:00.000-08:00</published><updated>2009-12-16T08:37:30.927-08:00</updated><title type='text'>Mouse editing... useful but not popular?</title><content type='html'>&lt;div&gt;This is just a bit of a rant, possibly about something people think is really trivial to talk about but I think there's something worth saying here.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;I've been noticing a lot of blogs and people using  tools claiming that never taking one's hands off the keyboard is a good thing.  This seems to be generally accepted as a rule of thumb to follow, but I don't buy it.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's window managers that abolish the mouse completely for X such as Xmonad and ratpoison.  They certainly have their merits and people are adopting them and finding that they get more work done than in alternative window managers.  All of that is fine, I'm not trying to take anything away from those people or those projects, I'd just like to challenge the premise that hardly ever using the mouse is always optimal.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A few examples to the contrary that I've found for myself:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Expose in Mac OS X allows me to quickly use my touchpad, or trackball/mouse to point at a location on my desktop and quickly see all my windows and nearly immediately point to the window I'm interested in.  To me this is a lot more useful than memorizing which of many desktops I might have decided to put certain windows on, or tabbing through to cycle to the correct window, or possibly remembering what shortcut key goes to a particular window on the current desktop.  Point and click is easy.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Still I've peers who don't like Expose and do everything they can to turn it off.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When editing text, GUI versions of Emacs allow me to sweep over text and use that as a copy command to move text around during editing sessions.  This is not as powerful as the Acme editor from Plan 9, in that I can chord buttons on my trackball to cut and paste text to different locations without taking my hand off the mouse.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I will admit I'm a bit of an emacs junkie, for better or worse, and like my elisp based customizations I've become used to over the years do save me a bit of time for certain tasks.  Those are nearly always keyboard accessible shortcuts, but again, this becomes a memorization process of those commands.  That memorization and customization is initially a distraction from getting work done, but it does become habit after a short time, and then it feels very fluid.  I still often find myself switching between Acme, Sam, and emacs depending on the sort of editing I'm doing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I don't see how selecting text with arrow keys or control key combinations is ever faster than a mouse sweep and click.  In fact while editing this blog I find myself taking my hands off the keyboard, pointing at a word or phrase to double click and change a word very quickly, much faster than if I had to press repetitions of keys and delete buttons to change text.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'll also go ahead and admit that before I'd used Acme, and I mean really used it for a little while, I was in the camp of people who would have said that never removing the hands from the keyboard was faster without even questioning why that is.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My advice to people is to try some of these other editors, and see if you can understand where I'm coming from.  The people who designed the editors that are mouse driven have written large amounts of code in their day, and they've certainly gained a lot of experience in knowing what annoys them during an editing session and wanted to make changes to make the process more comfortable for themselves.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Worst case scenario is you'll still think that keyboard-only is the way to go and you'll not really have lost anything but maybe have re-assured yourself that for your work environment, that's the best way for you to go.  Maybe you'll learn a new way to work that you find is faster.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Also, there's a lot more reasons to really like Sam or Acme, but that's for another time.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-7832139577256553731?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/7832139577256553731/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/12/mouse-editing-useful-but-not-popular.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/7832139577256553731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/7832139577256553731'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/12/mouse-editing-useful-but-not-popular.html' title='Mouse editing... useful but not popular?'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-2527254684658193486</id><published>2009-12-14T06:37:00.000-08:00</published><updated>2009-12-15T12:59:47.096-08:00</updated><title type='text'>Unemployed</title><content type='html'>Well the company I work for is in the process of restructuring, and most everyone has been laid off.  Verari Systems was a fun place to work, and I got to do a few of the things that I've nearly documented here (except for anything they'd consider Intellectual Property).  It's been a fun ride, and there's rumors floating around about people wanting to re-invigorate our technology into a new company.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm hoping I can play a part in that new company if it happens, but I'm not currently willing to wager on that.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Started interviewing at one company, and I've been working a contract that'll get me through the holiday season, but I'm currently on the market if there's anyone interested! &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'll post updates to my employment status here as things develop.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'd also like to say that the outpour of support I've gotten from friends has been amazing, and that I'm so glad to have people like them in my life.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-2527254684658193486?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/2527254684658193486/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/12/unemployed.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2527254684658193486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2527254684658193486'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/12/unemployed.html' title='Unemployed'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-4562524173697080472</id><published>2009-11-28T21:14:00.000-08:00</published><updated>2009-11-28T21:19:48.710-08:00</updated><title type='text'>Lazy Programming, too much, too little?</title><content type='html'>Another Haskeller/Blogger wrote the following&lt;a href="http://pchiusano.blogspot.com/2009/05/optional-laziness-doesnt-quite-cut-it.html"&gt; interesting article&lt;/a&gt; on how optional laziness doesn't always work out so well.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;However I'm finding there's a lot of functions that don't make a ton of sense to my imperative, strictly trained programmer's mind to do in a lazy way by default.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;foldl is a good example.  Without strictness checking turned on in the compiler options for GHC, it can turn into a memory leak right away.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I find myself kind of hard pressed to come up with a good use for a lazy foldl where it isn't obvious that I'd rather have used foldl'.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-4562524173697080472?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/4562524173697080472/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/11/lazy-programming-too-much-too-little.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4562524173697080472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4562524173697080472'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/11/lazy-programming-too-much-too-little.html' title='Lazy Programming, too much, too little?'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-845026369558754882</id><published>2009-11-11T06:14:00.001-08:00</published><updated>2009-11-11T07:38:40.431-08:00</updated><title type='text'>Long running Haskell applications</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="color:#0000EE;"&gt;&lt;span class="Apple-style-span" style="text-decoration: underline;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_RkKpoITzx50/SvrY8Vkw61I/AAAAAAAAAA4/Us2Vo_jkmXM/s1600-h/before.png"&gt;&lt;/a&gt;I've been using Haskell in a serious way for about 2 years.  Been using it in a professional sense about 1.5 years now in that, yes, I am one of the lucky ones that gets to use Haskell at work.&lt;br /&gt;&lt;br /&gt;The ride has been pretty smooth most of the time, as I've found that the type system especially helps me to rule out certain classes of bugs, easily test rather large chunks of programs as they're pure.  The interpreter allows experimentation and iteration of ideas that can then be composed into the final compiled programs.  All of this gives me a good deal of confidence that the code I'm writing is correct to some degree up front, something I've come to expect from functional programming languages over the years and greatly appreciate.&lt;br /&gt;&lt;br /&gt;However I've felt compelled to comment that things aren't always so smooth either.  I spent the better part of a weekend and a Monday tracking down a space leak in a program that just was not allowed to leak space.  I have a stack of a ReaderT StateT IO that I use to communicate with a device through a passthrough program that speaks CAN to a device for the purposes of creating a serial console connection where there is only a CAN bus.  The Haskell program is responsible for the management of the data found at the other end o the serial connection and supports operations to the device through the serial channel via a simple text protocol while "forever" polling data on the serial endpoint.&lt;br /&gt;&lt;br /&gt;What I had done was the equivalent of&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;pollerLoop :: Poller ()&lt;br /&gt;pollerLoop = forever pollOnce&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Where Poller is my monad stack.&lt;br /&gt;pollOnce is  defined as,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;pollOnce :: Poller ()&lt;br /&gt;pollOnce  = do&lt;br /&gt;checkCommandChannel -- see if there's a pending command to run&lt;br /&gt;executePoll&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Yes, this application is multi-threaded.  I have a logger thread, a thread watching standard input of the program for queries and issuing commands to the endpoint.  I have a thread per Poller, and the ability to poll devices simultaneously.&lt;br /&gt;&lt;br /&gt;The poller includes an implementation of my little "expect" syntax which was based on a naive implementation of hGetChar and checking for a desired result or timing out eventually.  The really data inefficient version is a real screamer, beating the heck out of my Parsec or even ReadP version, but because of the way I wrote it, with a lot of reversing and prefix checking and substring slicing into temporary areas, it's not useful for large input blocks over a long time frame.&lt;br /&gt;&lt;br /&gt;Still it's so fast that it's appropriate for certain sections of code.  I measured and verified this via space profiling to see the real runtime heap utilization (nice feature btw, I'd be dead without it right now I think).&lt;br /&gt;&lt;br /&gt;So what's the problem you're probably thinking?  Well it turns out that since part of my state in StateT is a Data.Map, and that all my polling and parsing of expect-passing blocks caused updates to a Map, coupled with the language's default laziness caused a bit of a "bomb" of PAP (Partial APplications of functions).&lt;br /&gt;&lt;br /&gt;I had an ill-timed, project wise, discovery of a space leak.&lt;br /&gt;&lt;br /&gt;I tried sprinkling $! and seq all over the place, rewriting big chunks of code that used Text.Regex.Posix, to use Parsec and only got incremental improvements.  The growth problem still existed, and would eventually exhaust memory.  This was a real problem as this was an application that was not supposed to stop when the other conditions of the management system were ok.  It could run for months or even years!&lt;br /&gt;&lt;br /&gt;I went through a whirlwind of emotions, and considered that perhaps I should be working a different job.  Perhaps I could be a lion tamer?  It turned out what I thought was a lion was really an anteater though... but that's literally a different story.&lt;br /&gt;&lt;br /&gt;It turns out that by looping not inside the monad, but over the execStateT/runReaderT expression I could pull all the state out, and then re-inject it into another execStateT/runReaderT each poll, which forced the strictness I needed on all state data, made the system respond faster, and best of all, not crash!!!!&lt;br /&gt;&lt;br /&gt;Diagrams below:&lt;br /&gt;&lt;br /&gt;This first one is the "before" picture.  It shows the data growth by cost center in my code.  As you can see things are getting worse almost linearly as I poll.&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="color:#0000EE;"&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span"  style="color:#000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "&gt;&lt;img src="http://2.bp.blogspot.com/_RkKpoITzx50/SvrY8Vkw61I/AAAAAAAAAA4/Us2Vo_jkmXM/s320/before.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5402869234079427410" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 222px; " /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This picture illustrates the result of pulling the state out of the Monad, and re-injecting it, forcing it to be evaluated.  As you can see, I've got much more manageable memory utilization.&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_RkKpoITzx50/SvrY8_MOzxI/AAAAAAAAABA/LsFPgULMK1k/s1600-h/goodrun.png"&gt;&lt;img src="http://2.bp.blogspot.com/_RkKpoITzx50/SvrY8_MOzxI/AAAAAAAAABA/LsFPgULMK1k/s320/goodrun.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5402869245250817810" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 214px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This final one shows the new algorithm running with 2 threads, one spawned a few seconds into the run.  You can see the initial burst of the fast but inefficient "expect" algorithm, followed by a much more regular memory utilization pattern.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_RkKpoITzx50/SvrY9LYjHqI/AAAAAAAAABI/ZnnQNF80-3I/s1600-h/2threads.png"&gt;&lt;img src="http://4.bp.blogspot.com/_RkKpoITzx50/SvrY9LYjHqI/AAAAAAAAABI/ZnnQNF80-3I/s320/2threads.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5402869248523706018" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 214px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'd like to thank all the folks on #haskell on FreeNode who gave me suggestions and hints to my vague problems regarding data growth and laziness vs strictness.  Haskell's got a great user community and is probably one of the most helpful out there.  One can learn a lot just asking questions of the right mentors as well as by reading haskell-cafe and the various blogs that are out there.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm hoping that this anecdote is useful to someone.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-845026369558754882?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/845026369558754882/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/11/long-running-haskell-applications.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/845026369558754882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/845026369558754882'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/11/long-running-haskell-applications.html' title='Long running Haskell applications'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_RkKpoITzx50/SvrY8Vkw61I/AAAAAAAAAA4/Us2Vo_jkmXM/s72-c/before.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-2751462886220712532</id><published>2009-10-22T20:54:00.000-07:00</published><updated>2009-10-22T21:07:41.212-07:00</updated><title type='text'>OOP maybe should have been called Oops</title><content type='html'>http://www.informit.com/articles/article.aspx?p=1327762 &lt;br /&gt;&lt;br /&gt;"Designing object-oriented software is hard—designing reusable object-oriented software is even harder. Experienced object-oriented designers will tell you that a reusable and flexible design is difficult, if not impossible, to get "right" the first time, and that multiple attempts at reuse with subsequent redesigns are normal."&lt;br /&gt;&lt;br /&gt;Now there's a statement about Object Oriented Design I can agree with :-)&lt;br /&gt;&lt;br /&gt;Yes I realize that Design Patterns tried to give a set of reusable designs to certain problem cases or environments, and that's all great and what not, but I think software design has to perhaps abstract these ideas even further into "modules of services".&lt;br /&gt;&lt;br /&gt;It won't matter so much if you used a methodology like OOP or Functional Programming, or any old imperative approach, as long as the pieces are small and purposeful, and the code is written in a clear enough way, it should be fairly straightforward to adapt it to new situations.&lt;br /&gt;&lt;br /&gt;That said...&lt;br /&gt;&lt;br /&gt;I've been successful in having written a service in haskell that doesn't really use much in the way of any object oriented design.  in fact, it's mainly done with monads, and an EDSL that looks a lot like "Expect".  I've been able to tweak this EDSL to write the solution to the problem I'm solving in the language *I* want.&lt;br /&gt;&lt;br /&gt;Due to the way the program is designed to work with an external program for getting communication done, it's isolated from the mechanisms of communication, and only implements the logic around parsing data and issuing commands.&lt;br /&gt;&lt;br /&gt;This has proven to be very powerful in testing systems via various interconnects.  I've used a bizarre combination of socat, hooked up to serial ports, that are looped back through to another program that uses a proprietary embedded serial streaming protocol back up into the Haskell code with exactly the same ease as launching an ssh client session or using socat straight across a serial line.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-2751462886220712532?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/2751462886220712532/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/10/oop-maybe-should-have-been-called-oops.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2751462886220712532'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2751462886220712532'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/10/oop-maybe-should-have-been-called-oops.html' title='OOP maybe should have been called Oops'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-2860517677503409558</id><published>2009-10-15T08:11:00.000-07:00</published><updated>2009-10-15T08:13:16.885-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='9p haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='9ph 9p Tim Newsham'/><title type='text'>Tim Newsham strikes again!</title><content type='html'>Another, more cleaned up version of 9P in Haskell is &lt;A HREF="http://www.thenewsh.com/~newsham/x/machine/hask9p/"&gt;here&lt;/A&gt;.&lt;br /&gt;&lt;br /&gt;Nice!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-2860517677503409558?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/2860517677503409558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/10/tim-newsham-strikes-again.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2860517677503409558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2860517677503409558'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/10/tim-newsham-strikes-again.html' title='Tim Newsham strikes again!'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-2106051097268359922</id><published>2009-10-14T19:58:00.000-07:00</published><updated>2009-10-14T20:02:34.448-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='9ph 9p Tim Newsham google code'/><title type='text'>I don't really know what to say..</title><content type='html'>...except that Tim Newsham is the man.&lt;br /&gt;&lt;br /&gt;Out of the blue one day he totally writes up a very nice 9P implementation in Haskell that I started to look at, then ran out of time before I had to start working on other things.  A few days ago I thought I'd get back to it, and it doesn't work out.  &lt;br /&gt;&lt;br /&gt;So a couple days ago he sends me *another* implementation of 9P in Haskell, but instead of just tackling straight 9P, he goes and does 9P.u too (Unix extensions involving fields for the stat message and such).  But not only that, he adds an example client program that works with a 9p service running on the Google Android platform, reading sensor data from the phone.&lt;br /&gt;&lt;br /&gt;Now that's cool...  I need to try it against some of my Inferno service stuff.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-2106051097268359922?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/2106051097268359922/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/10/i-dont-really-know-what-to-say.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2106051097268359922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2106051097268359922'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/10/i-dont-really-know-what-to-say.html' title='I don&apos;t really know what to say..'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-1852895724329325447</id><published>2009-10-06T18:08:00.000-07:00</published><updated>2009-10-06T19:31:40.764-07:00</updated><title type='text'>More Y</title><content type='html'>Y is trivial to write in Haskell.  The wikipedia entry on &lt;a href="http://en.wikipedia.org/wiki/Fixed_point_combinator#Y_combinator"&gt;fixed point combinators&lt;/a&gt; shows that via some reduction operations you end up with a simple definition of: &lt;B&gt;&lt;I&gt;Y g = g (Y g)&lt;/B&gt;&lt;/I&gt;&lt;br /&gt;&lt;br /&gt;To write this in Haskell is really straightforward:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;let y g = g (y g)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Yes.  Just that easy.&lt;br /&gt;&lt;br /&gt;The type of the function y is now:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;y :: (t -&gt; t) -&gt; t&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That is to say y is a function, that takes a function that takes a type "t" and returns a type "t" and returns a type "t".&lt;br /&gt;&lt;br /&gt;This form of type is consistent with being a fixed point calculator for functions. (see the top of that wikipedia article linked earlier for an explanation of a fixed point of a function).&lt;br /&gt;&lt;br /&gt;Can this be used to compute a fibonacci function from a fibonacci step?  You bet!&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;let fs = (\n -&gt; (\x -&gt; if x =&lt; 1 then 1 else (n (x -1)) + (n (x - 2))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now just like before, in scheme, we can use this to try to manually unroll recursion via the "n" argument which is a function to be run next.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;((fs (fs (fs (fs (fs undefined))))) 5)&lt;br /&gt;8&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So let's run it with Y&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;((y fs) 5)&lt;br /&gt;8&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;or something larger&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;((y fs) 10)&lt;br /&gt;89&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Strictly speaking, writing trace in a pure functional language is not allowed, unless you break the rules.  Debug.Trace.trace lets you do this, and since I'm tracing anyway...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;let tracestep label = (\f -&gt; (\g -&gt; (\n -&gt; let res = (f g) n in (Debug.Trace.trace (label ++ " " ++ (show res)) res))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Can I still compose this with "y"?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;((y (tracestep "fib" fs)) 5)&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 5&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 8&lt;br /&gt;8&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Yes!&lt;br /&gt;&lt;br /&gt;I was going to write about memoizing this as in the Scheme example, but I'm quite tired, and my wife and I watch So You Think You Can Dance, so that's what I'm going to do instead.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-1852895724329325447?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/1852895724329325447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/10/more-y.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/1852895724329325447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/1852895724329325447'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/10/more-y.html' title='More Y'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-5333191091931580107</id><published>2009-10-05T14:27:00.001-07:00</published><updated>2009-10-05T18:28:39.650-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='practical'/><category scheme='http://www.blogger.com/atom/ns#' term='Scheme'/><category scheme='http://www.blogger.com/atom/ns#' term='Y combinator'/><title type='text'>Some Scheme and Y</title><content type='html'>Y combinators are pretty cool.  They allow for the definition of recursive code without needing support for self-reference directly.&lt;br /&gt;&lt;br /&gt;You can find some good links about it &lt;a href="http://blog.jcoglan.com/2008/01/10/deriving-the-y-combinator/"&gt;here(javascript)&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Fixed_point_combinator"&gt;here (wikipedia)&lt;/a&gt;, and there's a ton of results for it if you search with google.&lt;br /&gt;&lt;br /&gt;In a nutshell it's a fixed point combinator that can generate a recursive function from a function that is not defined recursively.&lt;br /&gt;&lt;br /&gt;Take the following tried and true example of recursion, the factorial!&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;(define factorial&lt;br /&gt;    (lambda (x) &lt;br /&gt;        (cond ((= x 0) 1)&lt;br /&gt;                   (else (* x (factorial (- x 1)))))))&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;factorial is a function defined in terms of itself (references factorial).&lt;br /&gt;&lt;br /&gt;What if this wasn't allowed in your language though?  How could you write this?&lt;br /&gt;&lt;br /&gt;Well if you had the Y combinator you could write a step of the factorial calculation and add an argument which would be the next operation to run after this step is complete.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define factstep&lt;br /&gt;  (lambda (next)&lt;br /&gt;    (lambda (n)&lt;br /&gt;      (if (= n 0) 1 (* n (next (- n 1)))))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now if you want to use factstep to compute factorials you must first pass in the "next" operation, which yields another function which takes the parameter to the factorial.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;; factorial 1&lt;br /&gt;((factstep 'blah) 1)&lt;br /&gt;&lt;br /&gt;; factorial 3&lt;br /&gt;((factstep (factstep (factstep (factstep 0)))) 3)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see this gets really tedious without recursion.&lt;br /&gt;&lt;br /&gt;Enter the Y combinator:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define Y&lt;br /&gt;  (lambda (le)&lt;br /&gt;    ((lambda (f) (f f))&lt;br /&gt;     (lambda (f)&lt;br /&gt;       (le (lambda (x) ((f f) x)))))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Looks like complete nonsense if you don't know how it is derived.  There's many different websites that go into that, so I'm not going to.  I'm looking for a practical use of this thing.&lt;br /&gt;&lt;br /&gt;Well it turns out by applying Y to the function "factstep" you can create the factorial function you're after.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define factorial (Y factstep))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now (factorial 6) still yields 720.   (Yes Y seems quite magical at this point if you don't understand it, so I suggest reading up on that if it is confusing to you)&lt;br /&gt;&lt;br /&gt;So what good is this if we can just define functions recursively to begin with?  &lt;br /&gt;&lt;br /&gt;Well what if we want to weave in some other behaviors?&lt;br /&gt;&lt;br /&gt;Let's look at a more interesting primitive recursive function like fibonacci.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define fibstep&lt;br /&gt;  (lambda (next)&lt;br /&gt;    (lambda (n)&lt;br /&gt;      (cond &lt;br /&gt;        ((&lt;= n 1) 1)&lt;br /&gt;        (else (+ (next (- n 1)) (next (- n 2))))))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is known to be horribly inefficient as it redoes a lot of the same work?  Want to watch how inefficient it is?  Ok, let's add a trace step.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define tracestep&lt;br /&gt;  (lambda (label f)&lt;br /&gt;    (lambda (g)&lt;br /&gt;      (lambda (n)&lt;br /&gt;        (let ((res ((f g ) n)))&lt;br /&gt;          (display label) (display " ") (display res) (newline)&lt;br /&gt;          res)))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This simply passes through the previous steps, stores an intermediate value, and prints it using a label that's passed in.  Here's how to use it.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define traced-fib (Y (tracestep "fib" fibstep)))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now if we run it for say "traced-fib 6"&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; (traced-fib 6)&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 5&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 8&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 5&lt;br /&gt;fib 13&lt;br /&gt;13&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Look at all of those steps!!!  Clearly this sucks, and if you try something like (traced-fib 100) you'll be waiting for a long time for completion.  It expands it's "recursion" via Y like a bomb!&lt;br /&gt;&lt;br /&gt;How can we improve on this?  Well without modifying fibstep, we could add memoization, so first I'll make a global memoization table (forgive the possibly poor choice of data structures here)&lt;br /&gt;&lt;br /&gt;Memoization is a technique to prevent computing the same value twice, which we're doing a lot above per the trace.  (Again this has been explained on the web a lot.  Googling around for why may prove enlightening)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define memoization-table (make-vector 100 0))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is a vector of 100 0s. I'm only going to memoize 100 values of this computation statically.&lt;br /&gt;&lt;br /&gt;So now I'll write the memoization step.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define memoize&lt;br /&gt;  (lambda (f)&lt;br /&gt;    (lambda (g)&lt;br /&gt;      (lambda (n)&lt;br /&gt;        (let ((ref (vector-ref memoization-table n)))&lt;br /&gt;          (if &lt;br /&gt;           (= 0 ref)&lt;br /&gt;           (let ((val ((f g) n)))&lt;br /&gt;             (vector-set! memoization-table n val)&lt;br /&gt;             val)&lt;br /&gt;           ref))))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The indexes of the memoization table are the results of f(i), where i is the ith fibonacci number.  f(1) = 1, f(2) = 1, f(3) = 2, f(4) = 3... etc&lt;br /&gt;&lt;br /&gt;Basically once we compute a value for i, we insert it in the table, so we can look it up again.  if f(i) is 0, it means we have to compute it yet, but we'll only do it one time.&lt;br /&gt;&lt;br /&gt;So how do I stack all of this up with Y?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define traced-memo-fib (Y (memoize (tracestep "fib" fibstep))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;or if you don't want tracing&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define memo-fib (Y (memoize fibstep)))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Let's watch it run for 6 now&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; (traced-memo-fib 6)&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 3&lt;br /&gt;fib 5&lt;br /&gt;fib 8&lt;br /&gt;fib 13&lt;br /&gt;13&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;How about something bigger?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; (traced-memo-fib 8)&lt;br /&gt;fib 21&lt;br /&gt;fib 34&lt;br /&gt;34&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It didn't have to compute up to 13, so it just did fib(7) and fib(8).  If we reset the memoization table (reload the program) we can see all the steps again.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; (traced-memo-fib 8)&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 3&lt;br /&gt;fib 5&lt;br /&gt;fib 8&lt;br /&gt;fib 13&lt;br /&gt;fib 21&lt;br /&gt;fib 34&lt;br /&gt;34&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Compare this to the unmemoized fibonacci:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; (traced-fib 8)&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 5&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 8&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 5&lt;br /&gt;fib 13&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 5&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 8&lt;br /&gt;fib 21&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 5&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 8&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 1&lt;br /&gt;fib 3&lt;br /&gt;fib 1&lt;br /&gt;fib 1&lt;br /&gt;fib 2&lt;br /&gt;fib 5&lt;br /&gt;fib 13&lt;br /&gt;fib 34&lt;br /&gt;34&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Yikes!  That's a lot of waste there.&lt;br /&gt;&lt;br /&gt;What I've been able to do with Y is write steps of a computation in near isolation of each other, and then compose them with Y to form a useful function (arguably... it's just fibonacci) to optimize and augment behaviors by weaving them together.&lt;br /&gt;&lt;br /&gt;Now I'm not sure what this means for Y in terms of practicality, but it's kind of neat.  Obviously one has to obey certain rules to use Y compositionally, but it's totally possible for some classes of problems.  I'm not sure how my coworkers would react to my using this in any sort of production code.  Could anyone read it?  :-)&lt;br /&gt;&lt;br /&gt;Ah well, that's why this blog is just stuff that interests me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-5333191091931580107?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/5333191091931580107/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/10/some-scheme-and-y.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/5333191091931580107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/5333191091931580107'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/10/some-scheme-and-y.html' title='Some Scheme and Y'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-4423598560565342047</id><published>2009-10-04T10:51:00.001-07:00</published><updated>2009-12-16T08:46:33.260-08:00</updated><title type='text'>A few random thoughts</title><content type='html'>In conversations with people, it occurs to me that the concept of Functional Programming really scares some folks off.  I feel this is the effect of the object oriented paradigm having been shown to be the almighty hammer and the whole world to be a nail.  Shame on us.&lt;br /&gt;&lt;br /&gt;It's interesting to note that people often know more functional programming than they may even know.  Take the C++ STL for example.  It's all in generic algorithms that apply an outer-most layer of an algorithm, requiring the coder to specify the smaller steps that make the outer-most algorithm mean anything useful at all.  In C even, we have qsort and mergesort as standard calls.  These are a great start to addressing the "who needs Functional Programming?" question.&lt;br /&gt;&lt;br /&gt;The Standard C Library's qsort is a well documented and useful sort function with some very interesting properties, or no one would even care about putting it into a library.  Implementing it correctly the first time, from memory is not likely to happen, so to save us time the library has implemented all of the tricky outer-logic for us, requiring us only to provide a pointer to a function that implements the comparison function that will be used to determine if one item in the collection being sorted is less than, greater than, or equal to another item.&lt;br /&gt;&lt;br /&gt;I do not think anyone can argue that this is not a very powerful concept.  With this, one can create an arbitrarily complex data type, and as long as one can specify the comparison criteria, one can "implement" qsort, without doing the heavy lifting.  Isn't that what OOP was supposed to provide?  Is this not the same re-use goal we all want in libraries to begin with?&lt;br /&gt;&lt;br /&gt;Note that this means one can also "lie" to qsort about what value should come before the next, and by simply making the compare function return the swapped values for a less than comparison for the value returned for greater than, one can reverse sort a collection (descending order vs ascending order), again without writing all the outer-most, and more complex qsort code.&lt;br /&gt;&lt;br /&gt;How great is that?&lt;br /&gt;&lt;br /&gt;STL and C++ standard libraries let one define the "allocation" step for geting more memory as a separate "policy" from the rest of the code.  I've written my own C++ compliant allocators that allow for getting memory from "mmap" instead of malloc, and then run benchmark tests against each just for fun.  The algorithms for the collections are the same code, and the only difference is dropping in a template parameter for the allocation class.  This, even though it's C++, is not solely the domain of OOP languages.  In fact, Functional Programming is meant for this kind of flexibility.&lt;br /&gt;&lt;br /&gt;Is there any wonder now why people claim that Functional Programming is about managing complexity by thinking about operations rather than the data?&lt;br /&gt;&lt;br /&gt;I've written a good bit of Erlang code over the last 2 years, and there's no mutable variables (sort of) in that language, so in order to do a replace of a value in a list, I have to basically emit an entirely new list with the value in question updated.   Well I could have written all the code to do that myself using primitive recursion, and subtraction until a value for an index reaches 0 or 1 and then changing the value in question, and appending the rest of the list to it, but with functions like "foldl" and "foldr" that's not necessary.  I can just write the "guts" of the algorithm, and let the collection traversal of the list be handled by a well-defined, and reusable function.  Sure for lists this may seem a trivial operation, but consider that one could use a fold function over a tree in a few different traversal orders, and I think one can begin to see the power of this approach.&lt;br /&gt;&lt;br /&gt;If all of that evidence doesn't turn one on to at least appreciating Functional Programming, perhaps just looking at the sheer growth in popularity of well respected software institutions, and the application of Functional Programming to mission critical software could convince one to give it a second look.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-4423598560565342047?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/4423598560565342047/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/10/few-random-thoughts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4423598560565342047'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4423598560565342047'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/10/few-random-thoughts.html' title='A few random thoughts'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-1720452298834180395</id><published>2009-09-14T21:36:00.000-07:00</published><updated>2009-09-14T21:41:18.592-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='9ph Haskell 9p Tim Newsham google code'/><title type='text'>Get by with a little help from my friends...</title><content type='html'>I've had two random people express an interest in the 9P in Haskell stuff I've been thinking about, for similar reasons.  Tim Newsham went as far as to write a bunch of code for encoding/decoding of 9P messages to ByteStrings and mailed it to me.&lt;br /&gt;&lt;br /&gt;I'm not 100% sure it's 100% correct, but it looks darned good, and far cleaner than what I'd written, so I've used it in place of mine at the &lt;a href="http://code.google.com/p/9ph"&gt;9ph project page&lt;/a&gt;.  &lt;br /&gt;&lt;br /&gt;I've attempted to port my version test code (sends a 9p version message to a styx server on Inferno) to see if that works, but I'm not sure that the string type is being handled properly for the TVersion message, where it must be prefixed by a little endian encoded 16 bit integer for the protocol version being negotiated ("9P2000" in our case).&lt;br /&gt;&lt;br /&gt;Still 9P in Haskell looks like it will be useful for several folks, and I'm glad for that, even if I don't get mine done.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-1720452298834180395?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/1720452298834180395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/09/get-by-with-little-help-from-my-friends.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/1720452298834180395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/1720452298834180395'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/09/get-by-with-little-help-from-my-friends.html' title='Get by with a little help from my friends...'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-4949471244150857475</id><published>2009-09-10T23:31:00.001-07:00</published><updated>2009-09-10T23:55:04.708-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='libdispatch GCD prime sieve concurrency Snow Leopard'/><title type='text'>Prime Sieves again</title><content type='html'>Well I've been playing with libdispatch quite a bit lately now.  Apple just open sourced it &lt;a href="http://libdispatch.macosforge.org"&gt;here&lt;/a&gt;, and I hope linux/BSD folks figure out how to adopt it, because it's really cool!&lt;br /&gt;&lt;br /&gt;I took my pipe based CSP-like prime sieve, and at the prodding of my friend Kevin at Apple, rewrote it so that the blocks themselves contain the "message" and the queues contain the context I'm interested in.  This is in contrast to the pipe fd's being an event source to fire a block, and the fd itself having the context once it was an event source object.&lt;br /&gt;&lt;br /&gt;This meant re-structuring the code a bit, and capturing the value I would have written to the pipe in the block's closure.  To do so I opted to make a function as such&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// Runs a block asynchronously on a queue&lt;br /&gt;void run_block (dispatch_queue_t q, int cur_num) {&lt;br /&gt;  dispatch_async(q, &lt;br /&gt;   ^{&lt;br /&gt;     struct context * ctx = (struct context *) dispatch_get_context(q);&lt;br /&gt;     &lt;br /&gt;     if (cur_num == LAST) {&lt;br /&gt;       if (ctx-&gt;has_spawned == 1) {&lt;br /&gt;         run_block(ctx-&gt;neighbor, cur_num);&lt;br /&gt;       }&lt;br /&gt;       dispatch_release(q);&lt;br /&gt;     } &lt;br /&gt;     else if (cur_num == ctx-&gt;mynum) {&lt;br /&gt;         printf("%d\n", cur_num);&lt;br /&gt;     }&lt;br /&gt;     else if (cur_num % ctx-&gt;mynum != 0) {&lt;br /&gt;       if (ctx-&gt;has_spawned == 0) {&lt;br /&gt;         ctx-&gt;neighbor = create_queue(cur_num);&lt;br /&gt;         ctx-&gt;has_spawned = 1;&lt;br /&gt;       }&lt;br /&gt;       run_block(ctx-&gt;neighbor, cur_num);&lt;br /&gt;     }&lt;br /&gt;    &lt;br /&gt;   });&lt;br /&gt;}    &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://paste.lisp.org/display/86549#5"&gt;(Full source here)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I had someone tell me #define'ng MAX was bad, and I wanted it to be a command line argument anyway, so I made it so. &lt;a href="http://paste.lisp.org/display/86549#6"&gt;(here)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now this version runs pretty nicely, but all that block copying overhead is causing a lot of malloc'ng memory for const copies of contexts.  Seems a waste.  My friend Kevin pointed this out to me and said "try the async_f APIs".  &lt;br /&gt;&lt;br /&gt;These take a function pointer rather than a block.  It's easy enough to convert this block to the function pointer form:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;void worker (void * fctx) {&lt;br /&gt;  int cur_num = (int) fctx;  // bad bad bad, but I don't care.&lt;br /&gt;  dispatch_queue_t cur_q = dispatch_get_current_queue();&lt;br /&gt;  struct context * qctx = (struct context *) dispatch_get_context(cur_q);&lt;br /&gt;  &lt;br /&gt;  if (cur_num == LAST) {&lt;br /&gt;    if (qctx-&gt;has_spawned == 1) {&lt;br /&gt;      dispatch_async_f(qctx-&gt;neighbor, (void *)cur_num, worker);&lt;br /&gt;    }&lt;br /&gt;    dispatch_release(cur_q);&lt;br /&gt;  } &lt;br /&gt;  else if (cur_num == qctx-&gt;mynum) {&lt;br /&gt;    printf("%d\n", cur_num);&lt;br /&gt;  }&lt;br /&gt;  else if (cur_num % qctx-&gt;mynum != 0) {&lt;br /&gt;    if (qctx-&gt;has_spawned == 0) {&lt;br /&gt;      qctx-&gt;neighbor = create_queue(cur_num);&lt;br /&gt;      qctx-&gt;has_spawned = 1;&lt;br /&gt;    }&lt;br /&gt;    dispatch_async_f(qctx-&gt;neighbor, (void *)cur_num, worker);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now when I run my for loop it looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;for (x = 2; x &lt;= max; ++x) {&lt;br /&gt;    dispatch_async_f(two_q, (void *)x, worker);&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What is very interesting to look at is the pipe version's performance, vs the block copy, vs the function pointer version.&lt;br /&gt;&lt;br /&gt;Sieving all the primes from 2 to 9000 with the file descriptor version:&lt;br /&gt;1.68s user 5.05s system 171% cpu 3.929 total&lt;br /&gt;&lt;br /&gt;With block copy:&lt;br /&gt;0.24s user 0.02s system 118% cpu 0.219 total&lt;br /&gt;&lt;br /&gt;With function pointers:&lt;br /&gt;0.06s user 0.02s system 78% cpu 0.098 total&lt;br /&gt;&lt;br /&gt;It's hard to do a lot of sieving with the file descriptor version, because you have up your ulimit, and it hits the kernel a lot (see the system time of 5.05s, vs 1.68 user time!).  To demonstrate how much faster the function pointer version is compared to the block version, we need a larger range.&lt;br /&gt;&lt;br /&gt;Here's results for 2-90000&lt;br /&gt;&lt;br /&gt;With block copy:&lt;br /&gt;14.52s user 0.21s system 161% cpu 9.119 total&lt;br /&gt;&lt;br /&gt;With function pointers:&lt;br /&gt;2.66s user 0.15s system 130% cpu 2.156 total&lt;br /&gt;&lt;br /&gt;Look at that speedup!  Note how very little time is spent in the kernel making system calls.&lt;br /&gt;&lt;br /&gt;Not too shabby. &lt;br /&gt;&lt;br /&gt;One thing I did find out is that dispatch_async on a queue that has not set it's own target_queue to the main queue, will create a TON of threads.  I had up to 179 at one point.  Once I added the following line to the queue creation function I wrote, it stably stays at 4 threads:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  dispatch_set_target_queue(rv, dispatch_get_global_queue(0,0));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This was again advice given to me by my friend Kevin at Apple.&lt;br /&gt;&lt;br /&gt;Thanks Kevin, this has been enlightening!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-4949471244150857475?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/4949471244150857475/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/09/prime-sieves-again.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4949471244150857475'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4949471244150857475'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/09/prime-sieves-again.html' title='Prime Sieves again'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-7740436564000688395</id><published>2009-09-08T10:21:00.001-07:00</published><updated>2009-09-08T10:25:33.851-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='libdispatch GCD prime sieve concurrency Snow Leopard'/><title type='text'>Last bug found</title><content type='html'>Kevin spotted this before I did, but I'm afraid it's not quite what he thought.  I was using calloc to allocate a context for an event source, but part of that context was initialized after the block's context was created.  This lazy initialization of the context caused me trouble in that I was writing a -1 to stdin (0, because I used calloc should have been stdin, but it was making ???? appear at the console).&lt;br /&gt;&lt;br /&gt;At any rate the completed, and corrected code is &lt;a href="http://paste.lisp.org/display/86549#3"&gt;here&lt;/a&gt;.  &lt;br /&gt;&lt;br /&gt;Kevin went on to inform me that I don't need the semaphore and task counter because I can just use groups and group synchronization on the dispatch_objects that are sources.  He sent me some code, and I'll probably take a look at it, but for the purposes of demonstration I think this code is basically final.  (Groups do make sense to use here however as there's less manual book keeping, and that's part of the advantage of libdispatch and GCD).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-7740436564000688395?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/7740436564000688395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/09/last-bug-found.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/7740436564000688395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/7740436564000688395'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/09/last-bug-found.html' title='Last bug found'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-5935739124810299088</id><published>2009-09-07T17:08:00.000-07:00</published><updated>2009-09-07T17:13:19.432-07:00</updated><title type='text'>A simple solution?</title><content type='html'>Well that crash I caused is partially due to my own terrible error handling, and the fact that I didn't boost my ulimit for file descriptors (I am using a good bit of pipes in my process, but my per-user limit is ridiculously low!!!).&lt;br /&gt;&lt;br /&gt;Upped the ulimit to 2048 from a pathetically low 256 and now I can get through a lot more prime numbers before barfing. (It's a laptop man!  I'm the ONLY user...)&lt;br /&gt;&lt;br /&gt;A rather big part of this is that I'm using pipes for communication between event sources, which fire off my blocks.  There's exactly one pair of fd's for every prime I find, plus all the fds in use under my uname.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-5935739124810299088?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/5935739124810299088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/09/simple-solution.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/5935739124810299088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/5935739124810299088'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/09/simple-solution.html' title='A simple solution?'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-2138480303553668017</id><published>2009-09-07T14:36:00.001-07:00</published><updated>2009-09-07T14:49:26.821-07:00</updated><title type='text'>More libdispatch fun</title><content type='html'>Been playing with libdispatch of GCD from Snow Leopard for a few days now, and I'm having a heck of a time with a demo program I've been writing that's just not working for me yet.&lt;br /&gt;&lt;br /&gt;In fact, today while trying to make the synchronization happier (and succeeded), I realized I'm getting some junk out on stdout.  After trying to figure out exactly why this is happening by tweaking the code and rebuilding it, I managed to panic the kernel.&lt;br /&gt;&lt;br /&gt;The code is still at &lt;a href="http://paste.lisp.org/display/86549#1"&gt;lisppaste&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-2138480303553668017?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/2138480303553668017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/09/more-libdispatch-fun.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2138480303553668017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/2138480303553668017'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/09/more-libdispatch-fun.html' title='More libdispatch fun'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-3660647253530596135</id><published>2009-09-04T00:16:00.001-07:00</published><updated>2009-09-04T00:42:58.265-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Snow Leopard'/><category scheme='http://www.blogger.com/atom/ns#' term='blocks'/><category scheme='http://www.blogger.com/atom/ns#' term='weird'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><category scheme='http://www.blogger.com/atom/ns#' term='CSP'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Adventures with libdispatch</title><content type='html'>Apple released Snow Leopard to the world last Thursday, and with it came this interesting piece of technology called Grand Central Dispatch.  It totally changes the way C, C++, and Objective-C programmers will approach concurrency and threading if they were used to anything at all like pthreads.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Having built up a bit of a functional programming background for myself, I'm no stranger to new ways to do concurrent programming.  Scheme has its ways.  Haskell has a couple of ways (explicitly forkIO'ng sparks that might be run on threads, or data parallelism).  Also, I've tinkered with such things as typed data channels in Limbo from the folks at Bell Labs (seemingly inspired by Newsqueak by Rob Pike and CSP itself).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When I first looked at Grand Central Dispatch from Apple, I was a bit puzzled by the &lt;a href="http://developer.apple.com/mac/library/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html"&gt;API&lt;/a&gt;.  There's queues, event sources, asynchronous dispatching, and this interesting feature they've added to their implementation C language (though some of my fellow 9fans have been somewhat outspoken against it) called blocks.  Blocks are &lt;i&gt;closures&lt;/i&gt; for C.  If you want to know more about closures consult a good book on Scheme or a Scheme tutorial.  (or Lisp!)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm more used to a CSP-like programming interface, and I wondered if I could port a rather famous demo in Newsqueak, and Limbo to this interface.  It's a Prime Number Sieve (Pike?).  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The algorithm may be explained as such (poorly?):&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Create a channel of integers&lt;/li&gt;&lt;li&gt;Start a process that puts onto the channel from step 1 all the numbers from [2,N]&lt;/li&gt;&lt;li&gt;Start a process that reads from the channel all incoming numbers.  The first number read is "special" and becomes that process's special number.  This process prints it's number and creates another channel of ints, that it will feed all numbers that fail the test (incoming_number % my_special_num == 0).  In this way it filters out all numbers that are multiples of it's special number.  &lt;/li&gt;&lt;li&gt;Start another process and feed it the first number that passes through this filter.... the new process follows the same step 3 as above.&lt;/li&gt;&lt;/ol&gt;This creates us a sieve that only lets prime numbers escape.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A good animation of how one works is &lt;a href="http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My prose is rather lacking, so without further ado, here is the code I came up with to try to approach a prime number sieve, using pipes, and blocks, and libdispatch routines to concurrently schedule the sieve on my mac.&lt;/div&gt;&lt;pre&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;// David Leimbach&lt;br /&gt;// September 4, 2009&lt;br /&gt;//&lt;br /&gt;// First, unclean attempt at a prime number sieve in C with libdispatch&lt;br /&gt;//&lt;br /&gt;// Special thanks to Kevin Van Vechten and Jordan Hubbard for guidance through this new API!&lt;br /&gt;//&lt;br /&gt;// Thanks to Apple for making Snow Leopard so affordable!&lt;br /&gt;&lt;br /&gt;#include &amp;lt;dispatch/dispatch.h&amp;gt;&lt;/span&gt;&lt;dispatch/dispatch.h&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;stdio.h&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;stdlib.h&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;sys/types.h&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;#include &amp;lt;sys/uio.h&amp;gt;&lt;/span&gt;&lt;sys/uio.h&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;#include %lt;unistd.h&amp;gt;&lt;/span&gt;&lt;unistd.h&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;br /&gt;#define MAX 300&lt;br /&gt;&lt;br /&gt;struct context&lt;br /&gt;{&lt;br /&gt;int mynum;&lt;br /&gt;int has_spawned;&lt;br /&gt;int writefd;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;void setup_block(int read_fd) {&lt;br /&gt;dispatch_source_t piperead;&lt;br /&gt;struct context * ctx;&lt;br /&gt;piperead = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, read_fd,&lt;br /&gt;        0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0));&lt;br /&gt;&lt;br /&gt;ctx = calloc(sizeof(struct context), 1);&lt;br /&gt;&lt;br /&gt;ctx-&gt;has_spawned = 0;&lt;br /&gt;&lt;br /&gt;dispatch_source_set_event_handler(piperead,&lt;br /&gt;        ^{&lt;br /&gt;          int val;&lt;br /&gt;          int fd[2];&lt;br /&gt;          struct context * ctx = dispatch_get_context(piperead);&lt;br /&gt;&lt;br /&gt;          read(read_fd, &amp;amp;val, 4);&lt;br /&gt;&lt;br /&gt;          if (ctx-&gt;has_spawned == 0) {&lt;br /&gt;     pipe(fd);&lt;br /&gt;     ctx-&gt;writefd = fd[1];&lt;br /&gt;     ctx-&gt;mynum = val;&lt;br /&gt;     ctx-&gt;has_spawned = 1;&lt;br /&gt;     setup_block(fd[0]);&lt;br /&gt;     printf("%d\n", val);&lt;br /&gt;          }&lt;br /&gt;          else {&lt;br /&gt;     if (val % ctx-&gt;mynum != 0) {&lt;br /&gt;       write(ctx-&gt;writefd, &amp;amp;val, 4);&lt;br /&gt;     }&lt;br /&gt;          }&lt;br /&gt;        });&lt;br /&gt;&lt;br /&gt;dispatch_set_context(piperead, ctx);  // associate this state with this context&lt;br /&gt;      &lt;br /&gt;dispatch_resume(piperead);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void run_sieve(int writefd) {&lt;br /&gt;int x;&lt;br /&gt;&lt;br /&gt;for(x=2; x &lt;= MAX; ++x)&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;   write(writefd, &amp;amp;x, 4);&lt;/pre&gt;&lt;pre&gt;&lt;dispatch/dispatch.h&gt;&lt;stdio.h&gt;&lt;stdlib.h&gt;&lt;sys/types.h&gt;&lt;sys/uio.h&gt;&lt;unistd.h&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;   sleep(2); &lt;/span&gt;&lt;/unistd.h&gt;&lt;/sys/uio.h&gt;&lt;/sys/types.h&gt;&lt;/stdlib.h&gt;&lt;/stdio.h&gt;&lt;/dispatch/dispatch.h&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;}  &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;int main () {&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;    int fd[2];&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;    pipe(fd);&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;    setup_block(fd[0]);    &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;    run_sieve(fd[1]);    &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;    return 0; &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt; &lt;span class="Apple-style-span"  style="font-size:medium;"&gt;(Please forgive the code formatting, I'm having great difficulty with blogspot on this stuff with their editor)&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-3660647253530596135?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/3660647253530596135/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/09/adventures-with-libdispatch.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3660647253530596135'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3660647253530596135'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/09/adventures-with-libdispatch.html' title='Adventures with libdispatch'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-4154147145577182841</id><published>2009-09-01T11:55:00.001-07:00</published><updated>2009-09-01T11:57:22.249-07:00</updated><title type='text'>Plan 9 machine running</title><content type='html'>Erik Quanstom's 9atom.iso build of 9load correctly finds my motherboard specifics and can install a Plan 9 system on my old machine making it such that I don't need to buy a new one.  (hooray!)&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the process of figuring this all out, I learned that a Google SoC project "9null" can use Plan 9 to boot Plan 9 directly, rather than 9load which is a significant subset of plan 9 to boot plan 9.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Seems like this should just be easier for the smaller Plan 9 community to maintain.  I've not tried 9null out yet, but I'm pretty anxious to give it a go.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This weekend looks like it might be a good time for some of those side projects.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-4154147145577182841?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/4154147145577182841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/09/plan-9-machine-running.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4154147145577182841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4154147145577182841'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/09/plan-9-machine-running.html' title='Plan 9 machine running'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-494852601966400659</id><published>2009-08-31T19:43:00.000-07:00</published><updated>2009-08-31T19:51:42.143-07:00</updated><title type='text'>EDSL done...</title><content type='html'>The expect embedded Domain Specific Language portion of my code has turned out to be quite the useful little sublanguage to flexibly write little scripts in for controlling, over various channels (ssh, telnet, local comm ports perhaps), devices.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I probably can't document too much about it here, as it's company IP, but I can tell you that building up an EDSL in Haskell is not near as difficult as I thought, at least in the case I've implemented.  It's a matter of choosing the right Monad Transformer base, or writing your own (which could take a long time actually depending on how well you can wrap your head around the sequencing of the various actions you'd like to take).  Also once you realize that the aggregation and sequencing of simpler actions can be used to build up more complex ones, you're pretty much golden and have learned to realize the full power of the Monad concept.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's also one thing to see it, or even read about it, but the real eye-opening bit is when you actually implement one that's useful to you on your own.  Then you almost want to beat your chest and proclaim you're the new king of the tribe.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I love a programming language that you can use to build specialized tools ,*very* quickly, that meet your immediate need.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My boss even almost threw me a curve ball on the way he thinks I should utilize this technique.  Then I realized that what I'd written could most easily support the sort of idea he was after because I picked the right abstractions.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm very grateful that this technology even exists, as it is saving us a lot of time where I work, making progress on this sort of programming that otherwise seems a ton of work.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Haskell is definitely for the win today :-)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-494852601966400659?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/494852601966400659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/08/edsl-done.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/494852601966400659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/494852601966400659'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/08/edsl-done.html' title='EDSL done...'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-4814516191581585757</id><published>2009-08-25T18:55:00.000-07:00</published><updated>2009-08-25T19:04:31.701-07:00</updated><title type='text'>Haskell and DSLs</title><content type='html'>One of the great features of Haskell is the ability to write programs that execute in contexts that are separate from the rest of your program.  Monads are one of those kinds of contexts, and a monad allows you to define exactly what happens when you sequence different expressions within a context.   Using this, one can write little imperative DSLs (Domain Specific Languages) that execute along side the rest of your Haskell code.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's DSLs for controlling "robots" in Hudak's Haskell School of Expression book.  There's a DSL that is a &lt;a href="http://www.vintage-basic.net/downloads/Vintage_BASIC_Users_Guide.html"&gt;"vintage basic"&lt;/a&gt;.  There's another one for controlling small realtime systems called &lt;a href="http://patch-tag.com/r/atom/home"&gt;Atom&lt;/a&gt;. &lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The possibilities seem endless.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've been considering making one of these as a replacement for the old Unix program expect, or at least a subset of it that I'm interested in.  Haskell's already got very strong regular expression libraries, and some of the best parser writing libraries I've seen.  Having something like the expect syntax for interacting with remote services or devices would be excellent in conjunction with those other capabilities.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I found a tutorial &lt;a href="http://ashish.typepad.com/ashishs_niti/2007/06/haskell_dsl_and.html"&gt;online&lt;/a&gt; today about DSLs that seems pretty good.  We'll see if I ever get to the point of implementing one.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-4814516191581585757?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/4814516191581585757/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/08/haskell-and-dsls.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4814516191581585757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4814516191581585757'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/08/haskell-and-dsls.html' title='Haskell and DSLs'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-5675229370446455218</id><published>2009-08-20T07:47:00.001-07:00</published><updated>2009-08-20T07:52:00.589-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lazy'/><category scheme='http://www.blogger.com/atom/ns#' term='Monad'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>Interesting Discussion</title><content type='html'>I've been talking Monads with folks on haskell-cafe as well as lazy-IO, and understanding strictness and where it sometimes needs to be sprinkled in to get the behavior desired from a lazy IO system.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is sort of the price paid for wanting to completely separate one's pure data processing code from IO.  The advantage of having this separation is of course in testing of code, in that pure code has referential transparency, meaning that you can call it any number of times you like, and as long as you provide the same X for input, you will always receive the same Y as a result.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;By putting Input and Output operations into their own context of evaluation, we totally avoid certain classes of problems in software writing, so the effort seems worth it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Needless to say it's been an interesting discussion, linked &lt;a href="http://www.haskell.org/pipermail/haskell-cafe/2009-August/065417.html"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-5675229370446455218?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/5675229370446455218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/08/interesting-discussion.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/5675229370446455218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/5675229370446455218'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/08/interesting-discussion.html' title='Interesting Discussion'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-4226841979517468121</id><published>2009-08-18T19:53:00.000-07:00</published><updated>2009-08-18T20:26:05.095-07:00</updated><title type='text'>Posixy stuff and Haskell</title><content type='html'>&lt;span class="Apple-style-span"  style="font-size:small;"&gt;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.&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;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 &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;interact&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;, or rather, a close relative of interact.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;Interact has the signature &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;interact :: (String -&gt; String) -&gt; IO ()&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;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 ().&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;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.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;The way it works is by calling the function &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;getContents&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;, which lazily reads all the input from stdin and processes it through the provided (String -&gt; String) function, to produce output.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;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.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;For example, if one sets the handles for stdin and stdout to "LineBuffer" based buffers &lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;before &lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;calling interact, you can get linewise input by doing the following inside the (String -&gt; String) processing function.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;lineId = unlines . lines&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;The function &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;lineId&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; breaks up the lazy input string into lines, then re-assembles them by composing the function lines and &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;unlines&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; together.  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;The type of the function &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;lines&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; is:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;lines :: String -&gt; [String]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;The type of the function &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;unlines&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; is&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;unlines :: [String] -&gt; Strin&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;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 &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;lines&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;, however, if I add further behaviors to the function composition expression that operate on the [String] result of &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;lines&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; &lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;before&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; running &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;unlines&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; I have the opportunity to work on each member of the list.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;This gives me guaranteed linewise input evaluation of commands, and the ability to interpret line-oriented protocols, strings or what have you.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;Now think of how useful &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;interact&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; can be?  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;Now, &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;interact&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; 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 &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;interact&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; that can handle those sources of data.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;hInteract :: Handle -&gt; Handle -&gt; (String -&gt; String) -&gt; IO ()&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;hInteract inp out f = hPutStr out . f  =&amp;lt;&amp;lt; hGetContents inp&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;This function can take a handle for input, a handle for output, and a function of String -&gt; String, and uses them to lazilly read input from the input handle, pushing data through the String -&gt; String function, to finally output the result string to the output handle.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;All of the interesting parts of this function are still contained in &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;f&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;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 &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;words &lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;and &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;unwords.&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;I think I'm nearly ready to write an almost IO free, pure version of my Expect-like code bot in Haskell. &lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-4226841979517468121?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/4226841979517468121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/08/posixy-stuff-and-haskell.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4226841979517468121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4226841979517468121'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/08/posixy-stuff-and-haskell.html' title='Posixy stuff and Haskell'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-3329652412571131625</id><published>2009-08-10T12:49:00.001-07:00</published><updated>2009-08-10T12:55:23.922-07:00</updated><title type='text'>Keepin Busy</title><content type='html'>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.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-3329652412571131625?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/3329652412571131625/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/08/keepin-busy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3329652412571131625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3329652412571131625'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/08/keepin-busy.html' title='Keepin Busy'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-9196817899811607040</id><published>2009-07-14T16:53:00.000-07:00</published><updated>2009-07-14T17:02:51.939-07:00</updated><title type='text'>Need a new machine</title><content type='html'>I recently posted to 9fans that I  think I would like to get a new dedicated plan 9 box.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's my wish list:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Small footprint&lt;/li&gt;&lt;li&gt;Low power consumption&lt;/li&gt;&lt;li&gt;Connection to a large amount of storage, perhaps a 1TB disk external if  I can configure it as such.&lt;/li&gt;&lt;li&gt;Good Plan 9 support&lt;/li&gt;&lt;li&gt;Low cost&lt;/li&gt;&lt;/ul&gt;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 &lt;a href="http://www.amazon.com/Audio-Advantage-Micro-Sound-Card/dp/B0002ICGDY/ref=sr_1_1?ie=UTF8&amp;amp;s=electronics&amp;amp;qid=1247615811&amp;amp;sr=8-1"&gt;Turtle Beach Audio Advantage Devices&lt;/a&gt;.  So adding that later isn't going to be very difficult.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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....&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One day, I might see what it would take to get Plan 9 ported to what seems like will be inevitable &lt;a href="http://pcworld.about.com/od/businesscenter/Arm-to-Duel-With-Intel-in-the.htm"&gt;quad core ARM servers.&lt;/a&gt;  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.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-9196817899811607040?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/9196817899811607040/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/07/need-new-machine.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/9196817899811607040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/9196817899811607040'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/07/need-new-machine.html' title='Need a new machine'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-8254053184427902969</id><published>2009-07-14T16:41:00.001-07:00</published><updated>2009-07-14T16:47:47.488-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='plan9'/><title type='text'>Fun Distraction</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_RkKpoITzx50/Sl0ZD0fmZFI/AAAAAAAAAAM/CqaYUQQBQNs/s1600-h/mozilla-plan9.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 257px;" src="http://1.bp.blogspot.com/_RkKpoITzx50/Sl0ZD0fmZFI/AAAAAAAAAAM/CqaYUQQBQNs/s320/mozilla-plan9.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5358466685062243410" /&gt;&lt;/a&gt;&lt;br /&gt;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.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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....&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-8254053184427902969?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/8254053184427902969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/07/fun-distraction.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/8254053184427902969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/8254053184427902969'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/07/fun-distraction.html' title='Fun Distraction'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_RkKpoITzx50/Sl0ZD0fmZFI/AAAAAAAAAAM/CqaYUQQBQNs/s72-c/mozilla-plan9.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-6941106248758036609</id><published>2009-07-08T09:10:00.000-07:00</published><updated>2009-07-08T09:15:29.206-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='9ph'/><title type='text'>Not quite dead</title><content type='html'>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.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;... I'll get there one day.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-6941106248758036609?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/6941106248758036609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/07/not-quite-dead.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/6941106248758036609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/6941106248758036609'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/07/not-quite-dead.html' title='Not quite dead'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-3136369801719096353</id><published>2009-06-03T14:59:00.000-07:00</published><updated>2009-06-03T15:01:28.431-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='9ph'/><title type='text'>Success</title><content type='html'>Made progress on Tversion/Rversion comms.  It works.  It was a matter of using the correct decoder... big D'oh, on my part.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Next is the hard stuff.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And first I have business travel to contend with, for the first time in a while.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-3136369801719096353?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/3136369801719096353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/06/success.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3136369801719096353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3136369801719096353'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/06/success.html' title='Success'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-6268633099912934059</id><published>2009-06-01T21:48:00.001-07:00</published><updated>2009-06-01T22:19:49.517-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='9ph'/><title type='text'>Progress</title><content type='html'>Sometimes I just need to RTFM closer.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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).  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Still, I consider this progress.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've decided to call this little project 9ph for now, (9p in haskell)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-6268633099912934059?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/6268633099912934059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/06/progress.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/6268633099912934059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/6268633099912934059'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/06/progress.html' title='Progress'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-3276412934815600670</id><published>2009-05-28T19:52:00.001-07:00</published><updated>2009-05-28T19:53:56.942-07:00</updated><title type='text'>Progress</title><content type='html'>With much help from folks on haskell-cafe, I've got a basic utility Haskell module under development (Nine.hs) for trying to make unauthenticated connections to Styx servers from Haskell.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So far it's not quite right, but I can marshall a little-endian encoded stream of a Tversion message (I think... need to debug on the Inferno side a bit too.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;More later, hopefully.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-3276412934815600670?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/3276412934815600670/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/05/progress.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3276412934815600670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/3276412934815600670'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/05/progress.html' title='Progress'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-4309621362681237243</id><published>2009-05-22T15:58:00.000-07:00</published><updated>2009-05-26T15:52:39.465-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='pipe dreams'/><title type='text'>What I'm up to at least dreaming about doing.</title><content type='html'>For the last year or so I've been following and writing some code in the Haskell programming language, specifically using the &lt;a href="http://haskell.org/ghc"&gt;GHC&lt;/a&gt; compiler, on Mac OS X, Linux and Windows.  I've been using it in simulations at work for a remote computer hardware management system we've been developing, and it's been quite fruitful.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Also, we've been developing a management software package at work that deals with namespaces of resources rather than a static class library Object Oriented Model, which can become very difficult to design appropriately or extend as the needs of the organization, and our customers, evolve over time.  We aimed to make a project that uses a very simple interface to complex management systems, and I think we're succeeding quite well.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On top of all of this I've also been coding in &lt;a href="http://www.erlang.org/"&gt;Erlang&lt;/a&gt; for a bit of time now (about 2 years and 1.5 of those professionally) and I've found that designing systems as if they're distributed from the get go really helps one fit into the new trendy SOA models everyone wants you to think about in industry these days (It's just client server architecture with a lot of marketing as far as I can tell).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've also been using systems based on a distributed design like Plan 9 and Inferno as much as I can work them into my life these days.  Sadly that seems to have fallen back to *only* the use of an IRC file system for Inferno - a cool concept, think about how the popular UNIX "screen" program works with sessions you can detach and re-attach to, but do it over a system-wide ubiquitous file system protocol (&lt;a href="http://9p.cat-v.org/"&gt;9p&lt;/a&gt;).  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've worked with 9p client libraries written in C, Python, Java and other languages, but I've yet to see on for Haskell or Erlang for that matter.  Perhaps someone should do something about that...  (perhaps I will, time is not something I have an abundance of for this stuff these days).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One thing I would love to be able to do is fire up an iPhone application that had an embedded 9p client, and connect to the irc file system and use it.  Another interesting approach would be to try to implement the &lt;a href="http://lsub.org/ls/octopus.html"&gt;Octopus&lt;/a&gt; client on the iPhone OS, and just use that to connect to running programs on a centralized server.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;These days I wish I could just take a paid sabbatical from work and do these things, as spare time is hard to come by.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-4309621362681237243?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/4309621362681237243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/05/what-im-up-to-at-least-dreaming-about.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4309621362681237243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4309621362681237243'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/05/what-im-up-to-at-least-dreaming-about.html' title='What I&apos;m up to at least dreaming about doing.'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6892477962078801717.post-4758927148228661393</id><published>2009-05-20T13:50:00.000-07:00</published><updated>2009-05-20T13:51:59.024-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='meta'/><title type='text'>Purpose</title><content type='html'>Just a notebook of stuff I'm trying to do in my spare time, mostly for fun.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6892477962078801717-4758927148228661393?l=leimy9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leimy9.blogspot.com/feeds/4758927148228661393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leimy9.blogspot.com/2009/05/purpose.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4758927148228661393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6892477962078801717/posts/default/4758927148228661393'/><link rel='alternate' type='text/html' href='http://leimy9.blogspot.com/2009/05/purpose.html' title='Purpose'/><author><name>dleimbach</name><uri>http://www.blogger.com/profile/16390601578699023986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
