Skip to content

Instantly share code, notes, and snippets.

@greggirwin
Last active May 23, 2020 19:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save greggirwin/bde09ee106b7ac62a7f3c742b32155f6 to your computer and use it in GitHub Desktop.
Save greggirwin/bde09ee106b7ac62a7f3c742b32155f6 to your computer and use it in GitHub Desktop.
Old experiments in dynamically refined function calls
filter: function [
"Returns two blocks: items that pass the test, and those that don't."
series [series!]
test [any-function!] "Test (predicate) to perform on each value; must take one arg"
/only "Return a single block of values that pass the test"
][
result: reduce [copy [] copy []]
foreach value series [
append/only pick result make logic! test :value :value
]
either only [result/1][result]
]
to-path: func [spec][
; LOAD FORM is used to clean up specs that have refinements
; in them. Refinement values get their sigil doubled, which
; FORM removes, so they are sanitized. More overhead, but we
; could make that optional if this func lives on.
; Note that this literal path value persists, so if you
; inspect the function body later, it will have the last
; spec the func was called with.
load form append clear '_/_ spec
]
refine: function [
"Returns a path, by adding refinement(s) to a word or path."
path [any-word! path!]
refs [word! block!] "Refinements to add"
return: [path!]
][
if block? refs [
; Separate copy step because `remove-each` doesn't return
; a value at this time.
refs: copy refs
remove-each val refs [not all-word? val]
]
to-path compose [(path) (refs)]
]
p: refine 'append 'only
p: refine 'append [only]
refine 'append [only]
do reduce [refine 'append [only] [] [a]]
refine 'find [part only case same any with skip last reverse tail match]
;!! Where this won't work is if you have a function that takes refinements
; as args themselves. In that case, you need to use `refine` directly.
do-refined: func [fn [word!] args [block!]][
; Filter to split args into refinements and arg values
set [refs args] filter args :refinement?
; Make refined path
fn: refine fn refs
do compose [(fn) (args)]
]
do-refined 'append [[] /only [a]]
do-refined 'append [[] /only [a] /dup 3]
do-refined 'append [[] /dup /only [a] 3]
do-refined 'append [[] /dup [a] 3 /only]
do-refined 'append [[] [a] /dup 3 /only]
do-refined 'append [[] /dup 3 /only [a]] ; error, args out of order
do-refined: func [spec [block!] args [block!]][
; Filter to split args into refinements and arg values
set [refs args] filter args :refinement?
; Make refined path
spec/1: refine spec/1 refs
do compose [(spec) (args)]
]
do-refined [append [] [a]] [/only]
do-refined [append [] [a]] [/only /dup 3]
do-refined [append [] [a]] [/dup /only 3]
do-refined [append [] [a]] [/dup 3 /only]
do-refined [append [] [a]] [/dup 3 /only]
do-refined [append/only [] [a]] []
do-refined [append/only [] [a]] [/dup 3]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment