Last active
April 24, 2018 09:18
-
-
Save toomasv/1b1d8e859eeb1acfa230cc5357ca12fa to your computer and use it in GitHub Desktop.
Range for on-demand evaluation
This file contains hidden or 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 [ | |
Author: "Toomas Vooglaid" | |
Date: 27-11-2017 | |
] | |
lazy-range: function [ | |
"Returns function that generates next value in (possibly infinite) range" | |
val [scalar!] "Initial value" | |
/step stp [scalar! block!] "By which to increment each next value" | |
/limit lim [integer!] "How many new values to generate" | |
/stop stopval [scalar! block!] "On which value to stop generation of new values; if block, then also after how may matches" | |
/circle crcl [scalar!] "To generate (possibly infinite) new values in limited range" | |
][ | |
cx: context compose/deep [ | |
limit: lim | |
stop: (either all [stop block? stopval][stopval/1][stopval]) | |
step: (either step [([stp])][if percent? val [1%][1]]) | |
val: (val) | |
count: 0 | |
val2: none | |
cval: none | |
inc: if block? step [get step/2] ;either block? step [get step/2][:+] | |
circle: crcl | |
stop-count: (if all [stop block? stopval][stopval/2]) | |
count-stop: 0 | |
count-circle: 0 | |
bstep: if block? step [either '- = step/2 [0 - step/3][step/3]] | |
b2stp: 0 | |
next-val: does [ | |
if any [limit circle][count: count + 1] | |
either any [ | |
all [limit limit < count] | |
all [ | |
stop | |
either circle [ | |
if all [stop-count stop = val2][count-stop: count-stop + 1] | |
and~ stop = val2 either stop-count [stop-count = count-stop][true] | |
][ | |
pick reduce [stop > val stop < val] either any [ | |
all [number? step negative? step] | |
all [block? step '- = step/2] | |
][true][false] | |
] | |
] | |
][none][ | |
either circle [ | |
cval: either block? step [ | |
either number? circle [ | |
val2: val | |
b2stp: count - 1 * bstep % circle | |
val2/(step/1): val2/(step/1) + b2stp | |
val2 | |
][cause-error 'user 'message ["Only integer! type supported for circle in case of block step!"]] | |
][ | |
val + case [ | |
or~ number? circle time? circle [count - 1 * step % circle] | |
true [cause-error 'user 'message ["Only numeric and time types supported for circle!"]] | |
] | |
] | |
][ | |
also val val: either block? step [ | |
val2: val | |
val2/(step/1): val2/(step/1) inc step/3 | |
val2 | |
][ | |
val + step | |
] | |
] | |
] | |
] | |
] | |
:cx/next-val | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Examples
Simple generator:
In loops:
With
/limit
:With
/step
:With
/stop
:With
/circle
:When
stop
is block then second value is interpreted as the number of matches before stopping, e.g. in following1-Jan-2017
is matched 3 times before stopping.