Factor Combinators

If you want to discuss about Oforth...

Factor Combinators

Postby sotolf » 05 Aug 2015 07:03

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

Postby sotolf » 06 Aug 2015 08:59

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

Postby Franck » 06 Aug 2015 09:11

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

Postby sotolf » 06 Aug 2015 17:39

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 2

Runnable 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 3

Runnable 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 4

Runnable 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 5

Runnable 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 2

Runnable 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 3

Runnable 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 4

Runnable 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 0

Runnable 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 -1

Runnable 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 6

Runnable 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 4

Runnable 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 2

Runnable 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 2

Runnable 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 ]
}


spread.of
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 4
Runnable 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 1
Runnable 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 4
Runnable 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 30
Runnable 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

Postby Franck » 06 Aug 2015 19:02

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

Postby sotolf » 06 Aug 2015 19:48

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

Postby Franck » 09 Aug 2015 17:36

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


Return to Discussions

Who is online

Users browsing this forum: No registered users and 1 guest

cron