Last active
August 27, 2020 07:29
-
-
Save dander/66ad65555b30286115cee675b16bf1d7 to your computer and use it in GitHub Desktop.
An experiment to make a general purpose generator-creating function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Red [ | |
Title: "generator function experiments" | |
Author: "Dave Andersen" | |
Date: 27-Sep-2017 | |
] | |
reload: does [do system/options/script] | |
; @JacobGood's closure func | |
closure1: func [ | |
vars [block!] | |
spec [block!] | |
body [block!] | |
][ | |
; Can't use `function` here, because it will collect set-words | |
; in the body, which may be closure vars. | |
func spec compose [(bind body context vars)] | |
] | |
; @Nenad's closure func | |
closure2: func [vars spec body][ | |
bind (body-of spec: func spec body) (context vars) | |
:spec | |
] | |
closure2: func [vars spec body][bind body-of spec: func spec body context vars :spec] | |
; @9214's closure modification | |
closure3: func [vars spec body][func spec bind body context vars] | |
closure: :closure3 | |
enclose1: func [args /local w][ | |
collect [foreach w args [ | |
if word? w [keep to-set-word w keep/only to-paren w] | |
]] | |
] | |
enclose2: func [args /local w][ | |
context compose/only collect [foreach w args [ | |
if word? w [keep to-set-word w keep/only to-paren w] | |
]] | |
] | |
enclose3: func [args /local w][ | |
collect [foreach w args [ | |
if word? w [keep to-set-word w keep 'quote keep/only to-paren reduce ['get to-lit-word w]] | |
]] | |
] | |
enclose: :enclose3 | |
generator1: func [ | |
{Defines a generator with the given spec} | |
spec [block!] "generator parameters" | |
body [block!] "body of the function returned by the generator" | |
][ | |
closure | |
compose/only enclose [spec body] | |
spec | |
compose/only [ | |
closure compose/only (enclose spec) [] (body) | |
] | |
] | |
generator2: func [ | |
{Defines a generator with the given spec} | |
spec [block!] "generic spec for the defined generator" | |
body [block!] "body of the function returned by the generator" | |
][ | |
closure | |
enclose2 [spec body] | |
spec | |
compose/only [closure (enclose spec) [] body] | |
] | |
generator: :generator1 | |
++: func [ | |
"Increment a value by 1" | |
'value [word! path!] "thing to be incremented" | |
/after "return the current value, then increment" | |
][ | |
either after [ | |
also get value | |
set value (get value) + 1 | |
][ | |
set value (get value) + 1 | |
] | |
] | |
ticker: generator [ | |
"Generate numbers counting up from i indefinitely" | |
i [number!] | |
][ | |
++/after i | |
] | |
range: generator [ | |
"Generate numbers from start to finish, inclusive" | |
start [number!] finish [number!] | |
][ | |
if start <= finish [++/after start] | |
] | |
..: make op! :range | |
iter: generator [ | |
"Iterate over the items in a series" | |
series [series!] | |
][ | |
also series/1 | |
series: next series | |
] | |
blockify: function [ | |
"Produce a block from the output of a generator" | |
f [function!] | |
][ | |
collect [while [value: f] [keep value]] | |
] | |
cycler: generator [ | |
"Loop over the items in a series" | |
series [series!] | |
][ | |
if tail? series [series: head series] | |
also :series/1 | |
series: next series | |
] | |
limit1: function [ | |
"Generate up to 'n' items from a series or generator function" | |
sequence [series! function!] | |
n [integer!] | |
][ | |
gen: generator [i n][ | |
if n < 1 [return none] | |
n: n - 1 | |
i | |
] | |
gen either function? :sequence [:sequence][iter sequence] n | |
] | |
limit-gen: generator [ | |
"Generate up to 'n' items from a generator function" | |
f [function!] | |
n [integer!] | |
][ | |
if n < 1 [return none] | |
n: n - 1 | |
f | |
] | |
limit: func [f n][ | |
either series? :f [ | |
limit-gen iter :f n | |
][ | |
limit-gen :f n | |
] | |
] | |
zip: function [ | |
"Generate the outputs from two functions interleaved together" | |
f1 [function!] f2 [function!] | |
][ | |
select context [ | |
cyc: cycler reduce [:f1 :f2] | |
gen: func [/local f][f: cyc f] | |
] | |
'gen | |
] | |
apply: generator [ | |
"Apply a function to the items of a generator" | |
g [function!] "generator" | |
f [function!] "function to apply" | |
/local x | |
][ | |
x: g | |
if x [f x] | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment