## Factor Combinators

If you want to discuss about Oforth...

### Factor Combinators

I've been having fun implementing factor combinators (http://docs.factorcode.org/content/article-combinators.html) in oforth, yesterday I was doing the preserving combinatorshttp://docs.factorcode.org/content/article-dip-keep-combinators.html, with documentation and examples, and I will continue on today with the cleave ones if I get the time to do it. I'll see if I can upload the code later, I'm currently at work, and don't have access to it, as it was coded offline yesterday Really simple stuff, but it's fun, in understanding the combinators and seeing how they may be coming in handy some times.

All of the ones I've done so far, I've done as methods on Runnable, as I thought that would be the cleanest implementation.
sotolf

Posts: 55
Joined: 30 Jul 2015 15:53

### Re: Factor Combinators

Didn't get around to the net yesterday either, but I've now implemented the cleave combinators, and I'm almost finished with the spread ones, just got a bit mushy yesterday and didn't find something to take the nth value off the stack.
sotolf

Posts: 55
Joined: 30 Jul 2015 15:53

### Re: Factor Combinators

Interesting.

For Runnable implementation, yes, it is a good choice if the combinator only apply to one runnable (with paramters).
But, if a combinator applies to 2 runnables (for instance bi), there is a choice to do between a function and a method on runnables. Both have their advantages and inconvenients.

For the nth value off the stack, you really mean removing it, not picking it (using n pick) ? If it is really removing it, there is no word for that, you will have to make one, but, be carefull, it is strange to have to remove the nth element on the stack (and it is even considered "bad" to use #pick).

What is the need for taking off the nth value off the stack ? Which combinator need this ?
Franck

Posts: 155
Joined: 29 Oct 2014 19:01

### Re: Factor Combinators

So, now I'm at home and I'll post some of the stuff that I have done thus far, it's all raw first round stuff for now, it still needs tests, and reformatting of the little documentation that I have. But it's a start.

preserving.of
Code: Select all
`//******************************************************************************//******************************************************************************// Defines perserving combinators, like in factor//******************************************************************************//******************************************************************************// Copyright (c) 2015, 2016 Tor Erling Rumpold Opsahl. All rights reserved// Use of this source code is governed by the standard MIT license//******************************************************************************//******************************************************************************//******************************************************************************// dip ( x block -- x ) // takes x off the stack, performs block and puts x back on the stack// Example: 1 2 #[ 1 + ] dip -- 2 2Runnable method: dip(x){     self perform x}//******************************************************************************// 2dip ( x y block -- x y )// takes x and y off the stack, performs block and puts x and y back on the stack// Example: 1 2 3 #[ 1 + ] 2dip -- 2 2 3Runnable method: 2dip(y, x){   self perform x y}//******************************************************************************// 3dip ( x y z block -- x y z)// takes x, y and z off the stack, performs block and put them back on the stack// Example: 1 2 3 4 #[ 1 + ] 3dip -- 2 2 3 4Runnable method: 3dip(z, y, x){    self perform x y z}//******************************************************************************// 4dip ( x y z w block -- x y z w )// takes x, y, z and w off the stack, performs block and puts them back on the stack// Example: 1 2 3 4 5 #[ 1 + ] 4dip -- 2 2 3 4 5Runnable method: 4dip(w, z, y, x){    self perform x y z w}//******************************************************************************//******************************************************************************// keep ( x y block -- x (y block) y )// takes y off the stack, performs block on y, and puts it back on the stack// Example: 1 2 #[ 1 + ] keep -- 1 3 2Runnable method: keep(x){    x self perform x}//******************************************************************************// 2keep ( x y z block -- x (y z block) y z// takes y and z off the stack performs block on them both, and puts them back// Example: 1 2 3 #+ 2keep -- 1 5 2 3Runnable method: 2keep(y, x){    x y self perform x y}//******************************************************************************// 3keep ( x y z w block -- x (y z w block) y z w )// takes y, z and w off the stack, performs the block on them and puts them back// Example: 1 2 3 4 #[ + + ] 3keep -- 1 9 2 3 4Runnable method: 3keep(z, y, x){    x y z self perform x y z}`

cleave.of

Code: Select all
`//******************************************************************************//******************************************************************************// Defines cleave combinators, like in factor//******************************************************************************//******************************************************************************// Copyright (c) 2015, 2016 Tor Erling Rumpold Opsahl. All rights reserved// Use of this source code is governed by the standard MIT license//******************************************************************************//******************************************************************************//******************************************************************************// bi ( x block1 block2 -- ( x block1 ) ( x block2 ) )// Performs block1 on x and then block 2 on x// Example: 1 #[ 1 + ] #[ 1 - ] bi -- 2 0Runnable method: bi(blk2, x){    x blk2 perform x self perform}//******************************************************************************// 2bi ( x y block1 block2 -- ( x y block1 ) ( x y block 2)// performs block1 on x and y and then block 2 on the same// Example: 1 2 #+ #- 2bi -- 3 -1Runnable method: 2bi(blk2, y, x){    x y blk2 perform x y self perform}//******************************************************************************// 3bi ( x y z block1 block2 -- ( x y z block1 ) ( x y z block2 )// performs block1 on x,y,z and block2 on x,y,z// Example: 1 2 3 #[ + + ] #[ * * ] 3bi -- 6 6Runnable method: 3bi(blk2, z, y, x){    x y z blk2 perform x y z self perform}//******************************************************************************//******************************************************************************// tri ( x block1 block2 block3 -- (x block1) (x block2) (x block3)// performs all the 3 blocks on x// Example: 1 #[ 1 + ] #[ 2 + ] #[ 3 + ] tri -- 2 3 4Runnable method: tri(blk2, blk3, x){    x blk3 perform x blk2 perform x self perform}//******************************************************************************// 2tri ( x y block1 block2 block3 -- (x y block1) (x y block2) (x y block3)// performs all the three blocks on x y// Example: 1 2 #+ #- #* 2tri -- 3 -1 2Runnable method: 2tri(blk2, blk3, y, x){    x y blk3 perform x y blk2 perform x y self perform}//******************************************************************************// 3tri ( x y z block1 block2 block3 -- (x y z block1) (x y z block2) (x y z block3)// performs all the three blocks on x y z// Example: 1 2 3 #[ + + ] #[ * * ] #[ - -] 3tri -- 6 6 2Runnable method: 3tri(blk2, blk3, z, y, x){    x y z blk3 perform x y z blk2 perform x y z self perform}//******************************************************************************//******************************************************************************// cleave ( x [list of blks] -- [ x blk for list of blks ])// performs the blocks on x// Example: 1 [#[ 1 + ], #[ 1 - ] ] cleave -- 0 2: cleave(blks, x){ | i |    blks forEach: i [ x i perform ]}//******************************************************************************// 2cleave ( x y [list of blks ] -- [ x y blk for list of blks ] )// performs the blocks on x y// Example: 1 2 [ #+, #-, #* ] 2cleave -- 3 -1 2: 2cleave(blks, y, x){ | i |    blks forEach: i [ x y i perform ] }//******************************************************************************// 3cleave ( x y z [list of blks ] -- [ x y z blk for list of blks ] )// performs the blocks on x y z// Example: 1 2 3 [ #[ + + ], #[ * *] ] 3cleave -- 6 6: 3cleave(blks, z, y, x){ | i |    blks forEach: i [ x y z i perform ] }//******************************************************************************// 4cleave ( w x y z [list of blks ] -- [ w x y z blk for list of blks ] )// performs the blocks on x y z// Example: 1 2 3 4 [ #[ + + + ], #[ * * * ] ] 4cleave -- 10 24: 4cleave(blks, z, y, x, w){ | i |    blks forEach: i [ w x y z i perform ] }`

Code: Select all
`//******************************************************************************//******************************************************************************// Defines spread combinators, like in factor//******************************************************************************//******************************************************************************// Copyright (c) 2015, 2016 Tor Erling Rumpold Opsahl. All rights reserved// Use of this source code is governed by the standard MIT license//******************************************************************************//******************************************************************************//******************************************************************************// bi* ( x y blk1 blk2 -- x blk1 y blk2 )// performs the two blocks at their respective values// Example: 3 2 #[ 1 + ] #[ 2 + ] bi* -- 4 4Runnable method: bi*(blk2, y, x){    x blk2 perform y self perform}//******************************************************************************// 2bi* ( x y z w blk1 blk2 -- x y blk1 z w blk2 )// performs the two blocks on two values each// Example: 1 2 2 1 #+ #- 2bi* -- 3 1Runnable method: 2bi*(blk2, w, z, y, x){    x y blk2 perform z w self perform}//******************************************************************************//******************************************************************************// tri* ( x y z blk1 blk2 blk3 -- x blk1 y blk2 z blk3)// Performs the three blocks on their respective values// Example: 1 2 3 #[ 3 + ] #[ 2 + ] #[ 1 + ] tri* -- 4 4 4Runnable method: tri*(blk2, blk3, z, y, x){    x blk3 perform y blk2 perfrom z self perform}//******************************************************************************// 2tri* ( u v w x y z blk1 blk2 blk3 -- u v blk1 w x blk2 y z// blk3 )// Example: 1 2 3 4 5 6 #+ #- #* tri* -- 3 -1 30Runnable method: 2tri*(blk2, blk3, z, y, x, w, v, u){    u v blk3 perform w x blk2 perfrom y z self perform}//******************************************************************************// spread ( objs [list blks] -- obj blk for blk in list )// performs each blk in list on one element// Example: 1 2 3 [ #[ + 1 ], #[ + 2 ], #[ + 3 ] ] spread -- 2 4// 6: spread(blks){ | results i |    [] ->results    blks size seq forEach: i [ i pick i blks at}`

It's for the last function here I would need to take values off of the stack the function takes a list of blocks, and will perform it's action on the element that is nth on the stack, e.g x y z [ [blk1], #[blk2], #[blk3] ] -- x blk1 perform y blk2 perform z blk3 perform, the complication is that the length of the list is not known beforehand, so I can't take the values as arguements to the function, just the list, it would be easier if I could "nip" them off the stack, but I'll come up with something, probably I will end up with reversing the list of blocks, performing them, saving the result in a variable, and then reverse that again, and spit them back on the stack, or something like it, it'll probably be better that way anyway.
sotolf

Posts: 55
Joined: 30 Jul 2015 15:53

### Re: Factor Combinators

Good job,

For spread, there are many ways to do it.
One way is to use a recursion : spread with n elements is spread with n-1 elements + perform the last block on top of stack :

Code: Select all
`: spread(blks, x){   blks size 1 > ifTrue: [ blks left(blks size 1 -) spread ]   x blks last perform}`

Franck
Franck

Posts: 155
Joined: 29 Oct 2014 19:01

### Re: Factor Combinators

Cool, thank you I'll steal your implementation, and then continue on with the others, and then I'll just do some small things and have more fun with oforth
sotolf

Posts: 55
Joined: 30 Jul 2015 15:53

### Re: Factor Combinators

If fact, I think it would be better to create an intermediary function :

Code: Select all
`: spreadn(blks, n, x){   n 1 > ifTrue: [ n 1 - blks spreadn ]   x blks at(n) perform}: spread(blks) { spreadn(blks, blks size) }`

This way, no memory is used : the previous spread function was creating n lists of blocks.

Franck
Franck

Posts: 155
Joined: 29 Oct 2014 19:01