Technology Philosophy

Posted by Daniel Lyons Mon, 06 Oct 2008 16:40:00 GMT

I’ve been playing with Plan 9 again. It’s interesting technology, sure, but more interesting to me as a statement of philosophy. Let’s take the Unix philosophy about files and really extend it into the network, rewrite everything to use or serve files via 9P. What you wind up with is a network operating system, in the sense that everything you’re using might be networked. It’s also a statement about programming, that the best way to deal with data is as flat files of binary data, and that as far as programming languages go, C is just fine.

I’m not sure I agree with those last two points, but one wonders whether or not they could be changed without ruining the system. How many of any system’s warts are cosmetic, and how many of them are fundamental? Apparently the developers of Plan 9 felt that some of the warts were cosmetic, so they made Inferno, which replaces the language with Limbo (still a curly-brace language, but a more featureful one) and insinuates a virtual machine as the underpinning of a hypothetical operating system. And basically, it works like Plan 9.

Some of the great ideas about Plan 9 were so simple and great they’re winding up in other places. You can get 9P for Ruby, for Lisp, for a host of other languages. They’ve ported Plan 9’s userspace utilities to other operating systems, including Mac OS X and Linux. And you can run Inferno on a number of platforms. So you don’t need to be “locked in” to Plan 9 to use most of the power of Plan 9.

Sometimes I have to wonder if there is something good about the lock-in. Somebody called “jfm3” posts about this, citing this concept Done is Better as an alternative interpretation of Worse is Better. Most technology contains within it the wish that all of computing be seen afresh, refracted and reassembled through it. Lisp, Plan 9 and XML all contain that wish, that maybe systems built from the ground up with them would be more excellent, more transparent, more hackable, less bullshitty. But somehow, in the practical world of commerce, we always wind up with these heterogeneous systems. We mind the thought of storing all our data in XML, but we don’t mind serving it out over REST. We mind the thought of switching to Lisp for everything, but we don’t mind simplified macros. We mind the thought of dealing with Haskell for everything, but we don’t mind bringing map and fold into our everyday languages.

I think there is a moment with many technologies where they become recursively complete. I’m sure there’s a more mathematically correct term for what I’m referring to. With Matterform’s Voltaire, that moment came when we had given extensions access to the whole core, which was just three basic systems. Lisp’s REPL is a better example: between those three functions read, eval and print, there’s nothing left to expose. With Plan 9, the kernel doesn’t have to do a whole lot, mainly it has to multiplex access to 9P and provide the initial bootup. The way you recognize one of these systems is that you keep running into the same metaphors over and over again—you don’t wind up having to create totally new abstractions from scratch. The initial abstractions are simple yet powerful enough to see you through extremely diverse unforeseen circumstances.

So I have to wonder what it is about these systems that we find so attractive and so repulsive at the same time. Is it merely the amount of work it would take to, say, port Mozilla and other applications over? Or does it go deeper, that we just distrust homogeneous systems? Do we desire some funk? It’s not hard to look at Vim or Emacs versus Acme and say, these are extremist positions regarding the keyboard and the mouse, respectively. Does that mean we will always prefer editors like DreamWeaver, TextMate, Eclipse and so forth, that make poor use of both instruments? Do I really prefer the limitations of TextMate, or just the aesthetics? Are the aesthetics really so powerful they can trump technology—even among academics and researchers?

I’m pretty sure that even if Plan 9 had replaced Linux, I’d be annoyed by it, but I still have to wonder. So much of our current technology seems unquestioned. Only tiny changes seem to stick.

Tags , , , , , ,  | no comments

Migrating from Typo to Webby

Posted by Daniel Lyons Thu, 18 Sep 2008 16:10:00 GMT

Without realtime preview, I don’t have much reason to put up with the resource usage of Typo. I recently looked into Webby and like it quite a bit, especially because of its integration with source code highlighters, which are a major issue on my site.

I won’t be able to do comments unless I use a service like Disqus. I’m going to try really hard to care. See this? I’m trying really hard… I give up. It isn’t working. So yeah, I don’t care. 90% of you are already my friends, so just email me and maybe I’ll include your commentary. I delete most of your comments anyway, as I’m sure you’ve noticed.

Unless Reid decides to make me a web design for no particular reason it’s probably going to look a lot like the new xmonad design, because I think it’s really hot. Nowhere near as awesome as something Reid might make though. Hint hint.

So, if you’re trying to convert your Typo site to the state-of-the-art in statically generated content, you might want to follow my instructions:

  1. Put this into a file migrate.rb in your Typo install:
    class Article
        def migrate_to_webby        
            # get the YAML header
            attrs = self.attributes.slice('title','keywords','created_at')
            if keywords then attrs['keywords'] = keywords.split(',') end
            attrs['filters'] = 'textile'
    
            # make the destination directory
            dir = created_at.strftime('blog/%Y/%m/%d/')
            FileUtils.mkdir_p dir
    
            # status message
            puts "migrating #{title} to #{dir}#{permalink}.txt" 
    
            # dump the info out to the file
            File.open(dir + permalink + '.txt', 'w') do |f|
                f.write attrs.to_yaml
                f.write "---\n" 
                f.write body
            end
        end
    end
  2. Run this: script/console production
  3. Type this in:
    load 'migrate.rb'
    Article.find(:all, :conditions => {:published => true}).each {|a| a.migrate_to_webby }

A couple things you should note:

  1. Notice I hardcoded the format. You might have to fix that.
  2. I left out the author because I wrote all my own blog posts.
  3. I didn’t migrate any of the comments (oops? not really)
  4. I didn’t get any of the non-published content.

Still, if it’s any help to you, there it is. When I migrate the blog to Webby I might go through and change that to highlight the syntax.

Film at 11.

Tags , ,  | 1 comment

Technology/Bureaucracy Impedance Mismatch

Posted by Daniel Lyons Tue, 16 Sep 2008 19:15:00 GMT

People often talk about the relational/OOP impedance mismatch. There’s another one, the technology/bureaucracy impedance mismatch.

When we, the technologists, show up to solve a problem, we’re interested in modeling the problem domain and working out a good database, user interface, and set of functionality to accurately capture, simplify and streamline a given process. We try very hard to come up with a design that directs the user to the information they need and make it easy for them to do whatever it is they need to do. For example, if they need to make a selection, we’re going to use a combo box. The form will validate what they’re doing and ensure that the data coming in is very high quality.

The purpose of bureaucracy, as Reid put it, is to manage people’s inefficiency. If users of your bureaucracy aren’t able to accomplish their tasks, the bureaucratic solution is training, supervision, and more paperwork. Even if the problem is the paperwork you start with.

So when we arrive at a bureaucracy, the mismatch from our point of view is, we are being asked to model pointless tasks. Many of the processes we look at streamlining are intrinsically useless. There is no need to ask for certain pieces of information interactively; they can be looked up instead. The solutions to poor data quality in paperwork—repetition and redundancy—create inefficiency electronically, and reduce data quality in the process by giving opportunities for errors.

The perspective of the bureaucracy is also negative. Many tasks which would be trivial to automate, from their perspective, we are simply unwilling to automate. We have a very difficult time comprehending their desire for complex authorization schemes, largely because we know how easy they can be compromised. Bureaucracies are accustomed to the imperfections of systems and their own members; our perspective tends to be more black-and-white, seeing security as either perfect or worthless.

Bureaucracies do not shy away from complexity. In fact, they tend to get mired in it and produce more of it. Mutually exclusive rules can exist in a bureaucracy, because the rules are created and enforced by people—there is no program to determine whether or not the rules make sense. Bureaucrats find it annoying when we come back and say that modeling a process is impossible when they’ve been doing it fine for years. Our perspective on complexity is simply hatred; we’d rather model a simpler problem which is similar than a complex one. Indeed, we will spend great resources searching for a simpler one to avoid a complex one. (Unless we can involve another language, of course).

Bureaucracies are also extremely political. They get very involved in tracking people and their station on the hierarchy. Compare to almost all digital systems, which just have users and admins. The bureaucrat must ensure that every user of their system is aware of their relative stations. Bureaucracies work because every member in the group knows either who handles a particular problem or who will know this information. To them, this is a necessary feature to delegate work and ensure that questions get answered by the right people. To us, it is a giant, overly complicated system of maintaining people’s bragging rights over seniority.

It’ll be interesting to see which philosophy is more relevant at the end of the 21st century, if there is any change at all.

Tags , ,  | 3 comments

BarCamp Albuquerque

Posted by Daniel Lyons Mon, 15 Sep 2008 16:47:00 GMT

Where to begin? I was only there on Sunday, so I no doubt missed some great talks, but I want to tell you about two of the ones I saw on Sunday.

Jack Moffitt told us about his awesome startup, Chesspark which lets you see people playing and play others and chat completely interactively, using XMPP and BOSH. It’s hard for me to overemphasize this stuff. Marketing people would call this “game changing technology,” because that’s exactly what it is. It’s hard to imagine how Comet could defeat this, especially if you’re running ejabberd. If you want an interactive website that scales, this is precisely the technology you’re going to want.

Gabe Ortiz talked about his technology startup, Rarefied Technologies, making StupidFilter, which I’d actually read about on Reddit some months ago. Knowing how the technology works just makes me more impressed; he built it on Flex (as in Lex and Yacc, not Adobe) and libsvm. Amazing stuff! It never would have occurred to me to do NLP with Lex.

David Thomas spoke about monitoring networks, which was very interesting. And his son actually gave a talk on using Scratch, which I told Liz I’m going to get her on ASAP. :) (“Are you going to find a pair of glasses for me next?”)

All in all, I’m shocked and impressed at the quality of folk we have here in Albuquerque. Really hardcore, extremely motivated people working on interesting stuff locally. Who knew? My mind is racing with applications for the technology Jack showed us.

Very cool stuff!

Tags ,  | 1 comment

You Can Fit a Country Between Two Adjectives

Posted by Daniel Lyons Fri, 12 Sep 2008 21:03:00 GMT

Reid tells me about the lobster fishing industry. (It’s called fishing, even though the right word for it is trapping: they have cages, they trap lobsters in them.) While he was in Boston walking along the wharf, he and his father ran into a lobster fisherman. This fisherman informs him that 3/4ths of the lobsters they catch are underweight, so they get sent off to Canada to live in a lobster farm until they’re big enough. And this is true of all American lobster fishing. Lobsters, apparently, favor the colder clime.

So, while it’s true that your Fresh Maine Lobster is freshly caught, and while it’s true that it is originally from Maine, it’s quite likely that after the lobster was caught and before it was freshly, it lived in Canada for a while.

Fresh (Canadian-raised, originally from) Maine Lobster.

Tags ,  | 1 comment

Programming Is Language

Posted by Daniel Lyons Thu, 11 Sep 2008 14:46:00 GMT

I’m here to tell you that virtually all of programming is premature optimization.
Jonathan Edwards

This morning I remembered a cool program I had seen the other day, webby. I looked at it and I was thinking, maybe I’ll replace this blog with some kind of article serving website of my own construction, without commenting or trackbacks or any of that other crap I’m not really sure I like anyway. And then it would be more like a website and less like a blog, so when I occasionally write compelling content, it might actually stay up here for a while. I have often thought I would be happier if I had an RSS feed on top of some kind of categorized pile of essays. Plus, it would encourage me to write essay content instead of blog content, like I’m doing right now.

See, I have a bit of angst about this. The next version of the blog software I’m running, Typo, does not have the realtime preview functionality. I’m not sure why they decided to remove it (it’s one of the things I love most about Typo, dammit) but if I want to keep using Textile to run my blog I’m going to have to live with a publish/edit/publish/edit cycle. I’m already doing that somewhat, to fix typos and make sure it looks good enough, but I’d rather not become more dependent on it. And of course, they’re pushing TinyMCE on me. I hate TinyMCE.

Apart from that, in writing my company’s new product website I used Coda to edit the content. And, you know, it was really nice. Coda is a very good editor for the web, and it does a lot of book-keeping for me, it’s the kind of thing one would use DreamWeaver for if DreamWeaver didn’t suck so badly (apologies to Reid, my business partner, who uses DreamWeaver).

I’m staring at webby and thinking, this would be really cool, it would convert my problem back into a text problem. A programming problem. Compile your website.

This isn’t the first time someone had this idea. John Shipman, my mentor back at school also did this by writing webstyler “to reduce the drudgery of writing and maintaining webs.”

Of course, neither technology really guarantees you’re going to be writing compelling content. But it’s a pretty sure sign that a technology will help if it makes the task more fun. As much as it sucks, Typo 5.0.2 with the preview editor makes writing more fun for me, as does Coda, and I’m really not sure that webby would. Maybe. I might give it a try anyway. Since I’m not going to get live preview in Typo 5.1.

Have you noticed programmers often seem to convert your problem, whatever your problem might be, into a text/language problem? Back in the day, writing a GUI app was a huge headache. You had to code up where to draw everything, pixel by pixel. Widgets made it better, but it wasn’t until layout editors came around that it really became pretty doable. And yet, HTML + CSS takes the world by storm, converting the problem back into a language problem. Write your UI in HTML, so much less work because you don’t have to worry about the pixels. Then we’ll just write a giant stack of code to convert that into an interface, with the pixels.

Somehow, we just can’t seem to see the work that’s being done—both the work we’re writing code to do and the work we’re doing by actually writing that code—when we introduce another linguistic barrier. Perhaps Jonathan Edwards will have his revolution and the next generation of programmers won’t be as linguistically pre-occupied. Notice how little of the editor debates actually have anything to do with the aesthetic experience of editing the code. They all talk about power and speed and slimness and other attributes, but not the way it feels or looks. Unless you’re on a Mac.

I am wondering whether or not programming and language are one. I tend to think they are because of something I was taught in college. Some problems are concrete, because they have an encoding for input and output (anything on a computer). Some problems are decision problems, because they return true or false. Any problem can be made into a concrete decision problem by rewording it to accept a problem and a candidate solution and returning true or false. And every language is essentially a concrete decision problem: is this sentence in the language, yes or no?

It’s hard for me to overemphasize the role that this concept plays in my everyday thinking. Nevertheless, I am forced to ask myself whether or not my attachment to it is more mystical than scientific. I’m not sure I benefit from this thought tangibly. In fact sometimes I think I may be enslaved to this thought. Because if it affects all of computation and computer science without enlarging or reducing the set of possibilities, it’s hard to say what I gain. Would I gain from treating every problem as a compiler problem? It would probably make me feel better about it.

Any programmable system has a grammar and is thus a language. Even if the programming system ultimately was waving a magic wand or mixing potions. You could even say that a GUI is a programming system, the language is mouse clicks and key presses. Certainly not as automateable by default. This seems to mean that any human-computer interface is interchangeable, doesn’t it? Couldn’t I say that a programming language is a user interface? It is, isn’t it? Maybe API stands for application programmer interface rather than application programming interface.

So what difference does it make if I compile me websites and you edit yours in DreamWeaver? (Hey, at least Reid uses the code view and not the design view.) The answer, from a computational perspective is that there is absolutely no difference. Because the point of CS is to abstract things away to reason about it. But there is a very big difference in reality: enjoyment.

There aren’t going to be many users of webby who are not programmers. That’s fine, if that’s their aim. But let’s keep our bias in mind as we develop systems. We are bred to be linguistic. Users aren’t.

Tags , ,  | 1 comment

Glue

Posted by Daniel Lyons Mon, 25 Aug 2008 18:29:00 GMT

I think maybe what I love about Ruby is that it’s great for writing glue. And maybe what I hate about Ruby is that I’m tired of writing glue.

Tags ,  | 1 comment

Complexity and the Engine of Evaluation

Posted by Daniel Lyons Tue, 12 Aug 2008 17:23:00 GMT

So we find ourselves up against complexity itself, again.

Prolog, which I used the other day, is essentially abandoned. Paul Graham said it best:

“If high-level languages are better to program in than assembly language, then you might expect that the higher-level the language, the better. Ordinarily, yes, but not always. A language can be very abstract, but offer the wrong abstractions. I think this happens in Prolog, for example. It has fabulously powerful abstractions for solving about 2% of problems, and the rest of the time you’re bending over backwards to misuse these abstractions to write de facto Pascal programs.”—“Programming Languages Explained,” Hackers and Painters.

Interestingly, this is a problem Haskell shares a problem with Prolog: it’s very hard to control the order of evaluation. Of course, they both do what they can to ameliorate the situation. Prolog offers you the cut operator, and Haskell offers you quite a bit more: monads, do notation, unsafePerformIO, some interesting tracing functions, strictness annotations, etc. Will it be enough?

Consider the people using C++; some use just the templates, others use it as C, some try to use it as an OOP language. The language encompasses all of these communities. Natural languages are vast for the same reason. Is this a positive attribute? Does it take a complex programming language to have a large and thriving community? Recent examples seem to indicate so.

One problem with Prolog is that, apart from the novel evaluation mechanism, there isn’t a whole lot to recommend it. You get most of the same features in Lisp, but LIsp has a lot more other features. And, as Paul Graham and Peter Norvig attest, it’s famously easy to implement the unification algorithm in Lisp: have you cake and eat it too.

Haskell has a lot more than just laziness going for it. It’s the flagship of the FP world. The type system is shockingly impressive and fairly complicated by itself. You could have that without the laziness. Haskell has more than one appeal. No wonder its audience is larger and expanding. These days we expect languages to implement themselves. Imagine what it would be like to implement Prolog in Prolog, versus Haskell in Haskell.

Look at cool term rewriting systems, of which there are really only two worth talking about (Pure and its ancestor Q). They certainly have their appeal. But this also boils down to a fundamentally different engine of computation. Declarative logic programming seems to have found a niche in database querying and occasionally template expansion (XSLT). What will term rewriting’s niche be?

I’m not sure what people really want, or what I want. We seem to be pretty happy with a procedural view of things, with the occasional departure into declarative-land when querying databases and the occasional departure into functional-land when dealing with collections. We like polymorphism, we like sharing code, but this-then-that seems to be the only evaluation strategy we like. So we see laziness as libraries or corner cases for lots of languages—Lisp has SERIES, Q and many Schemes have lazy lists but very few people use Haskell or lazy Scheme. The story is the same for parallelism. People using Erlang make lots of use of it. Everyone else does not. But people seldom think to use Erlang to solve their problems, thinking they don’t need to the parallel features to solve a problem, preferring their native tools.

There is a sense that learning and then using an obscure language like Prolog to solve a tiny problem somehow adds complexity before you even start. Is that true? If only complexity could be quantified. It’s true that the I/O in my last post’s code was ungainly and a little gross, but it wasn’t especially complex. A lot of people would have stuck to the language they know, Ruby for example, and implemented a whole search method in it. Is that better or worse?

There’s something repugnant about these questions. Why are languages so hard to interface without becoming soulless CLR/JVM parasites or tiny portals sending and receiving strings? Why is it so hard to have a polyglot system? Yet, on the web we have a very pluralistic society down to the technology level, yet all the options in all their diversity suck?

Tags  | 2 comments

Prolog

Posted by Daniel Lyons Mon, 11 Aug 2008 18:01:00 GMT

There’s a wanker who keeps popping up on my blog and commanding me to do the I/O part of my Prolog programs. Coincidentally, Justin Dressel just popped up and asked me to solve a problem with him, he’s talking about doing it in Haskell while his girlfriend Darcey does it in Java (can you believe it?)

Have you played the game where you're given 4 numbers, 
and you have to form the number 10 out of them via any 
combination of +, -, *, or /?

e.g. 1, 2, 3, 4 -> (4*2)+(3-1)

Boy, does that sound like a Prolog program or what?

First let’s handle one term.

% solve two terms for a third
solve2(X, Y, Z, Op) :- Z is X + Y, Op = '+'.
solve2(X, Y, Z, Op) :- Z is X - Y, Op = '-'.
solve2(X, Y, Z, Op) :- Z is X * Y, Op = '*'.
solve2(X, Y, Z, Op) :- Z is X / Y, Op = '/'.

If I use it, I get this kind of thing back:

?- solve2(4, 2, 6, Op).
Op = + ;
fail.

?- solve2(4, 2, 8, Op).
Op = * ;
fail.

Great. Now let’s get the whole enchilada:

% solve four terms for three operators, given a certain result
solve4(A, B, C, D, Result, Op1, Op2, Op3) :-
    solve2(A, B, X1, Op1),
    solve2(X1, C, X2, Op2),
    solve2(X2, D, Result, Op3).

All I’ve done here is created some variables X1 and X2 which are just placeholders for intermediate values. I don’t do anything with their value other than stitch together Prolog’s calculations with them. I keep all of the operators and pass them out. The result is passed in, that’s our constraint. For example, we can try this on our original problem statement:

?- solve4(1,2,3,4,10,Op1,Op2,Op3).
Op1 = +,
Op2 = +,
Op3 = + ;
Op1 = *,
Op2 = *,
Op3 = + ;
fail.

So, Prolog is telling us we can get the result we want by doing ((1 + 2) + 3) + 4 or ((1 * 2) * 3) + 4.

Obviously, this isn’t all of the answers, nor is it particularly readable. I don’t want to have to worry about other operator groupings (which would be hard) when I can just reorder the input. And, to appease tndalpaul@yahoo.com, let’s do some I/O.

% solve([A, B, C, D], E), outputs the result
solve(Four, Result) :-
    permutation(Four, [A,B,C,D]),
    solve4(A, B, C, D, Result, Op1, Op2, Op3),

    % I/O
    write('(('), write(A), write(' '), write(Op1), write(' '), write(B), write(') '), 
    write(Op2), write(' '), write(C), write(') '), write(Op3), write(' '), 
    write(D), write(' = '), write(Result), nl,

    % try the next one
    fail.
solve(Four, Result) :- true.

I’m using a peculiarly Prolog style of looping here, called failure-driven iteration. The top of solve/2 gets a list permutation and a solution, then it does an action that produces a side-effect: it prints out the state of the world. Then, I fail explicitly. Without a cut, Prolog backs up to the last choice-point and tries again. solve4/8 has several choice points, because there are many solutions, so it produces the next one if it can, or else it fails. If it produces another result, we go back through the I/O and then fail again. This will repeat until solve4/8 has no more solutions with this set of input. Then Prolog will back up to permutation and get another list permutation and resume the computation.

When all the permutations and all of the solutions have been enumerated and we fail that last time, Prolog backs up and searches for another solution to solve/2. There is one, which is just true, but because it is the second predicate, it only occurs after the first one. This terminates the loop.

The I/O which I’m complaining about is the giant pile of write() calls there. In Ruby, this would look like this:

puts "((#{A} #{Op1} #{B}) #{Op2} #{C}) #{Op3} #{D}"

Compare: one line with one template-looking string to three lines of horrid Prolog. Is there a better way? If so, please leave it in the comments.

So, finally, this is the output:

?- solve([1,2,3,4],10).
((1 + 2) + 3) + 4 = 10
((1 * 2) * 3) + 4 = 10
((2 + 1) + 3) + 4 = 10
((2 * 1) * 3) + 4 = 10
((2 / 1) * 3) + 4 = 10
((2 + 3) + 1) + 4 = 10
((2 * 3) * 1) + 4 = 10
((2 * 3) / 1) + 4 = 10
((2 + 3) + 4) + 1 = 10
((2 * 3) + 4) * 1 = 10
((2 * 3) + 4) / 1 = 10
((1 + 3) + 2) + 4 = 10
((1 * 3) * 2) + 4 = 10
((3 + 1) + 2) + 4 = 10
((3 * 1) * 2) + 4 = 10
((3 / 1) * 2) + 4 = 10
((3 + 2) + 1) + 4 = 10
((3 * 2) * 1) + 4 = 10
((3 * 2) / 1) + 4 = 10
((3 + 2) + 4) + 1 = 10
((3 * 2) + 4) * 1 = 10
((3 * 2) + 4) / 1 = 10
((1 + 3) + 4) + 2 = 10
((1 * 3) * 4) - 2 = 10
((3 + 1) + 4) + 2 = 10
((3 - 1) * 4) + 2 = 10
((3 * 1) * 4) - 2 = 10
((3 / 1) * 4) - 2 = 10
((3 + 4) + 1) + 2 = 10
((3 * 4) * 1) - 2 = 10
((3 * 4) / 1) - 2 = 10
((3 + 4) + 2) + 1 = 10
((3 * 4) - 2) * 1 = 10
((3 * 4) - 2) / 1 = 10
((1 + 2) + 4) + 3 = 10
((2 + 1) + 4) + 3 = 10
((2 + 4) + 1) + 3 = 10
((2 * 4) - 1) + 3 = 10
((2 + 4) + 3) + 1 = 10
((2 * 4) + 3) - 1 = 10
((1 + 4) + 2) + 3 = 10
((4 + 1) + 2) + 3 = 10
((4 + 2) + 1) + 3 = 10
((4 * 2) - 1) + 3 = 10
((4 + 2) + 3) + 1 = 10
((4 * 2) + 3) - 1 = 10
((1 + 4) + 3) + 2 = 10
((1 * 4) * 3) - 2 = 10
((4 + 1) + 3) + 2 = 10
((4 * 1) * 3) - 2 = 10
((4 / 1) * 3) - 2 = 10
((4 + 3) + 1) + 2 = 10
((4 * 3) * 1) - 2 = 10
((4 * 3) / 1) - 2 = 10
((4 + 3) + 2) + 1 = 10
((4 * 3) - 2) * 1 = 10
((4 * 3) - 2) / 1 = 10
true.

Edit: Here are a few exercises for intrepid readers:

  1. Show that there are answers my program does not produce, and modify my program to produce them.
  2. Modify my program to not produce only unique answers.

Tags  | 2 comments

tndalpaul@yahoo.com

Posted by Daniel Lyons Sun, 03 Aug 2008 22:21:00 GMT

Leave an email address that works so I can reply to you. Your yahoo one bounces.

Tags  | no comments

Older posts: 1 2 3 ... 45