Metacircular thoughts

September 23, 2008

Prolog just blew my mind!

Filed under: Prolog — metacircular @ 11:04 pm

A while ago, I came across a fascinating blog entry apparently detailing how to embed an ALGOL-like language in Prolog, with a compelling concrete syntax exposed. However, as the comments indicate, his code did not work as is. Changing the “then” and “else” creators to be infix and adhering to the defined convention of “if {Cond} …” (he used “if(Cond) …”) seems to make his code samples work.

Here’s a more friendly guide to getting this awesome code to work. Skip to “code samples” below for awesome examples of this embedded language in action.

My system setup

I am running Ubuntu Hardy with SWI-Prolog 5.6.47; I installed SWI-Prolog straight from the Debian packages (through Synaptic, the usual way). Just get yourself a copy of Ubuntu and install SWI Prolog the sane way and this code should work.

The interpreter

change_member(_, N, [], [N]).
change_member(O, N, [O|XS], [N|XS]).
change_member(O, N, [X|XS], [X|YS]) :- change_member(O, N, XS, YS).

:- op(900, xfy, :=).
:- op(100, fx, [if]).
:- op(125, fx, [while,  return]).
:- op(125, yfx, [do, then, else]).

run({Block},                          EnvI, O, Ret) :-
  run(Block, EnvI, O, Ret).

run((First; Second),                  EnvI, O, Ret) :-
  run(First, EnvI, M, _), run(Second, M, O, Ret).

run(Place := Expr,                    EnvI, O, void) :-
  eval(Expr, Value, EnvI), change_member(Place = _, Place = Value, EnvI, O), !.

run(if {Cond} then {This} else {That}, EnvI, O, Ret) :-
  eval(Cond, Value, EnvI),
  ( Value = true -> Body = This ; Body = That ),
  run(Body, EnvI, O, Ret).

run(while(Cond) do {Body},            EnvI, O, Ret) :-
  eval(Cond, Value, EnvI),
  ( Value = true -> run(Body, EnvI, M, _),
                    run(while(Cond) do {Body}, M, O, Ret)
  ; O = EnvI, Ret = void
  ).

run(return Value,                     EnvI, O, Ret) :-
  eval(Value, Ret, EnvI), O = EnvI.

eval(Var,   Val,   Env) :- member(Var = Val, Env), !.
eval(Num,   Num,   _  ) :- number(Num), !.
eval(true,  true,  _  ).
eval(false, false, _  ).

eval(X + Y, Z, Env) :- eval(X, XV, Env), eval(Y, YV, Env), Z is XV + YV.
eval(X - Y, Z, Env) :- eval(X, XV, Env), eval(Y, YV, Env), Z is XV - YV.
eval(X * Y, Z, Env) :- eval(X, XV, Env), eval(Y, YV, Env), Z is XV * YV.
eval(X / Y, Z, Env) :- eval(X, XV, Env), eval(Y, YV, Env), Z is truncate(XV / YV).

eval(X = Y, B, Env) :- eval(X, XV, Env), eval(Y, YV, Env),
  ( XV = YV -> B = true ; B = false ).
eval(X < Y, B, Env) :- eval(X, XV, Env), eval(Y, YV, Env),
  ( XV < YV -> B = true ; B = false ).
eval(X > Y, B, Env) :- eval(X, XV, Env), eval(Y, YV, Env),
  ( XV > YV -> B = true ; B = false ).
eval(not(P), B, Env) :- eval(P, PV, Env),
  ( PV = true -> B = false ; B = true ).

Language samples

Here are samples of using this little embedded language we’ve built along with the evaluation results in comments.

factorial(N, {i := 1;
              n := N;
              while(n > 0) do {
                i := i * n;
                n := n - 1
              };
              return i}).

%% ?- factorial(5, P), run(P, [], _, X).

%% X = 120

fibonacci(F, {i := 1; a := 1; b := 1;
              while(not(i = F)) do {
                a := a + b;
                b := a - b;
                i := i + 1
              };
              return b}).

%% ?- fibonacci(7, P), run(P, [], _, X).

%% X = 13

pow2(N, {i := N;
         n := 1;
         while(not(i = 0)) do {
           i := i - 1;
           n := n * 2
         };
         return n}).

%% ?- pow2(8, P), run(P, [], _, X).

%% X = 256

gcd(X, Y,
    {x := X;
     y := Y;
     while(not(x = 0)) do {
       if {x < y} then {
         y := y - x
       }
       else {
         x := x - y
       }
     };
     return y}).

%% ?- A is 2*2*5*7*13, B is 5*13*7*7, gcd(A, B, P), run(P, [], _, X).

%% A = 1820,
%% B = 3185,
%% X = 455

isqrt(N, {q := N; p := (q + N / q) / 2;
          while(q > p) do {
            q := p;
            p := (q + N / q) / 2
          };
          return p}).

%% ?- isqrt(81, P), run(P, [], _, X).

%% X = 9

Discussion

As best I can tell this actually works. For instance, evaluating our Fibonacci function at 150 gives the correct value, spitting back 9969216677189303386214405760200 as should be the case. Notice how, therefore, we get, among many other things, SWI-Prolog’s built-in arbitrary-precision integers for free — a classic example of why embedded domain-specific languages are such a huge win.

The implementation depends heavily on Prolog’s excellent support for custom symbolic operators and pattern matching abilities, even tolerating added bits of syntactic sugar like the brackets used to delimit boolean conditions in our if-then-else blocks.

Obviously you wouldn’t want to use an interpreter this trivial for serious production/mission-critical stuff, but I think it definitely provides a compelling answer to how far a computer language could conceivably be extended to support new syntax. Languages that claim to support language-oriented programming, but don’t support custom operators with custom fixity and precedence — you’re on notice.

September 18, 2008

Quote of the Day: Victor Hugo on nihilism

Filed under: QOTD — metacircular @ 3:34 pm

With nihilism, no discussion is possible; for the nihilist logic doubts the existence of its interlocutor, and is not quite sure that it exists itself.

— Victor Hugo in Les Miserables

September 17, 2008

Quote of the day

Filed under: Life — metacircular @ 11:23 am

The dullest person becomes interesting if you feel that he is really himself, that he is not holding up some absurd shield or other in front of his shivering soul.

—Arthur Christopher Benson in The Upton Letters.

September 13, 2008

Experimenting with Prolog

Filed under: In the beginning, Prolog — metacircular @ 12:13 am

Here’s some hypothetical ActiveRecord-like application metadata for a blog-like application along with a utility function for querying such metadata.


:- op(500, fx, many).
:- op(500, fx, one).
:- op(600, fx, always).
:- op(600, xf, notnull).

:- op(500, fx, at_least).
:- op(500, fx, at_most).
:- op(500, fx, exactly).

model(post,
      title(length(at_least 10)) notnull,
      many tags(name),
      always one author(name notnull, email(email_addr), url(url)),
      body(memo),
      many comments,
      chronological).

model(comment,
      name,
      email(validate_regex("\w+ blah blah line noise here")),
      ip(ip_addr),
      body(memo),
      nonenull,
      chronological).

get_predicate_instances(Predicate, Instance) :-
        between(1, 255, Arity),
        functor(Instance, Predicate, Arity),
        predicate_property(Instance, interpreted),
        call(Instance).

get_predicate_instances allows us to query all instances of a predicate without needing to restrict their arity by enclosing things in lists. Query facilities like it would allow you to place fewer restrictions on what kind of input a user can provide when describing an application.

The point is, if you create a domain-specific metadata language, Prolog can slice and dice it quite nicely. No XML required, no search/traversal boilerplate.

Designing a system like this in a vacuum would be a mistake; I was just toying with postfix and prefix operators more than anything else. What we need is an application we can use every day to drive the development of a system like this.

September 6, 2008

HOWTO: Get the scroll wheel working on Linux under VMWare with Logitech MX518 mouse

Filed under: Lunix — metacircular @ 6:03 pm

This is just for my own reference.

I am running Ubuntu Hardy under VMWare Workstation. This should let you scroll webpages in Firefox. The back/forward buttons still don’t work, though.

Instructions to get scroll wheel working

  1. Open up a terminal window and type the following:

    sudo gedit /etc/X11/xorg.conf

  2. Find the section that says Section “InputDevice”.
  3. Replace that section with the following:
    
    Section "InputDevice"
    	Identifier	"Configured Mouse"
    	Driver		"vmmouse"
    	Option		"CorePointer"
    	Option		"Protocol"	"ImPS/2"
    	Option		"Device"	"/dev/input/mice"
    	Option		"ZAxisMapping"	"4 5"
    EndSection
    
  4. Restart X Windows by typing Ctrl+Alt+Backspace. Log in and the scroll wheel should work.

Good luck!

September 4, 2008

Enjoy the power of Linux from the safety of Windows with VMWare

Filed under: Lunix, Prolog, The Dark Side, Virtualization — metacircular @ 11:10 pm

I’ve been a fan of Linux for a very long time. I’ve sworn off Windows at least a dozen times — but each time I came crawling back, because there was always something I couldn’t figure out how to configure or get to work: in the past it was usually printing, video, audio, or multimedia-related.

With the rise of Ubuntu, most of those things just work by default. But still, having to give up Windows gaming, Photoshop, and other proprietary crap I can’t kick the habit of will always force me to keep Windows installed. I think this is the best of both worlds: I have Ubuntu running under VMWare Workstation running on one monitor (at 1680×1050, too, thanks to VMWare Tools) and Windows on the other. I can, for instance, do web development on the Linux screen and test it on Safari, Google Chrome, Firefox and Internet Explorer in Windows.

In the screenshot above you can see me drafting this post in Windows on Chrome while listening to crappy dance music in iTunes and, meanwhile, tinkering with Emacs, git and Prolog under Linux. Good times.

This way, I can make use of both monitors without having to figure out Xinerama or tinkering with stupid drivers in order to make use of my video card in Linux. It takes away a lot of the hassle and if you’ve been wanting to try an alternative operating system but haven’t been able to move out, this is a good compromise.

June 7, 2008

Imitating Ruby’s anonymous hashes in VB.NET

Filed under: Uncategorized — metacircular @ 10:13 pm

Module Program
    Sub PrintObj(ByVal obj As Object)
        Try
            Console.WriteLine(obj.B)
        Catch ex As MissingMemberException
            ' Do something appropriate here
        End Try
    End Sub

    Sub Main()
        PrintObj(New With {.A = 1, .B = eh})

    End Sub
End Module

Except here we’re passing in an anonymous object where one of the members is XML, something you can’t do in Ruby.

This seems like a reasonable workaround to VB.Net’s infuriating lack of collection initializers if you’re willing to give up type safety, I suppose.

February 25, 2008

What users want: porn, music, and video games

Filed under: Uncategorized — metacircular @ 10:41 am

Let’s get things nice and sparkling clear about what users want.

They want to download torrents of the latest episodes of their favorite TV shows. This is why torrent and P2P clients have billions of downloads. They want the utilities they need to watch, compress, decompress, and transfer around their media. This is why codec packs and utilities like WinZip have hundreds of millions of downloads. They want to keep their machines reasonably free of spyware. This is why applications like AdAware have hundreds of millions of downloads.

They want to communicate with their friends, be it through instant messaging, social networking websites, or whatever.

They do not give a shit about your blog or your productivity/organizational application (they don’t care about this blog or the little project I’m working on on the side, in particular). They won’t give a shit about it, anyway, unless you have an unusual angle, like Perez Hilton where you can get an eyeful just by scrolling, and without reading or taking the time to appreciate all the hard work the site’s creator puts in.

If you’re going to talk about what users want, look at how they’ve voted with their mice clicks: AdAware and celebrity gossip is in, Web 2.0 is out, not that it was ever in.

Maybe this is an indication that just because millions of people want something doesn’t mean that it has any intrinsic worth, eh?

Maybe spending your precious spare time on something that’s really tedious and difficult isn’t a good idea just because millions of dumb IE 6 users want it. Maybe, instead, you should spend your time on what you enjoy and value.

What you do to pay the bills or make your clients happy is a completely separate matter: you’re probably going to be logging quite a bit of time in Firebug because that’s quite possibly the most pragmatic way to do an application 5,000 people in a large corporation are going to use.

But when you finish the work day and you want to create excellent software for yourself, where you get to do the things your clients won’t let you do, why would you willingly make a Pentium 4 feel like a 386 with JavaScript hacks?

February 4, 2008

Web applications suck and they’re not worth creating

Filed under: Blasphemy — metacircular @ 10:28 pm

It’s a simple fact that complex web applications are almost impossible to create. This constrains you to making simple apps, which is often a good thing, but if the problem domain you happen to be in genuinely deserves deep exploration over time, you’ll quickly be fighting your deployment medium instead of working with it.

If you want a WYSIWYG editor roughly on par with the rich text box controls that give you about as much formatting oomph as Wordpad along with simple spellchecking of the kind that Firefox uses to tells me that “Wordpad” is incorrectly spelled as I type this, be prepared to spend several months to a year to get a production-ready version of it, the way Fog Creek did. That’s with FogCreek-level people on the job.

If you want a very nice, elegant calendar of the kind paying Backpack accounts do, be prepared to spend 2-3 months the way 37Signals did, and that’s if your coding chops are on par with DHH and the people who created scriptaculous and Prototype.

At least, if you want to achieve Internet Explorer 6 compatibility.

What chance do us po-faced mediocre daycoder fucks have? Fuck! We’re still trying to pretend Unicode doesn’t exist.

And then you have to host this. Once you grow big, you will need a full time system administrator to manage all of this, the way Fog Creek and 37Signals both do.

The unfortunate truth is that with a few minutes of point and clicking and a few more minutes of hacking in Visual Studio, I can create desktop apps with features that are a real pain in the ass to replicate in web apps. And your version will be on its way to being a big cumbersome JavaScript hack that takes so long to load it feels like a bloated desktop app. Irony.

Nothing to install, you say. From the perspective of someone who makes old-fashioned intranet client-server apps during the day and codes in their spare time and stands to make $0 off the software they produce from this, I don’t give a shit. I only work on the things I like, which it turns out almost no one else likes. You may actually discover that your customers actually want to host the software themselves, even though it’s a web app, in which case you have to do terrible things to make your dorkus malorkus customers happy.

I like applications that are fast (they do my 2 GB Core 2 Quad machine justice), that are available whenever I’m at my computer, and give me as much storage space as I can stick hard drives into my machine (on the order of a terabyte or so).

Can you imagine any web service anywhere giving you a terabyte of hard drive space, and actually delivering it? Even GOOG only gives you 2 gigs.

Getting back to complex apps, there’s a certain fundamental attribute of applications you live in, like email clients, web browsers, spreadsheets, text editors, IDEs, and other things that a lot of professionals get paid good money to spend all day in: extensibility, at multiple levels. Firefox has GreaseMonkey, Firebug, AdBlock Plus, and other wonderful things. Excel has VBA as well as a C/C++ API. Investment bankers live in their macros from what I hear.

Where is the web app equivalent of this? It’s some smug Danish cunt telling you you don’t need those things. That’s a copout and it’s a bunch of bullshit.

But there are tons of boring data-driven business apps that really ought to be web apps, you say. You are absolutely correct. By all means, the web is the default destination for heavily data-driven apps that involve a lot of simple data interactions and don’t require extensibility, realtime responsiveness (Ajax/Comet are not realtime), keyboard shortcuts and other power user features, and other lovely desktop things.

My point is this: my desktop apps leave your web apps in the fucking dust when it comes to the things that make performance-minded nerds happy. I will never create the next MySpace or Google. I don’t give a shit; I’d rather create the next uTorrent.

January 29, 2008

Paul Graham to programming community: fuck non-English speakers and web standards

Filed under: Uncategorized — metacircular @ 5:53 pm

Arc is finally out.

Choice excerpts:

I don’t want to spend even one day dealing with character sets. Character sets are a black hole. I realize that supporting only Ascii is uninternational to a point that’s almost offensive, like calling Beijing Peking, or Roma Rome (hmm, wait a minute). But the kind of people who would be offended by that wouldn’t like Arc anyway.

Apparently the only people who like Arc are people who use toy software that only they and their friends use. And none of them speak a language requiring a non-Latin character set.

Because Arc is tuned for exploratory programming, and the W3C-approved way of doing things represents the opposite spirit.

Durrrr, designing like it’s 1997 is great, because that’s the last time I learned anything new!

One is always a bit sheepish about writing quick and dirty programs. And yet some, if not most, of the best programs began that way.

On the Internet, you can make whatever claims you want without the need to ever provide evidence or facts. And if you disagree, you’re a moron who doesn’t understand closures or exploratory programming.

Nevertheless, I enjoyed my time with SLIME and SBCL during college, so I’ll try to give Arc a look one of these days. Maybe when it’s not so racist and has a cool app implemented in it.

Next Page »

Blog at WordPress.com.