Archives

Tags

blog scheme chipy mediagoblin freesw ai hatecrime licensing rsi deployment security lambdamoo release art autonomous cookies talks beyond-javascript wedding cryptocurrency hy guix fauxnads python diet configuration orgmode xudd anniversary miro pycon advocacy slib guile backups nouveau emacs monads base64 conference firefox tech privilege game family vegan personal n900 biking zine hacking pcf javascript creative-commons podcast blender speech recognition identica email sqlite phone libreplanet life update pelican by-sa freespeech art frostcast xkcd macros meme openmoko food package manager cooking contributor drawing patents money economics dustycloud immutability uuid code campaign recipe libre-graphics-meeting music gpl gnome shared hosting moo xmpp foss kinda-mediagoblin topsort robogoblins sfxr boingboing lisp mud firebug

Fever Dream: cryptocurrency

By Christopher Allan Webber on Sun 29 March 2015

I've been sick the last two days, and for some reason, I've been dreaming in lisp. It's not the first time I've dreamt in code, but all times have been in lisp. Maybe lisp is not as readable as many would like, but it seems dreamable.

Just got up from another nap, another lisp-based fever dream. This one about a cryptocurrencty on an actor model system, built for a MUD/AR type environment... no blockchain required (note: may be inspired by reading Rainbows End between naps):

  • Various actors represent "reserves", like the Federal Reserve can print their own money, as much as they like, but there may be various community enforcements of this
  • You might have different central banks / reserves on different servers
  • The "value" or exchange rate determined by the market, like international currency.
  • Currency is non-divisible (you have 100 rupees, but not .1 rupees)
  • Bank has a private key, so does each actor.
  • Basically more or less passing along capabilities (I think???) but maybe even the central bank signing whoever has "posession". The bank does not know who things are transferred to, but does verify that the transferring owner has the right capability currently belonging to that unit's ID, and does issue a new capability to the new owner.

Does this make sense? I'm too sick to know for now. But transactions flying everywhere, wrapped in parentheses, in my fevered mind.

If I have more crazy lisp fever dreams today I will record them here. No guarantee of sanity.

LibrePlanet and W3C Social Working Group 2015

By Christopher Allan Webber on Sun 29 March 2015

Great trip, spent 2 weeks doing the following:

  • Attending W3C Social Working Group. Good things have happened; felt much more clear by the second day than by the first day. Lessons learned in that raising issues (normally I'm reasonably quiet, a certain amount of imposter syndrome while participating in the group) was helpful, some people said they were thinking about the same things. Anyway, much work to do ahead.
  • Hanging out at Deb Nicholson's place with friends
  • Gave a talk at Libreplanet which I'm happy with
  • Had an awesome night of vegan salted caramel root beer floats (the best thing ever it turns out) and Hanabi with Aeva Palecek, Amy Guy, and Jessica Tallon; all friends of federation, but it was nice getting to decompress without worrying about that stuff for a bit. Way better than a trip to the bar!
  • So many great people at Libreplanet. I'm kind of sad that I didn't get to spend a lot of time with everyone, but the up side is that I got to spend a lot of time with some particularly great people, and the main problem was there was just too many good people at once. A good problem.
  • Mako and Karen both gave good keynotes, and I liked a lot of talks
  • Lots of Veggie Galaxy, eaten
  • Then took a trip to hang out with @Bassam Kurdali, Fateh, Libby Reinish, Tristen, at their respective places. It was nice to do this with @Tsyesika / Jessica Tallon joining me.
  • Much of the week spent from the "Nerdodrome", Hampshire College's animation studio, where Bassam works. I spent most of the week working on a deployment system I'm specc'ing out. If it turns out to be something I use, I'll update with more info.
  • Got to spend some time exploring Western Mass, which was great.

The trip was really worth it. I spent a lot of time with people I care about, and it felt very productive.

I'm not planning another conference for the remainder of 2015 though. Amongst other things, my back and wrists are killing me right now, and doing this morning's stretches was a painful wake-up. And I have a lot of difficult personal things in the year ahead. Oh, and let's not forget about how much work there is to do on MediaGoblin that I haven't gotten to.

But! This trip really helped set some directions for me for the year ahead, and I'm really grateful for that.

Looking forward to LibrePlanet 2016!

Fauxnads

By Christopher Allan Webber on Sat 14 March 2015

So off and on, I've been trying to understand monads. It turns out I have a use case: making web applications in the style I'd like but have them be asynchronous leads to trouble because you need a non-global-variable way of passing along context. I've tried thinking of some solutions, but a friend of mine convinced me that monads, if I could wrap my head around them, would solve the problem for me.

With that in mind, I did some reading... there are plenty of resources out there, some of them with nice pictures, and at one point I tried to understand them by just reading about them and not writing any code relevant to them. This lead to me guessing how they might work by trying to contextualize them to the problems I wanted to solve. So along that path, I had a misunderstanding, a mistaken vision of how monads might work, but while I was wrong, it turned out that this vision of ~monads is kind of fun and had some interesting properties, so I decided to code it up into a paradigm I'm jokingly calling "fauxnads".

Brace yourself, we're about to get into code, pseudo- and real, and it's going to be in Guile. (All code in this blogpost, GPLv3+ or LGPLv3+, as published by the FSF!)

So here's the rundown of fauxnads:

  • They still pass along a context, and under the hood, they do pass it in still as the first argument to a function!
  • The context gets passed up (and optionally, down... more on that in a few) in some kind of associative array... but we don't want to accidentally change the context that we passed to other functions already, so we'll use something immutable for that.
  • The user doesn't really access the context directly. They specify what variables they want out of it, and the fauxnad macro extracts it for them.
  • Fauxnads can add properties to the context that they'll call subroutines with so that subsequent fauxnad calls can have access to those.
  • Calling child fauxnads happens via invoking a function (=>) exposed to the rest of the fauxnad via some lexical scope hacks.

So when sketching this out, I tried to boil down the idea to a quick demo:

;; fleshed out version of what a fauxnad should approx expand to
(define (context-test1 context arg1 arg2)
  (letrec ((new-context context)
           ;; Define function for manipulating the context
           (context-assoc
            (lambda (key value)
              (set! new-context
                    (vhash-cons key value new-context))))
           ;; a kind of apply function
           (=>
            (lambda (func . args)
              (apply func (cons new-context args))))) ;; should be gensym'ed

    ;; This part would be filled in by the macro.
    ;; The user would set which variables they want from the context
    ;; as well as possibly the default values
    (let ((a (or (vhash-assoc 'a context) "default-value for a"))
          (b (or (vhash-assoc 'b context) "default-value for b"))
          (c (or (vhash-assoc 'c context) "default-value for c")))
      (values
       (begin
         (context-assoc 'lol "cats")
         (=> context-test2 "sup cat")
         (context-assoc 'a "new a")
         (=> context-test2 "sup cat")
         (format #t "a is ~s, b is ~s, and c is ~s\n"
                 a b c)
         (string-append arg1 " " arg2))
       new-context))))

;; intentionally simpler, not a "real fauxnad", to demo
;; the fauxnad concept at its most minimal
(define (context-test2 context arg1)
  (begin
    (format #t "Got ~s from the context, and ~s from args, mwahaha!\n"
            (vhash-assoc 'a context)
            arg1))
  (values
   "yeahhh"
   context))

Then calling in the console:

scheme@(guile-user)> (context-test1 (alist->vhash '((a . 1) (b . 2))) "passed arg1" "passed arg2")
Got (a . 1) from the context, and "sup cat" from args, mwahaha!
Got (a . "new a") from the context, and "sup cat" from args, mwahaha!
a is (a . 1), b is (b . 2), and c is "default-value for c"
$79 = "passed arg1 passed arg2"
$80 = #<vhash 2205920 4 pairs>

Okay, whaaa? Let's look at the requirement again. We'll be passing in a function to the start of the function, and then having some other args. We'll then pass that along to subsequent functions. So more or less, we know that looks like this. (I know, not the most useful or pretty or functional code, but it's just a demo of the problem!)

(define (main-request-handler context request)
  ;; print out hello world in the right language
  (display (translate-this (context-get context 'lang) "Hello, world"))
  (newline)

  ;; now call another function
  (next-function new-context (smorgify arg1)))

(define (next-function context what-to-smorgify)
  (write-to-db
   ;; Lots of functions need access to the
   ;; current database connection, so we keep it in the context...
   (context-get context 'db-conn)
   (smorgify-this what-to-smorgify)))

But wouldn't it be cool if we didn't have to pass around the context? And what if we just said, "we want this and this from the context", then forgot about the rest of the context? We'd never need to call context-get again! It would also be cool to have a way to set things in the context for subsequent calls. Ooh, and if we coud avoid having to type "context" over and over again when passing it into functions, that would also be awesome.

So how about a syntax like this:

(define-fauxnad (our-special-function arg1)
  ((lang "en"))  ;; we want the language variable, but if not set,
                 ;; default to "en" or english
  ;; (body is below:)
  ;; print out hello world in the right language
  (display (translate-this lang "Hello, world"))
  (newline)
  ;; now call another function
  (=> next-function (smorgify arg1)))

We also know we want to use some sort of immutable hashmap. Guile provides vhashes which provide "typically constant-time" data access, and while there are some caveats (a new vhash returned by appending a key/value pair where that key already existed in the vhash will just keep the old pair around... but on our pseudo-stack that shouldn't happen very often, so vhashes should be fine), they work for our purposes.

Okay, cool. So what would that look like, expanded? Something along the lines of:

(define (our-special-function context arg1)
  (letrec ((new-context context)
           ;; Define function for manipulating the context
           (context-assoc
            (lambda (key value)
              (set! new-context
                    (vhash-cons key value new-context))))
           ;; a kind of apply function
           (=>
            (lambda (func . args)
              (apply func (cons new-context args))))) ;; should be gensym'ed

    ;; This part would be filled in by the macro.
    ;; The user would set which variables they want from the context
    ;; as well as possibly the default values
    (let ((lang (or (vhash-assoc 'lang context) "en")))
      (values
       (begin
         ;; print out hello world in the right language
         (display (translate-this (context-get context 'lang) "Hello, world"))
         (newline)

         ;; now call another function
         (next-function new-context (smorgify arg1)))
       new-context))))

As a bonus, we've taken advantage of Guile's multi-value return support, so any parent function which cares can get back the new context we defined for subsequent calls, in case we want to merge contexts or something. But functions not aware of this will simply ignore the second returned parameter. (I'm not sure this is a useful feature or not, but it's nice that Guile makes it easy to implement!)

That's clearly quite a complicated thing to implement manually though... so it's time to write some code to write code. That's right, it's macro time! Guile has some pretty cool hygienic macro support that uses "syntax tranformation"... a bit nicer than common lisp's defmacro, but also less low-level. Anwyay, if you're not familiar with that syntax, trust me that this does the right thing I guess:

(define-syntax define-fauxnad
  (lambda (x)
    (syntax-case x ()
      ((_ (func-name . args)
          ((context-key context-default) ...)
          body ...)
       (with-syntax ((=> (datum->syntax x '=>))
                     (context-assoc (datum->syntax x 'context-assoc)))
         #'(define (func-name context . args)
             (letrec ((new-context context)
                      ;; Define function for manipulating the context
                      (context-assoc
                       (lambda (key value)
                         (set! new-context
                               (vhash-cons key value new-context))))
                      ;; a kind of apply function
                      (=>
                       (lambda (func . func-args)
                         (apply func (cons new-context func-args))))) ;; should be gensym'ed

               ;; This part would be filled in by the macro.
               ;; The user would set which variables they want from the context
               ;; as well as possibly the default values
               (let ((context-key (or (vhash-assoc (quote context-key) context)
                                      context-default))
                     ...)
                 (values
                  (begin
                    body ...)
                  new-context)))))))))

Nice, now writing our fauxnads is dead-simple:

(define-fauxnad (our-special-function arg1)
  ((lang "en"))  ;; we want the language variable, but if not set,
  ;; default to "en" or english
  ;; (body is below:)
  ;; print out hello world in the right language
  (display (translate-this lang "Hello, world"))
  (newline)
  ;; now call another function
  (=> next-function (smorgify arg1)))

(define-fauxnad (next-function context what-to-smorgify)
  ((db-conn #nil))
  (write-to-db
   ;; Lots of functions need access to the
   ;; current database connection, so we keep it in the context...
   (context-get context 'db-conn)
   (smorgify-this what-to-smorgify)))

Okay, again, my demos don't make this look very appealing I suppose. We can now transform the original demos I sketched up into fauxnads though:

(define-fauxnad (context-test1 arg1 arg2)
  ((a "default value for a")
   (b "default value for b")
   (c "default value for c"))
  (context-assoc 'lol "cats")
  (=> context-test2 "sup cat")
  (context-assoc 'a "new a")
  (=> context-test2 "sup cat")
  (format #t "a is ~s, b is ~s, and c is ~s\n"
          a b c)
  (string-append arg1 " " arg2))

(define-fauxnad (context-test2 arg1)
  ((a #nil))
  (format #t "Got ~s from the context, and ~s from args, mwahaha!\n"
          a arg1)
  "yeahhh")

And calling it:

scheme@(guile-user)> (context-test1 (alist->vhash '((a . 1) (b . 2))) "passed arg1" "passed arg2")
Got (a . 1) from the context, and "sup cat" from args, mwahaha!
Got (a . "new a") from the context, and "sup cat" from args, mwahaha!
a is (a . 1), b is (b . 2), and c is "default value for c"
$81 = "passed arg1 passed arg2"
$82 = #<vhash 2090ae0 4 pairs>

Okay, so what's the point? I doubt this blogpost really would sell anyone on fauxnads, and maybe why would you use fauxnads when you can use real monads? But here's some interesting properties:

  • fauxnads are still super simple functions that you can call manually: just pass in the context (a vlist) as the first parameter.
  • the "binding" function for calling sub-fauxnads is sugar, but hidden (and otherwise inaccessible, because the function hygeine keeps you from accessing "new-context") from the user.
  • I still like that you can get back the new context via multiple value return, but totally ignore it if you don't care about it.
  • I understand how they work.

And on that last note, I still don't understand monads, but I feel like I'm getting closer to it. It was fun to document, and put to code, a misunderstanding though!

Why XUDD is stuck (or: why Python needs better immutable structures)

By Christopher Allan Webber on Mon 23 February 2015

Update: Well, you post a thing, and sometimes that's enough for people to come and help you realize how wrong you are. Which is good! There are a number of ways forward (some obvious in retrospect). For one, pyrsistent does exist and looks nice and... well it's even actively developed. But even aside from that, there are several clean solutions: wrapper objects which "lock" the child object with getters but no setters, or even just using alist style tuples of tuples for a fake hashmap. Options are indeed abound.

And the exception thing? Well, that wasn't listed as a permanent problem below, but the solution is even easier! It would be simple to have a MessageError("some_identifier") which has a minimalist identifier which can be passed across the wire, and the directive of this error can be a special case.

Anyway, you can read the original post below. But it's good to be wrong. XUDD no longer has reason to be dead. Long live XUDD!

tl;dr: Kind of along post, but basically the lack of good functional data structures in Python has kinda killed the project.

One of my favorite projects ever has been to work on XUDD, an asynchronous actor model system for Python. Originally born out of a quest to build a MUD (hence the name), but eventually became the focus of being an actor model itself, it was a really interesting exploration for me.

There's a lot of things I like about the actor model... for one thing, functional programming is all the rage, right? But not all systems are easy to express in a purely functional style, and done right an actor model can be fairly object oriented'y, but done right, you can have your mutable cake and eat it too, safely! Your actor can mutate some of its own variables, but when it communicates across the wire, since it's a "shared nothing" environment you can get even better scale-to-the-moon type functionality than in many functional language systems: it's trivial to write code where actors communicate across multiple processes or machines in just the same way as if they were all on the same machine in the same process and thread.

I put a lot of thought into XUDD, and I've looked into some of the alternatives like Pykka, and I still think XUDD has some ideas that kicks butt on other systems. I still think the use of coroutines feels very clean and easy to read, the "hive" model is pretty nice, and the way it's built on top of the awesome asyncio system for Python are all things I'm happy with.

So, every once in a while I get an email from someone who reads the XUDD documentation and also gets excited and asks me what's going on.

The sad reality is: I'm stuck. I'm stuck on two fronts, and one I can figure my way out of, but the other one doesn't seem easy to deal with in Python as-is.

The first issue is of error propagation. This is solvable, but when an exception is raised, it would be nice to propagate this back to the original actor. There are some side issues I'm not sure about: in an inter-hive-communication (read: multiple machines or processes) type scenario, should we use standard exceptions and try to import and reproduce the same exception that was raised elsewhere? That seems like it could be... gnarly to do. Raising the error inside the original routine is also a bit tricky, but not too hard; python's coroutines can support it and I just need to think about it. So exceptions are annoying but solvable.

But the other issue... I'm not sure what to do about it. Basically, it's an issue of a lack of immutable types, or we might even say "purely functional datastructures" that are robust enough to continue with. Why does that matter? Messages sent between actors shouldn't have any mutable data. It's fine and well and even a nice feature for actors to be able to have mutable data within themselves, and actually even provide a nice way to pull of things that are just damned hard in purely functional systems, but between actors, mutable data is a no-no.

It's easy to see why: say we have a function that has a list in it, say of a number of children in my classroom, and I send this list over to an actor that controls some sort of database, right? I'm doing things in a nice, fancy coroutine'ish type way, which means my function can just suspend mid-execution while it waits for that database actor to generate some sort of reply and send it back to me. What happens if that other function pops one of the items off the list, or appends to it, or in some way actually mutates the list? Now, when my function continues, it'll be operating on a differently formed list than the one it thinks it has. I might have a reference to the third item in the list, but it turns out that there isn't a third item in the list anymore, because the other function popped it off. This can introduce all sorts of subtle bugs, and it's bumming me out that I don't have a good solution to them.

Now, there's a way around this: you can serialize each and every message completely before sending it to another actor. And of course, if actors are on different threads, processes, or even entirely different machines, of course we'd do this. But XUDD has the concept of actors being on the same hive, and there are a number of reasons for this, but one of them is that for local message passing, packing and unpacking data in some sort of serialized format for every call slows things down by a lot. When I originally began designing XUDD, the plan was for games that might need to shard out to a number of different servers but have players that can traverse different parts of the system and communicate with other shards (without knowing or the code mostly knowing that it's communicating with other actors that are technically remote). I want to be able to pass many messages at once to actors that are on the same hive, while still having a totally safe time of doing so. But there's no way to do so without a nice set of immutable / "purely functional" types, and Python just doesn't have this right now. None of the third party libraries I've found seem well maintained (am I missing something?), and the standard library is fairly deficient here. Why? I'm not really sure. I guess Python's history is just synchronously imperative enough that it just hasn't mattered.

I'd like to continue research into the actor model... I have some projects I'd like to work on where the actor model seems perfectly tuned to those tasks. What to do?

Well, I'm not really sure... I guess I could just serialize everything all the time, but it's kind of a bummer to me that so many cycles would be wasted for local computation. Maybe it's a dumb reason to feel exhausted with things, but that's the state of it. I'm not enough of a datastructure wizard to implement these things myself, but they exist. I've thought about giving up on XUDD being a Python project and to move over to something else... Guile has a cooperative REPL which would be great for debugging, and I really like the community there, so maybe that would be a nice place to go. Not really sure there's anything else I'm interested enough in at the moment. I think I'd miss Python. Or maybe I'm over-thinking everything in the first place? (Wouldn't be the first time.)

Maybe there's another way out. If you have any ideas, contact me.

Thoughts on LambdaMOO from a newbie

By Christopher Allan Webber on Sun 22 February 2015

While working on MediaGoblin's upcoming release, and (dare I say) feeling a bit bored and anxious and frustrated about the whole process, I decided that maybe it was time to look into some sort of entertainment. But for the most part, I feel like I've played all the interesting free software games out there. I've mostly beaten even the games of my old proprietary console using past. What to do?

I wondered what the state of good ol fashioned MUD systems are. I've had dreams for years of building such a system from scratch (hence my interest in the actor model). Answer: they feel like they're in the same place they were around 2000. But maybe this isn't bad? I tried playing some dungeon crawling'y MUDs but found myself a bit bored. But having remembered that Rob Myers has talked plenty about LambdaMOO, so that seems like good enough reason to connect and look around. (Note, connecting is not hard! I am using Mudlet at the moment.)

So, in-between actual coding and fretting about this and that, I've been getting in some downtime, poking around the LambdaMOO environment. And at first I was fairly unimpressed... this thing is what, 20 rooms big? What can I do here? But I've been finding some interesting things:

  • That LambdaMOO is both the software and one particular server is fairly confusing, but no matter: both are of interesting construction. They're both also very old, 25 years old at this point (egads), but particularly as to the world, that leads to much depth.
  • The main rooms of the house (see help geography) are not as interesting as the places they lead to. You can enter a model railroad and actually walk around that imaginary city and end up in some interesting places, reading graffiti off of nightclub walls, etc. Find an old teletype and type on it, or play one of the functioning (!) board games sitting around. A dusty hallway leads to a full hack and slash style game engine, coded live inside the system itself.
  • Most of the world is not really a dungeon crawler, though there is one hidden in it. Most of walking around LambdaMOO is exploring the many curiosities that users have provided there.
  • Speaking of coding live inside the system, what's really interesting about LambdaMOO is that you're really manipulating a big database, and that many features are live coded from within the game itself. Everyone can experiment with adding rooms, though not everyone can program, though you may be able to get help from a certain buffer in the smoking room, if you can find it. (I just got access... I'll have to try things.)
  • LambdaMOO is best known for a famous essay, but I think that essay is maybe not as interesting as it was in the 90s when online experiences were becoming a new thing? Still, the effect of the essay and the event it chronicles is still clear, including the way the world is introduced to you.
  • Interesting to think of LambdaMOO in case of copyright and licensing, of which... well there seems to be no clear answer what is going on, but sharing seems not impeded by it.
  • Being from the early 90s, it's amazing how much is here to explore, and how everything still lives. Since most of the world is pretty "low burn", that's nice for me, because I can just type in a command to look around somewhere every once in a rare while and leave LambdaMOO open in the background.
  • I'm enjoying exploring the world, but I sense that LambdaMOO had a heyday, and while there are users connected, the sheer size of it vs the volume of connected users gives me the sense that today is not it. There's a certain amount of feeling of exploring a secret city, which is wonderful and sad. (It would be nice to have some friends who were interested in exploring with me, maybe I should cajole some into joining me.) It's an interesting piece of internet history, still here to explore, but since it's in a "living" database, what will happen when it shuts down? There won't be any Internet Archive to preserve the LambdaMOO memories, I fear. But maybe nothing is forever, anyway.

I have more, maybe crazier, thoughts on MUDs and maybe a way they could be more useful in this modern world. May I'll explore soon, but I think that the popularity of MUDs has diminished with World of Warcraft and Skyrim and the like, but maybe they have a place still if we can do some new things with them? And those are fairly hack-and-slash type systems, maybe MOO/MUD/MUSH systems have more to offer than popular MMO systems provide? Roguelikes seem more popular than ever, if anything... things can come back... maybe new interfaces are needed?...

In the meanwhile, if you drop by LambdaMOO, send me a message! I'm "paroneayea" there.