Factor

Личный сайт Go-разработчика из Казани

Factor is a modern stack-based language, based on Forth, created by Slava Pestov.

Code in this file can be typed into Factor, but not directly imported because the vocabulary and import header would make the beginning thoroughly confusing.

1! This is a comment 2 3! Like Forth, all programming is done by manipulating the stack. 4! Stating a literal value pushes it onto the stack. 55 2 3 56 76 23 65 ! No output, but stack is printed out in interactive mode 6 7! Those numbers get added to the stack, from left to right. 8! .s prints out the stack non-destructively. 9.s ! 5 2 3 56 76 23 65 10 11! Arithmetic works by manipulating data on the stack. 125 4 + ! No output 13 14! `.` pops the top result from the stack and prints it. 15. ! 9 16 17! More examples of arithmetic: 186 7 * . ! 42 191360 23 - . ! 1337 2012 12 / . ! 1 2113 2 mod . ! 1 22 2399 neg . ! -99 24-99 abs . ! 99 2552 23 max . ! 52 2652 23 min . ! 23 27 28! A number of words are provided to manipulate the stack, collectively known as shuffle words. 29 303 dup - ! duplicate the top item (1st now equals 2nd): 3 - 3 312 5 swap / ! swap the top with the second element: 5 / 2 324 0 drop 2 / ! remove the top item (don't print to screen): 4 / 2 331 2 3 nip .s ! remove the second item (similar to drop): 1 3 341 2 clear .s ! wipe out the entire stack 351 2 3 4 over .s ! duplicate the second item to the top: 1 2 3 4 3 361 2 3 4 2 pick .s ! duplicate the third item to the top: 1 2 3 4 2 3 37 38! Creating Words 39! The `:` word sets Factor into compile mode until it sees the `;` word. 40: square ( n -- n ) dup * ; ! No output 415 square . ! 25 42 43! We can view what a word does too. 44! \ suppresses evaluation of a word and pushes its identifier on the stack instead. 45\ square see ! : square ( n -- n ) dup * ; 46 47! After the name of the word to create, the declaration between brackets gives the stack effect. 48! We can use whatever names we like inside the declaration: 49: weirdsquare ( camel -- llama ) dup * ; 50 51! Provided their count matches the word's stack effect: 52: doubledup ( a -- b ) dup dup ; ! Error: Stack effect declaration is wrong 53: doubledup ( a -- a a a ) dup dup ; ! Ok 54: weirddoubledup ( i -- am a fish ) dup dup ; ! Also Ok 55 56! Where Factor differs from Forth is in the use of quotations. 57! A quotation is a block of code that is pushed on the stack as a value. 58! [ starts quotation mode; ] ends it. 59[ 2 + ] ! Quotation that adds 2 is left on the stack 604 swap call . ! 6 61 62! And thus, higher order words. TONS of higher order words. 632 3 [ 2 + ] dip .s ! Pop top stack value, run quotation, push it back: 4 3 643 4 [ + ] keep .s ! Copy top stack value, run quotation, push the copy: 7 4 651 [ 2 + ] [ 3 + ] bi .s ! Run each quotation on the top value, push both results: 3 4 664 3 1 [ + ] [ + ] bi .s ! Quotations in a bi can pull values from deeper on the stack: 4 5 ( 1+3 1+4 ) 671 2 [ 2 + ] bi@ .s ! Run the quotation on first and second values 682 [ + ] curry ! Inject the given value at the start of the quotation: [ 2 + ] is left on the stack 69 70! Conditionals 71! Any value is true except the built-in value f. 72! A built-in value t does exist, but its use isn't essential. 73! Conditionals are higher order words as with the combinators above. 74 755 [ "Five is true" . ] when ! Five is true 760 [ "Zero is true" . ] when ! Zero is true 77f [ "F is true" . ] when ! No output 78f [ "F is false" . ] unless ! F is false 792 [ "Two is true" . ] [ "Two is false" . ] if ! Two is true 80 81! By default the conditionals consume the value under test, but starred variants 82! leave it alone if it's true: 83 845 [ . ] when* ! 5 85f [ . ] when* ! No output, empty stack, f is consumed because it's false 86 87 88! Loops 89! You've guessed it.. these are higher order words too. 90 915 [ . ] each-integer ! 0 1 2 3 4 924 3 2 1 0 5 [ + . ] each-integer ! 0 2 4 6 8 935 [ "Hello" . ] times ! Hello Hello Hello Hello Hello 94 95! Here's a list: 96{ 2 4 6 8 } ! Goes on the stack as one item 97 98! Loop through the list: 99{ 2 4 6 8 } [ 1 + . ] each ! Prints 3 5 7 9 100{ 2 4 6 8 } [ 1 + ] map ! Leaves { 3 5 7 9 } on stack 101 102! Loop reducing or building lists: 103{ 1 2 3 4 5 } [ 2 mod 0 = ] filter ! Keeps only list members for which quotation yields true: { 2 4 } 104{ 2 4 6 8 } 0 [ + ] reduce . ! Like "fold" in functional languages: prints 20 (0+2+4+6+8) 105{ 2 4 6 8 } 0 [ + ] accumulate . . ! Like reduce but keeps the intermediate values in a list: prints { 0 2 6 12 } then 20 1061 5 [ 2 * dup ] replicate . ! Loops the quotation 5 times and collects the results in a list: { 2 4 8 16 32 } 1071 [ dup 100 < ] [ 2 * dup ] produce ! Loops the second quotation until the first returns false and collects the results: { 2 4 8 16 32 64 128 } 108 109! If all else fails, a general purpose while loop: 1101 [ dup 10 < ] [ "Hello" . 1 + ] while ! Prints "Hello" 10 times 111 ! Yes, it's hard to read 112 ! That's what all those variant loops are for 113 114! Variables 115! Usually Factor programs are expected to keep all data on the stack. 116! Using named variables makes refactoring harder (and it's called Factor for a reason) 117! Global variables, if you must: 118 119SYMBOL: name ! Creates name as an identifying word 120"Bob" name set-global ! No output 121name get-global . ! "Bob" 122 123! Named local variables are considered an extension but are available 124! In a quotation.. 125[| m n ! Quotation captures top two stack values into m and n 126 | m n + ] ! Read them 127 128! Or in a word.. 129:: lword ( -- ) ! Note double colon to invoke lexical variable extension 130 2 :> c ! Declares immutable variable c to hold 2 131 c . ; ! Print it out 132 133! In a word declared this way, the input side of the stack declaration 134! becomes meaningful and gives the variable names stack values are captured into 135:: double ( a -- result ) a 2 * ; 136 137! Variables are declared mutable by ending their name with a shriek 138:: mword2 ( a! -- x y ) ! Capture top of stack in mutable variable a 139 a ! Push a 140 a 2 * a! ! Multiply a by 2 and store result back in a 141 a ; ! Push new value of a 1425 mword2 ! Stack: 5 10 143 144! Lists and Sequences 145! We saw above how to push a list onto the stack 146 1470 { 1 2 3 4 } nth ! Access a particular member of a list: 1 14810 { 1 2 3 4 } nth ! Error: sequence index out of bounds 1491 { 1 2 3 4 } ?nth ! Same as nth if index is in bounds: 2 15010 { 1 2 3 4 } ?nth ! No error if out of bounds: f 151 152{ "at" "the" "beginning" } "Append" prefix ! { "Append" "at" "the" "beginning" } 153{ "Append" "at" "the" } "end" suffix ! { "Append" "at" "the" "end" } 154"in" 1 { "Insert" "the" "middle" } insert-nth ! { "Insert" "in" "the" "middle" } 155"Concat" "enate" append ! "Concatenate" - strings are sequences too 156"Concatenate" "Reverse " prepend ! "Reverse Concatenate" 157{ "Concatenate " "seq " "of " "seqs" } concat ! "Concatenate seq of seqs" 158{ "Connect" "subseqs" "with" "separators" } " " join ! "Connect subseqs with separators" 159 160! And if you want to get meta, quotations are sequences and can be dismantled.. 1610 [ 2 + ] nth ! 2 1621 [ 2 + ] nth ! + 163[ 2 + ] \ - suffix ! Quotation [ 2 + - ]

Further reading