REBOL is pretty weird. It clearly owes a lot to LISP and to some extent Smalltalk in its underpinnings. Code and data both come grouped into “blocks” which behave like mutable arrays by default, and can be coerced into being lists or hashes. It has first-class functions, but it doesn’t seem to encourage a very functional style in general. It has objects, but once again doesn’t really push them. What I found most notable though were the unique syntax features.

It has an incredibly rich set of built-in datatypes, including URIs, filesystem paths, dates, money, email addresses, and more. A part of me quails a bit at the thought of parsing all these, but it actually highlights how silly it is that these highly standardized formats are treated as raw strings, that must be parsed at runtime, in every other language. Especially in languages which consider themselves statically typed. I wish my problem domain had afforded more of an opportunity to try these out.

Slash (/) is used as the “refinement” operator. Applied to a function, it alters the meaning of the function in some way, possibly requiring new arguments, very similar to how command line flags alter the action of a program invocation in unix. Applied to a an object, it accesses members. Applied with a literal number to a data block, it’s an index operator. For file paths, it descends. Etc.

It claims to be easier to learn if you’re not already a programmer. I tend to be skeptical of such claims, or at least skeptical that such a language is actually better-suited to the non-programmer-but-technical crowd (mostly scientists and engineers, I figure) that uses them. This one might have a claim to it, but it does seem like it could have kept all the features that make it interesting without diverging as wildly. But I have too many lines logged as a programmer to be able to evaluate that claim properly.

Next time I have a very network-oriented scripting task, I may give REBOL a shot. If it had an Open Source license, I’d consider it for more than that.

The code (written for version 2.7.7):

#!/usr/bin/env rebol -q REBOL [] player: 'X board: [1 2 3 4 5 6 7 8 9] cell2string: func [cell] [ either integer? cell [ join "(" [cell ")"] ] [ join " " [cell " "] ] ] print_board: does [ repr: [] clear repr for row 0 6 3 [ for col 1 3 1 [ append repr cell2string pick board (row + col) append repr either col < 3 [ "|" ][ "^/" ] ] if row < 6 [ append repr "---+---+---^/" ] ] print join "^/" repr ] make_move: func [space] [ if (pick board space) == space [poke board space player] ] cells_equal: func [value spaces] [ foreach space spaces [ if value pick board space [return false] ] return true ] winner?: does [ p: other_player if any [ cells_equal p [ 1 2 3 ] cells_equal p [ 4 5 6 ] cells_equal p [ 7 8 9 ] cells_equal p [ 1 4 7 ] cells_equal p [ 2 5 8 ] cells_equal p [ 3 6 9 ] cells_equal p [ 1 5 9 ] cells_equal p [ 3 5 7 ] ] [ player: p true ] ] tie?: does [ foreach cell board [ if integer? cell [return false] ] return true ] prompt: does [ case [ winner? [(print [player "Wins!"]) break] tie? [(print "It's a Draw!") break] true [ prin join "Select a square, " [player ": "] ] ] ] other_player: does [ either player = 'X ['O]['X] ] forever [ print_board prompt move: to-integer input if (make_move move) [player: other_player] ]