Re: Factor

Factor: the language, the theory, and the practice.

Translation

Friday, October 2, 2026

#language

Translating an existing piece of code from one language to another is often a good way to learn a language. A great long time ago, Arkady Rost posted to the mailing list a question about translating into Factor.

The original code that was being translated looked a bit like this:

for i in rangeA {
    for j in rangeB {
        foo(param, i, j);
    }
    bar();
}

Version 0

The first solution he found seemed a little bit involved, and he wondered if it could be improved:

rangeA rangeB param [ foo ] curry
[ swapd [ call ] 2curry each bar ] 2curry each

Using these values, for example:

  • rangeA: { "a" "b" "c" }
  • rangeB: { "1" "2" "3" }
  • param: " "
  • foo: append append write
  • bar: "" print

We can get this output:

IN: scratchpad { "a" "b" "c" } { "1" "2" "3" } " "
               [ append append write ] curry
               [ swapd [ call ] 2curry each "" print ] 2curry each
1a 2a 3a 
1b 2b 3b 
1c 2c 3c

Version 1

I suggested something like this:

IN: scratchpad { "1" "2" "3" } [
                   { "a" "b" "c" } [ append ] with map
                   " " join print
               ] each
1a 2a 3a 
1b 2b 3b 
1c 2c 3c

But then Arkady pointed out that “the original task is more complicated that’s why I’ve used foo and bar in definition of the problem”.

Version 2

I suggested an approach that takes two sequences, applies foo to create an intermediate sequence and then applies bar to each element:

: my-func ( a b foo: ( x y -- z ) bar: ( z -- ) -- )
    [ [ with map ] 2curry ] dip compose each ; inline

The readability of this can be improved quite a bit by using “fry quotations”:

: my-func ( a b foo: ( x y -- z ) bar: ( z -- ) -- )
    '[ _ with map @ ] curry each ; inline

Either way, using it is pretty easy:

IN: scratchpad { "1" "2" "3" } { "a" "b" "c" }
               [ append ] [ " " join print ] my-func
1a 2a 3a 
1b 2b 3b 
1c 2c 3c

More Ideas

Of course, we could also use local variables for a direct translation:

rangeA [| i |
    rangeB [| j |
        param i j foo
    ] each
    bar
] each

Or some inline fancy currying to get:

param rangeA [ rangeB [ foo ] 2with each bar ] with each

Some other ideas included a suggestion to use the sequences.product vocabulary.

And then there might be the potential need for row polymorphism, meaning that quotations are allowed to use a generalized amount of values present on the stack when called.

It’s fun to be reminded that there are many ways to solve problems, that expressibility of your programming language is important, and that ultimately being able to perform desired computations is the focus here.