Playing with expressing INTENT in REBOL
January 7th, 2009Intent, Intent.. I started thinking about this word when coding in Factor, and I coded a lot of factor lately. Cleave combinators are used to express intent.
Today I was improving the quality and robustness of my rebol crawlers. I deepened my knowledge in REBOL a little in this time too. Even though REBOL was one of the first languages I learned many years back I only recently become aware and amazed of it’s very interesting core language abilities. It has a lot of those but this time I mean the “code is data” aspect or maybe the lisp-ness of REBOL.
A bunch of OR-s
I collect a bunch of separate values from parsing multiple pages and at some moment I have to check them if any of them is empty and report an error in that case. This is not usually the case at my coding because if I have so many values to operate on I usually “get” them in some assoc. and I can operate on them as a whole. Well here this was not the case.
So the normal way would be to stick them with OR-s like this:
if (empty? d-y) OR (empty? d-m) OR (empty? d-d) OR (empty? title) OR
(empty? category) OR (empty? ad/3) OR (empty? city) OR (empty? manuf)
OR (empty? descr)
[ print "Error some value is empty: " fail: true ]
But this is ugly as hell and it it doesn’t reflect our intent which is just: if any of them is empty [ do this ]. Well we are coding in REBOL remember? Which is a dynamic languge not something like python, php.. which are called dynamic mostly because they have dynamic typing
, so let’s get brave a little. Let’s make a simple two-line function any-is?
any-is?: func [ 'PRE s ] [ while [ not tail? s ] [ s: next insert s PRE ] any reduce head s ]
and now we can write:
if any-is? empty? [ d-y d-m d-d title category ad/3 city manuf descr ]
[ print "Error some value is empty: " fail: true ]
Value of word empty? is a function. Or to say it simple, empty? is just a regular function and we can use any native or user defined function in it's place. For example:
if any-is? positive? [ apples oranges kiwis grapes ]
[ print "There is some fruit in your fridge" ]
Ok, so it looks we can stick any 1 function with 1 parameter in there, but you can do more, because that word can also be a block:
if any-is? [ not empty? ] [ a b ] [ print "yup" ]
if any-is? [ 5 < ] [ num1 num2 ] [ print "yup" ]
if any-is? [ 5 < length? ] [ str1 str2 ] [ print "yup" ]
And of course you can use a closure to make special preset versions of the functions you need.
A series of operations on a variable
This one is a little unusual. I don't need to do this often, but here I have to deal with concrete messy special cases of certain portal to get the information clean. And I have to perform a bunch of functions on one value.
Now in something like javascript I would nest it, but in rebol this looks a little confusing and would maybe even not work without some parentheses.
title: trim/with replace fix-encodings clean-special ad/2 "utf-8" "(vec...)" "" "- "
I could add parentheses in more lisp-y manner, but it still doesn't look that good:
title: ( trim/with ( replace ( fix-encodings ( clean-special ad/2 ) "utf-8" ) "(vec...)" "" ) "- " )
I could make it look like a good old imperative program which is simplest to look at but I hate this too:
title: clean-special ad/2
title: fix-encodings title "utf-8"
title: replace title "(vec...)" ""
title: trim/with title "- "
So encouraged by being able to make any-is? in few minutes I decided to make a bite in this one too. So we want to calculate a value of title by doing a series of operations on a value:
calc-with: func [ 'wrd bs ] [ foreach b bs [ set wrd do b ] ]
Function is beautifully simple and this is how to use it:
title: calc-with X [ [ clean-special ad/2 ]
[ fix-encodings X ]
[ replace X "(vec...)" "" ]
[ trim/with X "- " ] ]
That is it. You can see that you can code up constructs in REBOL without any problem that would in most other languages belong under native predefined features of a language.
Some of it comes from "function is a first class value" which a lot of "modern" functional-y languages have (like JavaScript, Lua..), and enables them great flexibility. For example defining something like control structures via HOF-s, or custom OO-ish systems. But REBOL goes much much further than that. Not just function is a value, but also program code are just values, variable names are just values that you can operate on at run-time.
---
EDIT:
Steeve at REBOL Altme world proposed more optimal version of any-is?
any-is?: func ['fun data][
repeat _x_ data compose [if (fun) get _x_ [return true]] false
]
but this version of code can't accept literal values in block (not that I need them in my particular case).

![Reblog this post [with Zemanta]](http://img.zemanta.com/reblog_e.png?x-id=f8f35839-691a-4f15-a454-f6b8a880f255)