Many ways to skin a FAt CaT OR …

April 27th, 2008

Some people go to church on Sundays and some find time to divulge to the non-urgent ie. play with Factor a little. Well, I am not playing, I started making something concrete in Factor. Something that was cooking in my head for 6 whole years, and if no one made it in this time I might just step out and do it.

Well the concept is still not fully cooked, but I decided it’s time to stop boiling it and put it out on a pan and burn it a little and see what we get. So today I made few more words and a bunch of unit tests for it. Ok, so I am coding a very concrete thing in Factor for the first time. I like when I see that the Forth philosophy about re-FACTORing (yeah, hence the name I think) words to smaller and smaller independent words showed it’s beauty.

My main words with very rich functionality basically needed very very little stack shuffling ( just a dup, swap or over here and there - and I didn’t use cleave combinators) but then I came to one very simple utility word that because of few specifics used them noticeably more.

It was no problem to write but because Factor is so versatile I was sure there are other more elegant solutions. So I pasted that word on Factor’s paste and asked on IRC and so far I have 4 solutions that used very different concepts each, so I think it’s an interesting example of Factor.

This is my original, made in the “primitive” way with just stack shuffling… The code takes assoc. array, extracts/processes few values from it and leaves 3 values on stack. Basically very simple unimportant stuff…

: unpack-answer-to-me ( array -- type_subj answer id )
    "type" over at "subject" pick at " " prepend append
    "answer" pick at
    "id" roll at ;

#! Example of use..
{ { "type" "typ" } { "subject" "subj" } { "id" 12 } { "answer" "ans" } }
unpack-answer-to-me .s
! returns
"typ subj"
"ans"
12

Itvar on IRC came to this solution, he used locals. I think it’s much more readable than mine..

:: unpack-answer-to-me ( array -- type_subj answer id )
  "type" array at
  "subject" array at " " prepend append
  "answer" array at
  "id" array at ;

Then Itvar made a word using the new cleave combinators. Cleave combinators are new “invention” (I think) in stack based world and I didn’t see them in action until this. This code looks very good to me and nicely reflects the logical structure of code.. The cleave stuff is that bi and tri

: rev-at swap at ;

: cleave-unpack-answer ( array -- type_subj answer id )
  [ [ "type" rev-at ] [ "subject" rev-at ] bi " " prepend append ]
  [ "answer" rev-at ]
  [ "id" rev-at ] tri ;

Before Itvar showed this code I was thinking that I could make some sort of “extract” combinator myself that could be useful in all such cases. I made modify-values combinator before and really liked what it allowed. Well it was too interesting to-not-do it so I made it and this is the usage..

: unpack-answer-to-me ( array -- type_subj answer id )
    { { { "type" "subject" } [ " " prepend append ] }
      { { "answer" } [ ] }
      { { "id" } [ ] }
    } extract-values+ ;

Well I am biased and I don’t know Factor well yet, but I like this solution the most :) . Cleave is cool too. I will post the code for this and some other combinators soon-ish. This post is getting too long already.

update

johnnowak , a guy who is making his own stack based language Fifth (5th — website should be coming soon) came up with yet another solution. I like this one because it creates/uses 2 very general purpose and useful combinators to get a very straightforward solution.

: 2dip -rot 2slip ;

: extract swap [ at ] curry each ;

: unpack-extract
  { "type" "subject" "answer" "id" } extract
  [ " " prepend append ] 2dip
;

Here is more readable formatted code for all 5 examples.

Leave a Reply