word!
, [construct
](http://www.rebol.com/docs/words/wconstruct.html):red red>> obj: construct [ name: uppercase "Fred" age: 20 + 7 time: now ] == make object! [ name: 'uppercase age: 20 time: 'now ]
system/script/args
should be itsystem/script/args
except none
. BTW I am confused about system/options/args
-- what is its relation to the other one?system/script/args
is a raw string, as it comes from the OS. system/options/args
is a block of strings where that string is split at spaces. Not the most intuitive design, but I understand the rationale.read
and write
that already exists in red for that (at least for simple http)remove
returns series after removed value and take
returns removed value.pydoc
** Script Error: length? expected series argument of type: series port tuple bitset struct ** Where: rejoin ** Near: length? first :x "] " mold >>
query
func was useful for finding new words your code added to the system. Combined with an include system, you could track what words each file or module added to the system, rather than just seeing what functions are defined in them. Hmmmm.&File
makes F key a shortcut to file menu.c> numbers: charset [#"0" - #"9"] == make bitset! #{000000000000FFC0} c> string: "abcd123efgh" == "abcd123efgh" c> parse string [collect [to numbers keep some numbers]] == ["123"]
c> parse string [to numbers copy value some numbers] == false c> value == "123"
>> parse string [to numbers copy value some numbers] ** Script Error: Invalid argument: make bitset! #{ 000000000000FF03000000000000000000000000000000000000000000000000 } ** Where: action ** Near: parse string [to numbers copy value some numbers]
>> value: copy "" parse string [some [[copy char numbers (append value char)] | skip]] == true >> value == "123"
first parse string non-digit
non-digit
a delimiter set containing all characters but digits.>> string: "abc123def456ghi" == "abc123def456ghi" >> value: copy "" parse string [some [[copy char some numbers (append value char) to end] | skip]] == true >> value == "123"
s: "abc123def456ghi" copy/part pos: find s digit find pos complement digit
lisp refs: parse spec-of :now [string! collect some [keep refinement! string!] to end]
== [ /year /month /day /time /zone /date /weekday /yearday /precise /utc ]
>> foreach ref refs [print [ref do join join 'now {/} ref]]
year 2017 month 1 day 30 [..]
*** Script Error: join has no value
source
of join
from R2 to Red gives another error:*** Script Error: reduce does not allow string! for its /into argument
>> foreach ref refs [print [ref do append copy {now/} ref]]
*** Internal Error: reserved for future use (or not yet implemented) *** Where: now
do
thosenow
is not fully implemented: only time! values for now.now/date
, now/year
... will give you this kind of error!function!
and refinement!
in general, now
was useful in that it gave me that errorpath!
to a block!
:red>> append [] test == [now time]
to-block test
gives the sameappend/only
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. 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!] ][ refs: copy refs remove-each val refs [not any-word? val] to-path compose [(path) (refs)] ] 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] 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]
to-path
here, which I wrote before it was standard in Red. I need to rename it now, we need to compare the standard version. The standard version doesn't work with this version of do-refined
. do-refined
with a different interface [fn [word!] args [block!]]
, which was my first thought, but I like the way version reads at the call site better.to-path
does what the comment in my func works around. If you have refinements in the spec, the sigil gets doubled.refine
.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 any-word? val] ] to-path compose [(path) (refs)] ]
do-refined
is easier propagation of refinements. Wrapping funcs that take refinements leads to a lot of extra code in R2. One catch we still have is easily mapping same-named refinements. They are logic values in the called func, which we then need to map back to refinement values to propagate this way.arity-of
and refinement-names
funcs, but haven't pushed things forward because I haven't needed them yet, and want to see what Doc's general HOF thoughts are, and his take on apply
. It wasn't terribly friendly in Rebol, in the name of efficiency.specialize
function. Rebol has that feel of malleability to me specialize
specialize
does is to create a whole new function, using the original as a template. specialize
is a very simple example of metaprogramming, if you look at how it uses parse
to analyze and modify the body of the template function, you can see how that approach could do more advanced work, finding complex patterns in code or data and rewriting them.bind
words to contexts and when you evaluate (e.g. get
) a word, the context determines the value you'll get. And because words carry their binding with them, you can re-bind them and have a mix of words with different bindings in a given "location".a: 1 o: object [a: 2] p: object [a: 3] append b: [] reduce [ 'a in o 'a in p 'a ] probe b ; == [a a a] reduce b ; == [1 2 3]
parse [1] [1]
number!
or if you want one, the character literalize-int-rules: func [template [block!] "modified" /local rule mark] [ ; Turn a single integer value into a quantity-of-one integer ; rule for parse (e.g. 1 becomes 1 1 1, 4 becomes 1 1 4). rule: [ any [ into rule | mark: integer! (insert mark [1 1]) 2 skip | skip ] ] parse template rule template ] print mold literalize-int-rules [1 2 3]
red>> parse [1] [1 1 1] *** Script Error: PARSE - invalid rule or usage of rule: 1 *** Where: parse
parse [1] [quote 1]
should be ok.quote 1234
versionquote
instead of 'lit-
number!
s is because the parser treats numbers specially. words!
can't start with a number:>> parse [1 1] [2 '1] ** Syntax Error: Invalid word-lit -- '1 ** Near: (line 1) parse [1 1] [2 '1]
quote
, yes.red>> get load "blah" *** Script Error: blah has no value *** Where: get
get
ting value of a word:red>> if value? word: load "blah" [get word] == none red>> if value? word: load "red" [get word] == 255.0.0
s: "abc123def456ghi" copy/part pos: find s digit find pos complement digit
numbers: charset [#"0" - #"9"] chars: reduce ['some (complement numbers)] keys: ["uu" | "dd" | "lll" | "rrr"] probe parse "dd" [keys] probe parse "odd" [chars] probe parse "odd" [chars keys] ; ??
parse-trace
?probe parse "odd" [chars]
already matched, so no matching[set x]
and [char some char]
may be useful herekey-arrow: [#"u" 2 #"d" 2 #"l" 3 #"r" 3] text: "ozzllluu" lastchar: "" count: 1 escape-char: "" foreach char text [ if/else char == lastchar [ count: count + 1 if (select key-arrow char) == count [ escape-char: char break ] ] [count: 1] lastchar: char ] if/else escape-char == "" [print "no escape-char"] [print join "escape-char " escape-char]
parse
?red>> char-rule: [ set curr-char ["a" | "b" | "c"] (either curr-char = prev-char [ count: count + 1 if count = 3 [ print ["found 3-duplicate " curr-char] break ] ] [ count: 1 prev-char: curr-char ] ) ] red>> parse "aabbbcc" [ (set 'count 1 set 'prev-char none) any char-rule ] found 3-duplicate b *** Throw Error: no loop to break *** Where: break
parse
from inside itselfbreak
is a word in the parse
dialect and also in red itself. You simply have to put break
outside the parensparse
or notred>> parse [] [if (false) ] == false red>> parse [] [if (true) ] == true
if
here is a word in the parse dialect. As usual in the parse dialect, what is inside the parens ()
gets called as normal Red/rebol codered>> parse [1 2 3] [any [set 'x number! if (x > 1) (print ["last:" x]) break]] *** Script Error: PARSE - unexpected end of rule after: set *** Where: parse
parse
block is a dialect, not normal rebol code'x
no need to quotebreak
into if's branch?if
work in parse
?if
just succeds or fails the expression, so no break needed?parse
by itselfred>> parse [1 2 3] [any [set x number! if (x > 1 print ["last:" x])]] last: 1 last: 2 last: 3 == true
red>> parse [1 2 3] [any [set x number! (print ["x:" x]) [ if (x > 1) (print ["last:" x]) break | ]]] x: 1 x: 2 last: 2 == false
red>> char-rule: [ set curr-char ["a" | "b" | "c"] [if (curr-char = prev-char) (count: count + 1) [if (count = 3) (print ["found 3-duplicate " curr-char]) break | ] | (count: 1 prev-char: curr-char) ] ] red>> parse "aabbccc" [ (set 'count 1 set 'prev-char none) any char-rule ] found 3-duplicate c == true
break
doesn't fail the matching:red>> parse [] [ break | (print "second") ] == false
parse
will only hit the first rulebreak
does *not* fail the matching:fail
:Dparse
variant of codeparse
string for first n duplicate character found in (character ,n) setprint random [1 2 3 4 5 6 7 8 9] == 7 6 4 8 1 9 3 5 2
FindWindowto get a handle to the main window of the other app.
seed
something reliable and random, usually current time in nano/micro/seconds is used for thisnow/precise
is a good candidate for this, but it seems not yet implementedrandom/secure
for real security (help shows it as TBD)random/seed
to control the starting point. I agree with @maximvl that you should not rely on internal details in this case. probe system/options/args
and probe system/script/args
, the first only gives the scriptname and the second says 'none' (I gave three arguments)probe
code solution!routine. Here is an example that will return a single string containing the arguments. The tricky part for me was creating a single string to return to Red from Red/System. I don't know of an easy way to concatenate strings in Red/System.
Red [] #system [ args: declare str-array! buffer: allocate 1024 c: 0 c-str: declare c-string! save-buffer-start: buffer temp-buffer: declare byte-ptr! ] get-args: routine [return: [string!]] [ print ["count: " system/args-count lf] args: system/args-list print ["first argument: " args/item lf] if system/args-count < 2 [ return string/load "" 0 UTF-8 ] c: 2 args: args + 1 ;; skip first argument until [ print ["argument " c ": " args/item lf] temp-buffer: as byte-ptr! args/item until [ ;; copy the args to the buffer buffer/value: temp-buffer/value buffer: buffer + 1 temp-buffer: temp-buffer + 1 temp-buffer/value = as byte! 0 ] buffer/value: #" " ;; add a space after the arg buffer: buffer + 1 args: args + 1 args/item = null ] buffer/value: as byte! 0 ;; change the last space to end of string c-str: as c-string! save-buffer-start return string/load c-str length? c-str UTF-8 ] print get-args
mbp:red peter$ ./test count: 1 first argument: ./test mbp:red peter$ ./test 1 2 3 count: 4 first argument: ./test argument 2: 1 argument 2: 2 argument 2: 3 1 2 3
buffercan accommodate the next argument before trying to add it.
-r, so that the correct Red/System functions will be available.
get-args
safe for unicode characters? red>> to-paren () *** Script Error: to-paren does not allow unset! for its value argument *** Where: to-paren
c>
send-keys
dialect, for Windows, that uses APIs to do it. I haven't needed it in Red, so haven't tried to port it yet. If you want to take a crack at it, I can get it to you.Replace
is a mezzanine, so you can see how it works.red>> s: "abcdefghijklmno" == "abcdefghijklmno" red>> replace/all copy s charset "aeiou" #"x" == "xbcdxfghxjklmnx"
""
?char!
, no. A char is always there. #"@"
/null
is the null char, but that will still take up space. In this case, you may just want to use trim
on the result.red>> stripchars "She was a soul stripper. She took my heart!" charset "aei" *** Script Error: invalid argument: "" *** Where: eval-set-path
red>> s: "She was a soul stripper. She took my heart!" == "She was a soul stripper. She took my heart!" red>> trim/with replace/all copy s charset "aei" null null == "Sh ws soul strppr. Sh took my hrt!"
replace
. Otherwise roll your own.strip-chars: func [str [string!] chrs [string! bitset!]][ collect/into [foreach ch str [if not find chrs ch [keep ch]]] copy "" ] print strip-chars "She was a soul stripper. She took my heart!" "aei" print strip-chars "She was a soul stripper. She took my heart!" charset "aei"
strip-chars: func [str [string!] chrs [bitset!] /local res][ res: copy "" parse str [collect into res [some [chrs | keep skip]]] res ] print strip-chars "She was a soul stripper. She took my heart!" charset "aei"
trim
that doesn't match the spec though. red>> trim/with copy s "aei" == "Sh ws soul strppr. Sh took my hrt!"
strip-chars: func [str [string!] chrs [string!]][trim/with str chrs]
strip-chars: :trim
;^)/with
then. trim/with "She was a soul stripper. She took my heart!" "aei"
>> "She was a soul stripper. She took my heart!".delete("aei")
>> do %run-all.r ** Script Error: Feature not available in this REBOL ** Where: context ** Near: SECURITY_ATTRIBUTES: make struct! [ nLength [integer!] lpSecurityDescriptor [integer!] bInheritHandle [int...
Red [] L: charset "ABCDEFGHI" D: union N: charset "123456789" charset "0" repeat y 9 [repeat x 9 [col: either x = 1 [#" "][#"A" + (x - 2)] append p: [] set ref: (to word! rejoin [col y - 1]) make face! [size: 90x24 type: pick [text field] header?: (y = 1) or (x = 1) offset: -20x10 + as-pair ((x - 1) * size/x + 2) ((y - 1) * size/y + 1) text: form case [y = 1 [col] x = 1 [y - 1] 'else [copy ""]] para: make para! [align: pick [center right] header?] extra: object [name: form ref formula: old: none] actors: context [on-create: on-unfocus: function [f e][f/color: none if rel: f/extra/old [react/unlink rel 'all] if #"=" = first f/extra/formula: copy text: copy f/text [parse remove text [any [p: L N not ["/" skip not N] insert p " " insert "/data " | L skip | p: some D opt [dot some D] insert p " " insert " " | skip]] f/text: rejoin [f/extra/name "/data: any [math/safe [" text {] "#UND"]}] if f/data [any [react f/extra/old: f/data do f/data]]]] on-focus: func [f e][f/text: any [f/extra/formula f/text] f/color: yello] ]]]] view make face! [type: 'window text: "PicoSheet" size: 840x250 pane: p]
to word!
. There's a placeholder col header with #" "
as the text, which to word!
doesn't like when combined with a numeric digit to create the cell ref name.[#" "]
with [#"_"]
for now, it will work again. Please file a ticket, or I can do it if you want.ext install red
1199.1341 (11892.8300) Thread/Start 11892 (12488) 1199.5043 (11892.892) Thread/Start 11892 (8300) 1199.6397 (11892.12488) FileIO/Create 'C:\Users\XX\Downloads\programming\LIBREDRT.DLL' (0xFFFFA984C9587440) rw- 1199.7294 (11892.12488) FileIO/Close 'C:\Users\XX\Downloads\programming\LIBREDRT.DLL' (0xFFFFA984C9587440) 1199.7708 (11892.12488) FileIO/Create 'C:\Users\XX\Downloads\programming\LIBREDRT.DLL' (0xFFFFA984C9587440) rw- 1244.2050 (11892.2564) Thread/Start 11892 (8300)
call
behaves like Rebol one, and try to be more helpful to users or not?call "notepad"
.desktop
files on linux and what is there on macscall {xdg-open firefox}
xdg-open
is irrelevant here, ignore previous comment :)call "notepad"
already works ;)notepad.exe
is in the default search paths)./shell
if a file name is not found.call
does not rely on Windows shell. In Rebol, there is a run
command for taking advantage of Windows shell, but it's not there in Red yet. The /shell
option in call
refers to the default system CLI environment.help
space: #" " str: rejoin [tab space] foreach char str [ switch char [ tab [print "tab"] space [print "space"] ] ]
space: #" " str: rejoin [tab space] foreach char str [ do select [ #"^-" [print "tab"] #" " [print "space"] ] char ]
switch
labels are literals, i.e. they are not evaluated. Thus writing tab
means testing for the lit-word'tab
sp
space
text: [5 "Test"] space-to-tab: true tab-width: 4 append-tab-indent: [ loop (tab-num * tab-width) [append output-text tab] ] append-space-indent: [ loop tab-num [append output-text space] ] file-save: does [ output-text: copy [] either space-to-tab [append-ident: append-tab-indent] [append-ident: append-space-indent] foreach [tab-num t ] text [ if tab-num > 0 [ do [append-ident] ] ] probe output-text ] file-save
foreach
and other iterators in Red are not providing a local context, so your tab-num
and t
words are globally declared, while in R2, they are local to the loop. Note that if you use the function
constructor, they would have been captured and became local to file-save
function. We might provide local context for iterators like Rebol in the future.function
leaks words, now you are saying that foreach and other iterators in Red are not providing a local context
functionfunction is syntactic sugar that processes the source of a function and tries to automatically declare them as local to the function.
var
which will keep variable in local contextforeach
to use global tab-cnt
.Red/Rebol [] text: [5 "Test"] space-to-tab: true tab-width: 4 tab-num: 0 output-text: copy [] append-space-indent: does [ loop (tab-num * tab-width) [append output-text tab] ] append-tab-indent: does [ loop tab-num [append output-text space] ] file-save: does [ output-text: copy [] either space-to-tab [append-indent: :append-tab-indent] [append-indent: :append-space-indent] foreach [tab-num t ] text [ if tab-num > 0 [ append-indent ] ] probe output-text ] file-save
tab-num
."tab-num
and t
are local to the foreach
loop, but not in Red (actually).context
, use
as a means to further isolate stuffword!
s must have a context. So if the context is not specifically defined, the 'global' context is used.locally
bound words by-default and if for some unimaginable reason I would need a global thing - to declare it separatelyRed [] a: "Hello" print [a "word"]
a
. It is the case, in some way, its the script context (think of it as the C main
).local crap
lolforeach /local
or even a global system/
?append-tab-indent
and append-space-indent
. As I understand them, append-tab-indent
would append tab-num
tab
s (it appends tab-num * tab-with
) and append-space-indent
would append tab-num * tab-with
space
s (it appendstab-num
tab
s).scope
because this is pretty much it, I do believe a lot of things are wrong with modern languages, but scope is something decently goodtext: [5 "Test"] space-to-tab: true tab-width: 4 file-save: does [ output-text: copy [] foreach [tab-num t] text [ either space-to-tab [ loop tab-num [append output-text tab] ][ loop (tab-num * tab-width) [append output-text space] ] ] probe output-text ] file-save
tab-num
and output-text
were local to file-save.append-tab-indent
into file-save
. My original post refers to code indirection. :point_up: [March 14, 2017 1:06 AM](https://gitter.im/red/help?at=58c733efde5049082287f6ff)tab-cnt
is on the stack, in the short term memory.text: [5 "Test"] space-to-tab: true tab-width: 4 file-save: does [ output-text: copy [] foreach [tab-num t] text [ either space-to-tab [ append/dup output-text tab tab-num ][ append/dup output-text space tab-num * tab-width ] ] probe output-text ] file-save
var
which will keep variable in local context/local
thing requires you to go to the head of function each time you introduce new wordwrite
, that is changing word's value and assign
which is creating a new binding are two different things=
:
in Redboluse [c][loop 1 [c: 5]]
, or define loop-local function, which would just do the same? But you probably are asking about the default, out of the box behaviour like that?global [c] [loop 1 [c: 5]]
:)d: 10
in the body of the loop :-)append-space-indent
and append-tab-indent
functionality is indeed reversed.Red/Rebol [] ; ? can it work in R2 text: [5 "Test"] space-to-tab: true tab-width: 4 append-tab-indent: does [ loop (tab-num * tab-width) [append output-text tab] ] append-space-indent: does [ loop tab-num [append output-text space] ] file-save: does [ output-text: copy [] either space-to-tab [append-indent: :append-tab-indent] [append-indent: :append-space-indent] foreach [tab-num t ] text [ if tab-num > 0 [ append-indent ] ] probe output-text ] file-save
if tab-num > 0 [do bind :append-indent 'tab-num]
foreach
context. And if you define space: #" "
!does
(so you define functions). It become over complicated (but doable) to rebind them.do func-name
?func-name: does [;some code]
format.func-name
looks and feels like any other words.does
will go away when browsing for the word definition.do
count?foreach
body would have to be always interpreted.* (defun f (x y) (+ x y)) F * (disassemble 'f) ; disassembly for F ; Size: 40 bytes. Origin: #x10058B0F13 ; 13: 498B4C2460 MOV RCX, [R12+96] ; thread.binding-stack-pointer ; no-arg-parsing entry point ; 18: 48894DF8 MOV [RBP-8], RCX ; 1C: 488BD6 MOV RDX, RSI ; 1F: 488BFB MOV RDI, RBX ; 22: 41BBC0010020 MOV R11D, 536871360 ; GENERIC-+ ; 28: 41FFD3 CALL R11 ; 2B: 488B5DE8 MOV RBX, [RBP-24] ; 2F: 488B75F0 MOV RSI, [RBP-16] ; 33: 488BE5 MOV RSP, RBP ; 36: F8 CLC ; 37: 5D POP RBP ; 38: C3 RET ; 39: CC10 BREAK 16 ; Invalid argument count trap
mac [x y], every time the word mac is in the source code somewhere it will attempt to expand
'
what makes difference, in CL you can tell what's data and what is the code during parsingseem
easy, but it's not easy inside :Dspace: #" " text: [5 "Test"] space-to-tab: true tab-width: 4 append-space-indent: func [ tab-num ] [ loop (tab-num * tab-width) [append output-text tab] ] append-tab-indent: func [ tab-num ] [ loop tab-num [append output-text space] ] file-save: does [ output-text: copy [] either space-to-tab [append-indent: :append-tab-indent] [append-indent: :append-space-indent] foreach [tab-num t ] text [ if tab-num > 0 [ append-indent tab-num ] ] probe output-text ] file-save
str: "" loop 10 [append str #"x"]
function
collects set-words
not words, so "leaking words" is improper, as it does not collect words. For the rest, it makes no sense in languages like Redbol, as they don't have scopes (only an illusion of scopes constructed at runtime, called "definitional scoping").var
which will keep variable in local contextvar
-like construct makes no sense, as it implies scopes.write
, that is changing word's value and assign
which is creating a new binding are two different things.load
, bind
or a context constructor), and setting a word to a value (in a context) using a set-word or set
function, are two differnt operations.a
to 5, the second will set it to 6 (assuming both a:
are bound to the same context).print d
I would like d
to be searched in outer contexts as welllayout
is used to transform VID block
into tree of faces
, and view in turn is used to actually show GUI from a face treelayout
isn't mandatory?view
. But in some cases, you might want to apply manual transformations to the face tree before passing it to view
, so you will use layout
separately in such cases. For example:win: layout [button "ok"] win/size: 200x200 uppercase win/pane/1/text view win
red
pill becomes more deeper...foo: function [][ set load "a" 123 set load http://domain.com/get-name 456 ;-- would return "b" ]
set first random [a b c] 789
set
could add word to current contextload
system/words
and ask load
to use this object instead, would it make sense?make
), in Rebol3, object can be extended using series actions. I was not for that change, as it was blurring the lines between objects and series (not even mentioning maps). I personnaly had no need for expandable objects, just maybe for some specific cases, where reconstructing the whole objects with the right binding would have been too expensive/complex. So I was in favor of just an extend
native, which would allow extending objects in-place (and would work only on objects, so avoiding confusion with series). In Red, I plan to add extend
, though, it would probably make objects access path compilation much less efficient a priori, so I need to find a way to avoid the speed penalty for that first.module!
type. We will introduce it in 0.8.0. It would also provide boundaries for macro expansions (@JacobGood1 ;-)) and modular compilation support.func
word correctly? as in func
creates context, then finds all it's arguments words in the body, binds them to this context, and on evaluation assigns passed parameters to context so each corresponding word in function will be evaluated to this value?none
and a logic value (depending if the refinement was used at call site or not).func
is just a (convenient) shortcut for make function!
by the way. Note that Red follows R3 in this case, with a fixed-arity make
action (variable-arity in R2).strip-words: function [code][ parse code rule: [any [ p: word! (p/1: to-get-word p/1) | any-string! | into rule | skip ]] reduce code ] do probe strip-words [append "=" mold add 1 2]
probe
. ;-) That is another important feature of Redbol: all values are anonymous (including functions, objects, context,...). If you're not convinced, tell me the name of the following function: set [foo bar] func [ ][print "hello"] :foo == func [][print "hello"] :bar == func [][print "hello"]
strip-words
example is cool though, thanks:anythingyouwant
and it will never fail :D:never-gonna-give-you-up-never-gonna-let-you-down
get/any 'anythingyouwant
, though I still feel uncomfortable about it (being too used to Rebol2's way).red>> n: 600'851'475'143 *** Syntax Error: invalid value at "600'851'47" *** Where: do
red>> n: 600'851'475'1 == 1713547455
Red [ Title: "Largest prime factor" Description: { The prime factors of 13195 are 5, 7, 13 and 29. What is the largest prime factor of the number 600851475143 ? } Date: "13-Dec-2016" Author: "9214" ] n: 600'851'475'143 print form compose [ the largest prime factor of the number (n) is (last collect [repeat i to integer! sqrt n [if all [odd? i n // i = 0] [n: n / i keep i]]]) ]
extend
, but it looks like it's already defined... Also, wouldn't it be necessary for adding new words to system/words
?red>> n: 600'851'475'143 == 600851475143.0 red>> n: 600'851'475'1 == 6008514751.0
system/words
is a special context, which is managed by low-level code from the Red runtime library and by the compiler (for compiled user code), so it doesn't have the same constraints as contexts managed by users.foo: function [][ probe set load "a" 123 probe set load http://domain.com/get-name 456 ;-- would return "b" ]
red>> foo 123 *** Script Error: set does not allow none! for its word argument *** Where: set
load http://domain.com/get-name
returns none
, it just an example usage, normally it should return a word.>> n: 600'851'475'143 == 600851475143.0 >> system/build/date == "16-Mar-2017/13:55:07+5:00"
red>> n: 600'851'475'143 *** Syntax Error: invalid value at "600'851'47" *** Where: do red>> system/build == "15-Mar-2017/14:34:50+5:00"
bind
somewhere inside foo
body, but I can't wrap my head around it... any ideas?Red [] i: 111 foo: function [ 'x [word!] bump [integer!] case-block [block!] ][ repeat :x bump [ case case-block ] ] foo i 10 [ even? i [print "even!"] odd? i [print "odd!"] ] print system/words/i ; => should be 111
... 10
old-i: :i foo i 10 [ even? i [print "even!"] odd? i [print "odd!"] ] i: old-i
Red [] i: 111 foo: function [ 'x [word!] bump [integer!] case-block [block!] ][ old: get x bind case-block :foo repeat :x bump [ case case-block ] set x old ] foo i 10 [ even? i [print "even!"] odd? i [print "odd!"] ] print system/words/i
use
function (like in Rebol), you could wrap the body of foo
into a use reduce [x][...]
and avoid the manual saving/restoring of x
.use
do internally?use
?bind case-block :foo
partuse
is optimized for that single usage scenario.i
remains global, as iterators in Red are not creating local contexts (yet). It should work in Rebol (using a local word as bind
's target, instead of the function reference).bind
is useless in such use-case, I overlooked it.Red [] x: 1 foo: does [ context [ x: 2 return x ] ] print foo ; 2 print x ; 1
Red [] i: 111 use: func [spec [block!] body [block!]][ body: has spec bind body 'body do body ] foo: function [ 'x [word!] bump [integer!] case-block [block!] ][ use reduce [x] compose [ bind case-block :body repeat (x) bump [case case-block] ] ] foo i 10 [ even? i [print "even!"] odd? i [print "odd!"] ] i
use reduce [x] compose/deep/only [ repeat (x) bump [case (case-block)] ]
context
is a synonym for object
(which is simply word
--value
mapping)?load
time (source as text to Red values).func [a b c /local ] [...]
there's multiple rounds of bindings for every nested construct?func
, so only one binding pass, which will match every local word.func
lisp list: [a a a] ctx: reduce [context [a: 1] context [a: 2] context [a: 3]] repeat i length? list [bind at list i ctx/:i] list == [a a a] reduce list == [1 2 3]
list
will be rebound 3 times, but each time starting at an offset moved by one, so the left elements are not rebound, only the right ones. ;-) Note: once we add HOF iterators, such code examples should look nicer. ;-)a
will point to a specific context where it's boundmy-context: context [a: 1]
my-context
will be bounded to "default" (i.e. global) context, and a
will be bound to ...?my-context
is (illusory) nested inside global contextmy-context
symbol. That reference can be removed at any time, or other references can be created in the global context, or in another context, or in a block (anything that can contain a value).my-context
was constructed ofc (and how exactly this happening?)a
will be rebound to the context referred to by my-context
word. ;-) Keep in mind the separation between a word and the value it refers to. Words are not "variables" (label on a value) in Redbol, but first-class values themselves."my-context: context [a: 1]"
is LOADed as [my-context: context [a: 1]]
(all words there are bound to global context).my-context:
is a set-word!, so a value is fetched for it.context
is a function call requiring a single argument ([a: 1]
), so it is evaluated.a
as the only entry. The [a: 1]
block is rebound to that context and then evaluated.1
is associated to a
in the newly created context.my-context
entry in the global context is associated to the context value that was created at 4.a: 1
, there's still a: 1
entry inside global context?context
will bind
its body block just after gathering all the set-words it contains to create the new context (with all value entries preset as unset
). Same happens for func
or function
.a: unset
?a: 1
in local?catch-all
and will auto-expand for new words, setting them to unset
until they eventually get set to some other value. This special behavior is unique to the global context in Rebol2 and Red, but Rebol3 generalizes it to "modules" (of type module!
). Red will get them in 0.8.0.set-word!
is bounded to a global context with unset
value, and every word!
..?word!
load
is some sort of bridge between outter world with strings
and Redbolland with blocks
and other values? :Dany-word!
is bound to global context.load
is the lexer that converts a text representation of Red values, to Red values in memory. So that everything exists *only* as data at this point.module!
mean to improve this?bound [a: 1] to new context
part thoughtest.red
with:Red [] f: function [n][ c: 0 loop n [ prin 1 c: c + 1 if c > 10 [quit] ] ] f "hello"
% red test.red *** Script Error: loop does not allow string! for its count argument *** Where: loop
red -c -r test.red
and run it:% ./test 11111111111
loop
doesn't complain about the wrong argument type and would run indefinitely.loop
should not run with an argument of type string!
, what about type checking in compiled code, should it return the same error as the interpreter or should one specify arguments type for compiled code?Red [] f: function [ n [integer!] ][ c: 0 loop n [ prin 1 c: c + 1 if c > 10 [quit] ] ] f "hello"
*** Script Error: f does not allow string! for its n argument *** Where: f *** Stack: f
repeat
isn't a context constructor, so i
word is still bounded to global context during iteration?1
after compilation'x
word at load-time and run-time? Is it bounded or skipped somehow? i
is still bounded to global context - because there's no i
word inside foo
spec, hence new context will be constructed without i
entry?foo
? (jeez, lots of questions!)>> foo: func [/local c][print mold context? 'c] == func [/local c][print mold context? 'c] >> foo ; invoke the function to get the printout func [/local c][print mold context? 'c]
foreach
in Redbol?lang-list: [2 "Rebol" 3 "Rebol" 0 "Red"] line-num: 0 foreach [version r-dialect] lang-list [ print rejoin [ line-num: line-num + 1 " " r-dialect " " version ] ]
foo
is :foo
* That is not accurate, the context is a property of a function, the context is not the function. context?
returns the function itself if the argument word is bound to a function, because contexts are not first-class values, so for convience, the function! value itself is returned (so it can be manipulated by the user, doing, e.g., comparisons)function
constructor, then the iterator words will be locally bound to that function's context.loop
in the compiler.repeat
is a context constructor in Rebol, not yet in Red.'x
is bound to global context at load-time (like any other any-word!
value), then rebound to the function's context at run-time by the function
constructor.context!
type do exist). The closest you could get would be by using words-of :foo
(and values-of :foo
from inside the function), but those reflectors are not yet implemented for functions.[my-context: ...]
loaded result block.[a: 1]
to local context", it really means "bind the words in [a: 1]
to local context".context
is just an alias to object
, so the returned value from context
is an object! value.context?
is not equal to the context, whereas in the case of objects, it is. :worried: context?
returns an object!. There are no first-class context values.>> type? context? in context [a: 0] 'a == object!
lang-list: [2 "R ebol" 3 "Rebol" 0 "Red"] line-num: 0 forever [ print rejoin [ line-num: line-num + 1 " " lang-list/(2 +(line-num * 2)) " " lang-list/(1 +(line-num * 2)) ] if line-num = 2 [break] ]
lang-list: [2 "Rebol" 3 "Rebol" 0 "Red"] line-num: 1 for [version r-dialect] lang-list 2 3 [ print rejoin [ line-num: line-num + 1 " " r-dialect " " version ] ]
for labels series from to
construct make sense in Red?context!
which has no values that the user can make
or otherwise produce... But according to the convention, context?
would be the test function to check if a value is of that type. So I agree with you it is not a good name. I could propose context-of
.lang-list: [2 "Rebol" 3 "Rebol" 0 "Red"] line-num: 0 foreach [version r-dialect] lang-list [ print reform [ line-num: line-num + 1 " " r-dialect " " version ] if line-num = 2 [break] ]
list
with only the displayed range.foreach-range: func[ "Evaluates body for each value in a series limited to range" 'word [word! block!] "Word, or words, to set on each iteration" series [series!] from [integer!] to [integer!] ;beware that `to` is used system word! body [block!] /local index __counter result count ][ if from < 1 [ from: 1] ;or throw error? if 0 >= count: to - from [return] series: skip series (either block? word [length? word][1]) * (from - 1) __counter: 0 index: length? body ;store original body size append body [ __counter: __counter + 1 if __counter > count [break] ] foreach :word series body clear at body index ;remove the code we added to body ] lang-list: [2 "Rebol" 3 "Rebol" 0 "Red" 4 "Scala" 7 "Haxe"] foreach-range [version r-dialect] lang-list 2 4 [ print rejoin [ r-dialect " " version ] ] foreach-range value lang-list 1 4 [probe value]
foreach-range: func[ "Evaluates body for each value in a series limited to range" 'word [word! block!] "Word, or words, to set on each iteration" series [series!] from [integer!] to [integer!] ;beware that `to` is used system word! body [block!] /local __counter __count __body ][ if 0 > __count: (to - from) [return false] from: either from < 1 [0][from - 1] series: skip series from * either block? word [length? word][1] __counter: 0 __body: insert body [ if __counter > __count [break] __counter: __counter + 1 ] foreach :word series body remove/part body __body ;remove the code we added to body true ]
todo: [print [a c]] foreach-range [a b c d] lang-list 1 1 todo probe todo ; just a test if the action code is really as before
forall
in case like your mentioned editor. There is always many ways how to do things.forall
and just used, that the series is holding its position (that would be the start) and then just simple loop with number of lines.lang-list: [2 "Rebol" 3 "Rebol" 0 "Red"] line-num: 0 list: skip lang-list 4 while [not tail? list][ set [version r-dialect] list print [ line-num: line-num + 1 " " r-dialect " " version ] if line-num = 2 [break] list: skip list 2 ]
list: skip list...
parts, you can write your own iterator abstracting that (as shown by @Oldes).loop
REP in the wiki which should cover such needs though. I would like to implement it when we'll find time, extending the existing loop
function.set
is setting version
and r-dialect
as global.function
constructor would avoid manually declaring them:function [][ ... set [version: r-dialect:] list ... ]
for
in the REP...I've already renamed it to loop
in my head. ;-)qux
word will be bounded, since it's /local
..?>> bar: 'whatever == whatever >> foo: func [bar /local qux] [return (context? 'bar) = :foo] == func [bar /local qux][return (context? 'bar) = :foo] >> foo 'boo-hoo == true
red>> context? 'test == make object! [ datatype!: datatype! unset!: unset! none!: none! logic!: logic! block!: block! paren!: paren! string!: string! file!: file! url!: url! char!: char! integer!: integer! float!: float! symbol!: unset
>> mold :test == "unset"
load
-time all any-word!
values are bounded to global context by default>> (context? 'abracadabra) = system/words == true >> (context? 'whatever-its-all-the-same) = system/words == true
load
) which parses string context?
and spits out [context? a Red block with all words in it bounded to global context
red>> context? 'cat == make object! [ datatype!: datatype! unset!: unset! none!: none! logic!: logic! block!: block! paren!: paren! string!: string! file!: file! url!: url! char!: char! integer!: integer! float!: float! symbol!: unset
help system/words
caps-lock unset! unset num-lock unset! unset cat unset! unset
context? #issue
though :confused: equal? source context source object
name-space: :context
context
and object
are essentially the same (to my believe), though I don't know much about it's internal representation (context!
type?)#
inside system/words
, could it be a bug? #
)?issue!
is any-word!
: red>> type? #abcd == issue! red>> any-word? #abcd == true
any-string!
in R2.context?
does not add word to system/words but the console.context? 'test probe last words-of system/words
test
on console, but not when it is compiled.system/script
and system/options
. When I compileRed [ field: 'value ] print system/script/header
none
. What do I do wrong?any-word!
it will be bounded at load
time just like anything else, thanks!system/script/header
is not implemented yet.system/script/header
will be filled, I can see the following considerations: will you require a sequence of :
pairs, and if not, what will be the consequence of other items within the block, e.g. set
like in the spec of make object!
? system/script/header
to the header block, without any evaluation. But maybe forcing it to an object like Rebol would be better, as we can provide a prototype with default fields. Even in such case, I would block evaluation (using construct
).c> f: func ["short string" "and long string, tadadam"] [] == func ["short string" "and long string, tadadam"][] c> help f USAGE: f DESCRIPTION: short string. f is of type: function! ARGUMENTS: REFINEMENTS:
>> foo: func [ [ { oh [ how [ I [ love [ to [ write [ long [ detailed [ documentation [ in [ a [ header [ of [ my [ lovely [ function [ ! [ }][] == func [ { oh^/how^/I^/love^/to^/write^/long^/detailed^/documentation^/in^/a^/header^/of^/my^/lovely^/function^/!^/} ][] >> ? foo USAGE: foo DESCRIPTION: oh how I love to write long detailed documentation in a header of my lovely function ! . foo is of type: function! ARGUMENTS: REFINEMENTS: >>
help
does not expect newlines or actually any formatting at all in docstring. But as you can see, it is possible to store it there.help2
function that would accept docstrings in Markdown format, Red does not prevent you from doing that.helpr
, it basically does it.>> foo: func ["first" "second" "third"][] == func ["first" "second" "third"][] >> second spec-of :foo == "second"
parse
it or whatever, even entire blockc> f: func ["help string" http://www.red-help.com/f] []
gen-doc file-or-directory format
spec
blocks, parse
them, save in a file, something like thatspec
s ?red>> succ: func [s [string!] /local c][c: (to-integer last s) + 1 [ replace s last s to-char c [ ] == func [s [string!] /local c][c: (to-integer last s) + 1 replace s last s to-char c ] red>> succ "cat" == "cau" red>> succ "zaz" == "{az" red>> loop 10 [print succ "aa"] ba bb cb cc dc dd ed ee fe ff
c> succ: func [s] [c: (to-integer last s) + 1 change back tail s to-char c s] == func [s][c: (to-integer last s) + 1 change back tail s to-char c s... c> succ "zaz" == "za{"
last
returns value, not position in series.last
doesn't return position.back tail
returned a positionindex?
help replace
doesn't seem to mention first occurrence. :smile: succ
func. I have something I can port to Red, though you can learn a lot doing it too.step
.step-back
function. As I looked at my code, the magic range markers bothered me. Now I know why. ;^)red>> al-num == [48 49 50 51 52 53 54 55 56 57 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 ]
a
word to point to c
context, while saving a: 1
entry in a global one. Can't wrap my head around it :confused:Red [] c: context [a: 2] a: 1 bind 'a c print a ; want it to be 2
Bind
returns the bound word, but where would Red save the old binding? You would need to use context?
and store the original binding yourself. You can also use in
to get a word bound to a specific context.>> c: context [a: 2] == make object! [ a: 2 ] >> a: 1 == 1 >> ac: context? 'a == make object! [ datatype!: datatype! unset!: unset! none!: none! logic!: logic! block!: block! paren!: paren! string!: string! file!: file! >> set 'a bind 'a c == a >> print a a >> print get a 2 >> get in c 'a == 2
word
has a binding
.binding
is kinda of a pointer to a specific context
. context
is a namespace with entrys, every entry is a word: value
pair, simpy speaking. Is everything correct?binding
of a word
I change a pointer to a different context
, there this word
has some entry with associated value, is that so?bind
. Am I wrong?Red [] c: context [a: 2] a: 1 blk: [a] bind blk c ; i.e. bind all words (`a` word) in a block to a context print reduce blk ; 2 print a ; 1
in
is an alternative for path synthax? in obj 'foo
is the same as obj/foo
to my believe.in
b?" in
ned?bind
but positions reversed. So bind
itself might not mean what you think.. print :in = :bind
:smile: a: 1
, but in local we have a: 2
.a
word is bounded to a global context, there it has associated entry a: 1
, hence it's value is 1
.a
binding, I should use bind 'a local-context
. Now, in this local context, a
has associated entry a: 2
, hence its value should be 2
.a: 1
entry in a global context to which I can revert back with bind 'a global-context
.Red [] c: context [a: 2] a: 1 print equal? (probe context? in c 'a) (probe context? bind 'a c)
bind/copy
is used on blocks (see p 3.4 [here](http://www.pat665.free.fr/doc/bind.html)), not sure how it can help with word
s thoughin
?](https://stackoverflow.com/questions/21059228/how-to-use-in-with-a-block-instead-of-an-object/39812409#comment66916104_39812409)bind
is from in
red>> o: make object! [ a: 1 set 'b 2] == make object! [ a: 1 ] red>> o/a == 1 red>> o/b *** Script Error: cannot access b in path o/b *** Where: catch red>> b == 2
red>> b == 2 red>> get 'b == 2 red>> get 'a *** Script Error: a has no value *** Where: get red>> get in o 'a == 1
word
s is completely wrong. I know that it's a structure with a text representation and a pointer to the context, but... uhm... do they "exist" *inside* or *outside* of contexts?word!
value is something external to a context
, then I don't get why I can't change its pointer and make it refer to a different context where word will have different value (meaning)ain one context can mean 1, in another context it can mean
"This is mine.".
word -- meaning
pairs. Does that mean that actual word
is that exact word
part inside word -- meaning
pair?Word
es and Doctor Bind
son, or "Zen and The Art of Scope Maintenance: An Inquiry into Context
s" :bulb: block
is kinda misleading thoughprint
a
in default context. Even simpler version:c: context [a: 2] bind 'a (context? in c 'a) ; No error here. (parens aren't needed) print a ;there is no a in default context, hence an error occurred print get in c 'a ; == 2
c: context [a: 2] b: in c 'a ;b bounds to c *now* get b ; == 2 context? b ; == make object! [a: 2]
bind
or in
will just rebind the argument value, other words (with same symbol) are unaffected. Each word is an instance of a symbol (internal symbol!
type), and exists independently of all others. bind
and in
will return their arguments bound, you need to use that rebound value in your example:c: context [a: 2] new: bind 'a (context? in c 'a) print new ; == 2 print get in c 'a ; == 2
:a
instead of context? in c 'a
(strictly equivalent).:c
.any-word!
word consists of symbol!
part (its textual representation), object!
reference part (pointer to a context) and value part of some type.system
block compared to system/words
?any-word!
in my code is more like | symbol | context! reference | index |
under the hood?any-word!
in my code is more like | symbol | context! reference | index |
under the hood?block!
or paren!
).context pointer
part to point to some different context, leaving older context entry as it was? a: 1
and a: 2
are entrys in different context; when I've encountered a
word which points to the first a: 1
, why can't I alter this word to point to the second one a: 2
, leaving a: 1
as it was without any changes?bind
.load
phase script itself is a blocklisp a: 0 one: context [a: 1] b: [a] print bind b/1 one ; == 1 print b ; == 0 bind b one print b ; == 1
block
the bind
change is kinda persistent, but without one it has zero effect, just returns a value?bind
is quite dumb, it will simply process the argument you provide on the stack. As you can only get the return value back from the stack, if you pass a scalar value (word! value in this case) and do not use the returned value (rebound new word), your bind
call will have produced no effect.copy
or the /copy
refinement of bind
(which avoids an extra internal copy do be done).a:
?bind
.bind
called on a block will just traverse a block looking for a values available in a context and bind these words to the context?red>> a: 1 == 1 red>> ctx: context [a: 2] == make object! [ a: 2 ] red>> get bind 'a ctx == 2 red>> a == 1
a
is totally new worda
and a
are two completely different words, just happend to be named with the same symbol makes total sense nowbind
works like I expect with blocks but not with bare-bone words, now I see that (I think)bind
does the same job, it's just that words with same symbol are not inter-connected (other than sharing the same symbol ID). A new word (sent to input in the case above) is by default bound to global context, no matter what you did to a previous word with the same spelling. Now you start to realize how far the "variables" concept from other languages can be. ;-)bind 'a context
means "find a
in a *current* context..." but that's BS since there's no **current** contextfind a in current context
- makes little sense, you can only find value of a
in context, right?'x
; now, let us make our spoon to be just a "spoon" set 'spoon bind 'spoon third contexts ; <-- at this part I've started doubting myself and started a discussion print spoon print reduce shelf-with-spoons comment { however, last entry changed too! how can we avoid that? <-- use poke on a series..? }
spoon
in a block should be rebounded somehow, to keep an old string value?bind back tail shelf-with-spoons make object! [spoon: "take the RED pill"] print reduce shelf-with-spoons print spoon
78
line, bind back tail shelf-with-spoons context [spoon: "take the RED pill"]
spoon: "take the RED pill"
which was entered in a script later... somehowsystem/console/history
for that? ;)Red [] ; 1 ; 2 a: 1 ; 3 a: 2 ; 4 ; 5 1336 + <`a` at line 3 inside LOADed block> ; --> 1337
1337.red
file, then:h4x0r: load %1337.red h4x0r/9: h4x0r/4 do h4x0r
h4x0r: load
load/header
c> script: load/header %json.red == [Red [ Title: "JSON parser" File: %json.red Author: ... c> script/2 == [ Title: "JSON parser" File: %json.red Author: "Nena... c> script/2/file == %json.red
Red [File: %1337.red]
, though, Red does not yet store the header info in system object (Rebol does).file
entry from a header :confused:, what's the point?in
and bind
](https://stackoverflow.com/questions/42907481/how-is-bind-and-in-different)c
?red>> c: context [a: 2] == make object! [ a: 2 ] red>> new: bind 'a c == a red>> print get new 2
context? in c 'a
context? ...
part, as it related to in
, but we could remove it. c
and :c
should be the same for a context. Maybe Nenad can confirm is there are any subtle differences.same?
says they're the same, but...word
is it's context! pointer
part? And to change the value of a word, one should alter the entry in a context
to which word refers?any-word!
is a scalar value, it will be pushed onto stack, rebounded, and then poped off. To save that rebinding I should set
that word to its rebinded alternative.series!
is a non-scalar type, it's passed by a refference... a-a-and? I don't get the whole mechanism :( How do word
s reside inside a container?syntax -> symantics
, in a very high level wayc
?:c
for objects as they evaluate to themselves, though the get-word is required in case of functions (or in the not-too-distant future, closures).block
is essentialy a chunk of memory?block
(i.e. some word should be setted to point to that block), or it will be wiped out with GC (?)bind
a block, every any-word!
scalar value in it will be rebinded (i.e. its context reference will be changed), but block will still reside in a memory, because there's still a pointer to it?>> a: "hello" == "hello" >> next a == "ello" >> a == "hello" >> a: next a == "ello" >> a == "ello"
head a
afterwards?a: head a
>> a: "hello" == "hello" >> b: next a == "ello" >> c: skip a 3 == "lo" >> d: tail a == "" >> reduce [a b c d] == ["hello" "ello" "lo" ""] >> foreach s [a b c d][print index? get s] 1 2 4 6
[a b c d]
all 4 words are slot values, pointing to one shared buffer?h
and to the right of last o
"?| left boundary | current offset | right boundary |
under the hood?emit: func [c [byte!]][ write stdout :c 1 ]
c
is not enough?get-word!
meaning is different at the R/S level.>> nums: [0 1 2 3 4 5 6 7 8 9 0] == [0 1 2 3 4 5 6 7 8 9 0] >> cycle-n: func [n][select nums n] == func [n][select nums n] >> n: 0 == 0 >> n: cycle-n n == 1 >> n: cycle-n n == 2 >> n: cycle-n n == 3 ... >> n: cycle-n n == 9 >> n: cycle-n n == 0
select
:>> vals: [a #test 5x5 8 "key" %file 10% a] == [a #test 5x5 8 "key" %file 10% a] >> val: 'a == a >> cycle: func [v][select vals v] == func [v][select vals v] >> loop 7 [probe val: cycle val] #test 5x5 8 "key" %file 10% a == a
cycle
, using select/only
we can support blocks too.>> vals: [[a #test] [5x5 8] ["key" %file 10%] [a #test]] == [[a #test] [5x5 8] ["key" %file 10%] [a #test]] >> val: vals/1 == [a #test] >> cycle: func [v][select/only vals v] == func [v][select/only vals v] >> loop length? vals [probe val: cycle val] [5x5 8] ["key" %file 10%] [a #test] [5x5 8] == [5x5 8]
cycler: context [ _data: none _key: none set-data: func [data [block!]][ _data: copy data ; Should we make sure the data conforms to our needs? ;if (last data) <> (first data) [ append/only _data first _data ;] _key: last data ] take: does [_key: select/only _data _key] test: does [loop length? _data [probe take]] ] cyc: make cycler [] cyc/set-data [0 1 2 3 4 5 6 7 8 9] cyc/test cyc: make cycler [] cyc/set-data [a #test 5x5 8 "key" %file 10%] cyc/test cyc: make cycler [] cyc/set-data [[a #test] [5x5 8] ["key" %file 10%]] cyc/test
; @JacobGood's closure func closure: 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)] ] cycler: func [block [block!]][ closure compose/only [block: (block)] [/reset] [ if reset [block: head block exit] if tail? block [block: head block] also first block block: next block ] ] test-cyc: func [cyc-fn [function!]][loop 7 [probe cyc-fn]] cyc: cycler [1 2 3 4 5] test-cyc :cyc cyc: cycler [a #test 5x5 8 "key" %file 10%] test-cyc :cyc cyc: cycler [[a #test] [5x5 8] ["key" %file 10%]] test-cyc :cyc
/reset
refinement, should it exit
or should it return the first value, which would let us use any [reset tail? block]
and remove some redundancy?; @JacobGood's closure func closure: 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)] ] cycler: func [block [block!]][ closure compose/only [block: (block)] [/reset] [ if any [reset tail? block] [block: head block] also first block block: next block ] ] test-cyc: func [cyc-fn [function!]][loop 7 [probe cyc-fn]] cyc: cycler [1 2 3 4 5] test-cyc :cyc cyc: cycler [a #test 5x5 8 "key" %file 10%] test-cyc :cyc cyc: cycler [[a #test] [5x5 8] ["key" %file 10%]] test-cyc :cyc
Size: 7kb
now that's the spiritscheduler
and use it in production. do load
it wherever I feel like using it. solution.
I changed the line
0 >= count into
0 > count so range 1 1 would work.
Since few people need it,
:)
to
is used system word!
`foreach-range
adoption report.foreach-range
, if you find it useful.. I did it just for fun.foreach-range
.for
proposal. https://github.com/red/red/wiki/REP-0101---For-loop-functionnative!
word if they feel like it at the "bare metal level" just as in Forth?native!
(quite easy), just cannot expect it will be merged into official repository.Loop macro
in http://www.red-lang.org/ (shame it is not possible to link it directly)prin "no newline " prin "add a newline manually" prin newline ; "^/"
>> blk: ["name: " name " birthday: " birthday " phone: " phone] == ["name: " name " birthday: " birthday " phone: " phone] >> block? blk == true
#[...]
) that will be a special case that's related.prin
evaluate the block so that the labels got expanded to their values?words
:)prin/print
reduces the block.string!
values evaluate to themselves, and values associated with word!
s are fetched from their contexts (?)sum-letters: func [str [string!] /local alpha acc][ acc: 0 alpha: "abcdefghijklmnopqrstuvwxyz" foreach c str [acc: acc + index? find alpha c] ]
sum-letters "greg tewalt"
parse
.sum-letters: func [str [string!] /local alpha acc val][ acc: 0 alpha: "abcdefghijklmnopqrstuvwxyz" foreach c str [ if val: find alpha c [ acc: acc + index? val ] ] ]
none
?sum-letters: func [str [string!] /local alpha acc val][ acc: 0 alpha: charset [#"a" - #"z"] parse str [ some [ set val alpha (acc: acc + (to integer! val) - 96) | skip ] ] acc ]
sum-letters: func [str [string!] /local alpha acc][ acc: 0 alpha: "abcdefghijklmnopqrstuvwxyz" foreach c str [ if find alpha c [acc: acc + index? find alpha c]] ]
reduce-integer sum-letters "bla bla bla"
>> type? read http://www.rebol.com == string! >> sum-letters read http://www.rebol.com == none >> data: read http://www.rebol.com == {<!doctype html>^/<html><head>^/<meta name="generator" content="REBOL >> type? data == string!
^
character?>> type? "{<!doctype>^" *** Syntax Error: invalid value at {"^{<!doctype>^^"} *** Where: do
sum-letters: func [str [string!] /local alpha acc val][ acc: 0 alpha: "abcdefghijklmnopqrstuvwxyz" foreach c str [ either val: find alpha c [acc: acc + index? val][acc: acc + 0]] ]
>> sum-letters read http://www.rebol.com == 50256 >> sum-letters read http://www.google.com *** Access Error: invalid UTF-8 encoding: #{A050726F} *** Where: read >> sum-letters read http://www.yahoo.com == 3755672
sum-letters
is for a numerology game. a = 1, b = 2, etc.find
a lot. Bolek's parse version shows how to avoid that. You can use if
instead of either
, because you don't need to add 0 if there's no match. You can avoid find
without parse as well.sum-letters-ltgt: func [str [string!] /local acc][ acc: 0 foreach c str [ if all [c >= #"a" c <= #"z"] [acc: acc + (c - 96)] ] acc ]
either
you could hoist acc:
to the front, so you're not repeating it in each condition block.sum-letters: func [str [string!] /local alpha acc val][ acc: 0 alpha: "abcdefghijklmnopqrstuvwxyz" foreach c str [ acc: acc + either val: find alpha c [index? val][0] ] ]
acc
at the end of the func, because funcs return the last evaluated value. If the last char isn't a-z, the if
block isn't used, and if
returns none
.- 96
maps to those values for your range.a-z-count: routine [ str [string!] return: [integer!] /local s [series!] unit [integer!] pos [byte-ptr!] head [byte-ptr!] tail [byte-ptr!] n [integer!] ch [integer!] ][ s: GET_BUFFER(str) unit: GET_UNIT(s) head: (as byte-ptr! s/offset) + (str/head << (log-b unit)) pos: head tail: as byte-ptr! s/tail n: 0 while [pos < tail][ ch: string/get-char pos unit if all [ch >= 65 ch <= 90] [n: n + ch - 64] if all [ch >= 97 ch <= 122] [n: n + ch - 96] pos: pos + unit ] n ]
find
takes ~0.5s. R/S takes 0.01s.a-z-count-latin-1: routine [ str [string!] return: [integer!] /local s [series!] pos [byte-ptr!] tail [byte-ptr!] n [integer!] ch [integer!] ][ s: GET_BUFFER(str) pos: as byte-ptr! s/offset tail: as byte-ptr! s/tail n: 0 while [pos < tail][ ch: as-integer pos/value if all [ch >= 65 ch <= 90] [n: n + ch - 64] if all [ch >= 97 ch <= 122] [n: n + ch - 96] pos: pos + 1 ] n ]
alpha: "abcdefghijklmnopqrstuvwxyz"
, you can create a bitset which would be way more faster for lookups: alpha: charset [#"a" - #"z"]
. With the string form, each find
is a linear search (O(n)), while with the charset, it's a direct lookup in an array, so constant time (O(1)).sum-letters: func [str [string!] /local alpha acc][ acc: 0 alpha: charset [#"a" - #"z"] str: lowercase str foreach c str [ acc: acc + either find alpha c [c - 96][0]] ]
lowercase
that slows it up a little?time-it: func [block /count ct /local t baseline][ ct: any [ct 1] t: now/time/precise loop ct [do []] baseline: now/time/precise - t t: now/time/precise loop ct [do block] now/time/precise - t - baseline ]
{Hi there my name is } {Bob Jones}
do [ code: ask {Enter some code: } ; for example, {print "hello"} do append {print "Here's your running code..."} code ]
append {"Here's your running code..."} do code
code
can be anything you type. So the resulting code is just preceded by a line that print "Here's your running code..." in the console. To me, there is a missing space at the end of the string to have good Red code.do [ code: ask {Enter some code: } ; for example, {print "hello"} do append {print "Here's your running code..." } code ]
x: 2 y: 10 square-root x * x + (y * y)
, then append will just join it to the string.{print "Here's your running code..." x: 2 y: 10 square-root x * x + (y * y)}
.print
inside a string is just a bunch of symbols, but after appending and calling do
, {print "Here's your running code..." }
become [print "Here's your running code..." ]
- a valid Red block which can be evaluated.
parse
power, what I mean is some kind of "unconventional" use of atomic parts of a languageRed [title: "test" needs: 'view] view [ below text "Some action examples. Try using each widget:" button red "Click Me" [ print "You clicked the red button." ] f: field 400 "Type some text here, then press [Enter]" [ print f/text ] t: text-list 400x300 data ["Select this" "Then this" "Now this"][ [print pick t/data t/selected] ] check yellow [print "You clicked the yellow check box."] button "Quit" [unview] ]
copy []
instead of just []
... I set it just []
and it worked just fine:Red [title: "test" needs: 'view] gui: [] foreach color [red green blue] [ append gui reduce ['text color] ] view layout gui
[print pick t/data t/selected]
instead of print pick t/data t/selected
? If you put the code in a block, then the block evaluates to itself, and nothing happens.gui: []
is setting always gui
to the same block, so in some cases, you need to copy
it to start with a new empty one. For example:loop 3 [ gui: [] append gui 0 probe gui] loop 3 [ gui: copy [] append gui 0 probe gui]
copy
, saves you from lots of headaches laterLocal variables that hold series need to be copied if the series is used multiple times. For example, if you want the stars string to be the same each time you call the start-name function, you should write: star-name: func [name] [ stars: copy "**" insert next stars name stars ] Otherwise, if you write: star-name: func [name] [ stars: "**" insert next stars name stars ] you will be using the same string each time and each time the function is used the previous name will appear within the result. print star-name "test" *test* print star-name "this" *thistest*
copy
on series!
is important to understand. Examine the following examples:>> f: has [s] [s: "" append s form random 9] >> f == "4" >> f == "46" >> f == "464" >> f: has [s] [s: copy "" append s form random 9] >> f == "3" >> f == "6" >> f == "5"
call
could be used to wrap eventual Curl functionality, if it exists ...call
is the way to go for now, there are should be terminal applications to send emalssimple-io
stack under Linux and macOS me thinks. Here's quick example - http://stackoverflow.com/questions/14722556/using-curl-to-send-emailred>> f: func [x /local o] [ o: object compose [x: (x) my-closure: func [] [x: x + 1]] :o/my-closure ] == func [x /local o][o: object compose [x: (x) my-closure: func [] [x... red>> g: f 5 == func [][x: x + 1] red>> g == 6 red>> g == 7 red>> g == 8 red>> g == 9 red>> x *** Script Error: x has no value *** Where: catch
block
as an argument and bind what's needed inside, but HOF can do the same using functions only.*
(match any char) in Parse?skip
for thatskip
need an offset (number of chars to skip)?red>> parse [a b c] [2 skip 'c] == true
any skip
? :)to end
. that also matches everything.skip
hereskip
, true*-each
style funcs, the block model works really well, but I haven't tried it where more rebinding was used, or layered calls. I imagine a lot of functional people will want a more traditional approach, using funcs. If Red doesn't build them in, they'll create various libs for them. Blocks are cleaner than inline func
lambdas, but func args for existing funcs can be cleaner still, in some cases. help
implementation in pretty good shape. Should I have Peter, Oldes, or Bolek review first, to see if they have suggestions before taking your time? Or should I just put it in a gist for review?help
would be great (in a gist seems appropriate).format
is done?quantum parse dialect
, then build logic gates, registers, FSM... CPU, assembler, OS, userland stuff, etc etc4.2
;)help
.. should the block
in object
be partially visible or should be there just the length of it?>> ? system SYSTEM is an object! with the following words and values: version string! "0.6.1" build object! [date config] words object! [datatype! unset! none! logic! block! pare... platform function! "Return a word identifying the operating s... catalog object! [datatypes actions natives errors] state object! [interpreted? last-error trace?] modules block! [] codecs block! [png make object! [title: "" name: 'PNG mi... schemes object! [] ports object! [] locale object! [language language* locale locale* months ... options object! [boot home path script args do-arg debug s... script object! [title header parent path args] standard object! [header error] lexer object! [pre-load throw-error make-hm make-msf mak... console object! [prompt result history limit catch? count ... view object! [screens event-port metrics fonts platform... reactivity object! [relations stack queue debug? eval eval-re...
>> ? system SYSTEM is an object of value: version string! "0.6.1" build object! [date config] words object! [datatype! unset! none! logic! block! paren! string! file! url! char! integer! f... platform function! Return a word identifying the operating system. catalog object! [datatypes actions natives errors] state object! [interpreted? last-error trace?] modules block! length: 0 codecs block! length: 8 schemes object! [] ports object! [] locale object! [language language* locale locale* months days] options object! [boot home path script args do-arg debug secure quiet binary-base decimal-digits... script object! [title header parent path args] standard object! [header error] lexer object! [pre-load throw-error make-hm make-msf make-hms make-hmsf make-time make-binary ... console object! [prompt result history limit catch? count ws gui? read-argument init-console cou... view none! none reactivity object! [relations stack queue debug? eval eval-reaction on-stack? check is~]
mold/part
or form/part
. I generally prefer a preview of inner content, even if partial. Also, in many cases, the content of blocks in objects will contain valuable data which can fit into a single line.>> mold/part system/codecs 100 == {[png make object! [^/ title: ""^/ name: 'PNG^/ mime-type: [image/png]^/ suffixes: [%.png]^/ }
form/part
?>> form/part system/codecs 100 == {png title: ""^/name: 'PNG^/mime-type: [image/png]^/suffixes: [%.png]^/encode: routine [img [image!]][^/ }
>> mold/flat/part system/codecs 100 == {#(png: make object! [title: "" name: 'PNG mime-type: [image/png] suffixes: [%.png] encode: ro...
b: [{^/^/foo^/^/boo}]
>> trim/lines mold/part system/codecs 100 == {[png make object! [ title: "" name: 'PNG mime-type: [image/png] s...
help
rewrite is up in a gist, for a few people to comment on before opening it up to wider criticism. Since I went in quite a different direction than the original code, I'll state some of my goals in doing so:help
a less monolithic functionred
binary itself?words are fun in Red
Red [] words: load %text-list-words.txt ; Because our words are words and text-list wants strings form-all: func [blk][forall blk [blk/1: form blk/1] blk] form-all words list-cur-text: func [face "text list"] [pick face/data face/selected] list-cur-word: func [face "text list"] [to word! list-cur-text face] view [text-list data words [print list-cur-word face]]
>> call/output "MOVE /Y t1.txt t3.txt" s: copy "" print s 1 file(s) moved. >> read %t3.txt == {^/-=== Red Compiler 0.5.4 ===- ^/^/Compiling /c/dev/git/red/tests/test2.reds
parse "ab cd cdefg" [any [to "cd"] to end]
. Infinite loop? The first to
should be thru
to make it work.forever
.some
parse
less powerful than that? Any
and some
are great, until they're not. Same with to/thru
when they don't work how you first expect, but are correct. But we have options. You can set limits easily with ranges to prevent endless loops. e.g.>> n: 0 parse "ab cd cdefg" [1 1000 [to "cd" (n: n + 1)] to end] == true >> n == 1000
help parse
parse
is too complex to fit the help in the help string. See http://www.red-lang.org/2013/11/041-introducing-parse.html for more informations.red gui-console.red
prin
printing an unset as an empty string here:>> prin "blah" prin :blah print "foo" blahfoo
>> reduce ["a" :test :test :test "ok"] == ["a" unset unset unset "ok"] >> prin ["a" :test :test :test "ok"] a ok
prin
outputs the block, whose form
action is called in preparation. Unset values then also get formed, and they come back as ""
. Block's form
adds spaces between values that don't end in a whitespace char. There is just no special check for empty strings.>> form reduce [:test] == "" >> form reduce [:test :test] == " "
unless
block there would do the trick. Depends on what the result of get-char
is there.part
is the refinement for form
. Shouldn't glance at this while working on other things. Compiling to native code... *** Compilation Error: undefined symbol: get-errno-ptr *** in file: %/C/Users/Old%20Man/Desktop/My%20Changes/runtime/crypto.reds *** in function: red/crypto/init *** at line: 34 *** near: [get-errno-ptr]
...Target: Linux Compiling to native code... *** Compilation Error: a variable is already using the same name: red/crypto/get-errno-ptr *** in file: %/D/Red/crypto.reds *** at line: 278
parse
would be a great example of Red's self-tooling capability. ask/input
, to step trace.parse
again with the stored state.stack
, which is the internal parse rules stack (says a comment). That could be an issue, as there's no way to save and restore that.iterate
and paren
too. We may have all we need.parse/trace
and from the callback, update the GUI and interact with the user (looping on do-events/no-wait
eventually).collect
functionparse
is safely reentrant?push/pop/fetch
events, rather than adding tracing code to every rule. Debugging large parsers on large inputs can be a pain, and this will help with that a lot.parse-trace
is a useful helper utility covering most of my parse debugging. I think I've not advanced enough.. source parse-trace
looks simple. :on-parse-event
however..>> third spec-of :on-parse-event == {Trace events: push, pop, fetch, match, iterate, paren, end}
append copy digit-nz #"0"
over something like union digit charset #"0"
(since the other rules are using union)? Or using the charset range syntax? Does it prevent extra allocations or something?hexa
contain 'F'?union
wasn't implemented when @dockimbel wrote [original version](https://gist.github.com/dockimbel/71f48be60273d9c8d609)? I've just fixed some problems I found when using it with JSONs from GitHub and Gitter, I wasn't doing much rewriting in other areas of code.F
in my repo, I'll take a look at the append
vs union
in the morning.>> print [1 2 print 5] 5 >> print [1 2 print 5] 5 >> print [1 2 prin 5] 5 1 2 >> prin [1 2 print 5] 5 1 2
append copy digit #"0"
is one character shorter than union digit charset "0"
:) Also, it seems to be bit faster (around 15%).charset [#"0" - #"9"]
that's even shorter>> dt: function [code] [t: now/time/precise do code now/time/precise - t] == func [code /local t][t: now/time/precise do code now/time/precise ... >> dt [loop 1000000 [charset [#"0" - #"9"]]] == 0:00:00.616000001
>> probe :f func [code][either error? e: try code [e] [2]] == func [code][either error? e: try code [e] [2]] >> g: func [] [ error? try [return f [5 / 0]] print "test test"] == func [][error? try [return f [5 / 0]] print "test test"] >> g *** Math Error: attempt to divide by zero *** Where: /
a:
is 1
. Once a
is set, the interpreter fetches the next expression: 2
, which evaluates to 2
, then 3
which evaluates to 3
. That being the last result of the list of expressions, it is then returned.1 2 3
?>> reduce [a: 1 2 3] == [1 2 3]
parse
is reentrant, yes, you can call it recursively.append copy digit-nz #"0"
, it looks odd indeed, and I don't see any reason why union
or charset
is not used instead. What I remember clearly though, is that I wrote that JSON code during a very shaky 3h flight, my laptop was jumping on my knees, so that might also explain the missing F
in hexa
definition. :-)try
, you are catching and disarming the error exception. If you want to throw it up again (re-arm it), you need to use do
on the error value: do e
. So, injecting do
in your f
function should give what you expected (as I understand it):>> f: func [code][either error? e: try code [do e] [2]] == func [code][either error? e: try code [do e] [2]] >> g test test
disarm
function for that usage, though, in Red and Rebol3 (IIRC), it's disarmed by default when caught, so you can safely manipulate it, and eventually re-arm it.time-it: func [block /count ct /local t baseline][ ct: any [ct 1] t: now/time/precise loop ct [do []] baseline: now/time/precise - t t: now/time/precise loop ct [do block] now/time/precise - t - baseline ]
>> myfun: func [body /local ret] [ret: do body] == func [body /local ret][ret: do body] >> myfun [print "test"] test *** Script Error: ret: needs a value *** Where: ret
unset!
value. print
is returning an unset!
value, so you need to use the escape mechanism for setting such value: set/any 'ret do body
.unset!
value as return from my function?:ret
should work, thanks! :)set/any
for setting, get-word for getting or get/any
).unset!
type comes handy.word: 'x o/:word
, but is it possible to do the same to set it? o/:word:
gives errorset/any in o :word
in
help in
is not descriptive at all :Dunset
is used to show that there is no value at all, while none
is a valid value :)>> print "hello" hello >>
>> print "hello" hello == none >>
== none
would be confusing, like help
).None
and it doesn't print it as a resultsystem/words/x
is not an error here?>> load "x" == x >> system/words/x >> x *** Script Error: x has no value *** Where: catch
none!
in Redbol is significant, you don't want to hide it.system/words/
prefix uses internally the get-word
semantics. We should probably consider that a bug.o/:word:
does not give an error in my version Red 0.6.2 - 27-Mar-2017/20:46:55+2:00 (W10)>> x *** Script Error: x has no value *** Where: catch >> value? 'x == false >> unset? 'x == false >> unset? :x == true >> value? :x *** Script Error: value? does not allow unset! for its value argument *** Where: value?
>> my-value?: func ['x] [not unset? get/any x] == func ['x][not unset? get/any x] >> my-value? x == false
red -e "print 5 + 5"
?** Script Error: Invalid compressed data - problem: -3 ** Near: script: decapsulate if none? script Process *red* finished
red
is only a wrapper for our toolchain, which acts as a proxy to the console, what you really want is the console executable. So just use the console binary from the Red cache folder, or re-compile one, or use a shell script to wrap red
executable. (python
is equivalent to our console, not to red
, which is the toolchain).--== Red 0.6.2 ==-- Type HELP for starting information. [3C 5 + 5 [8Cprint "hi" [18C 1 [19C
make-comint-in-buffer
runs program and redirects IO to the process and backcallwas introduced). It worked in 2014 \but stopped working sometime ago. #1186
ansi-term
emacs emulator#<STANDARD-CHAR {A49}> -------------------- Char code: 10 Lower cased: @0=#\Newline Upper cased: @0=#\Newline
\n
:Ddo/next
doesn't seem to work in the way that it is explained in the Rebol 2 guideRebol /next -- Do next expression only. Return block with result and new position. Red /next => Do next expression only, return it, update block word. position [word!] => Word updated with new block position.
LF
and conforms to the platform standard when doing I/O, so it outputs CRLF
on Windows, and LF
on other platforms.do/next
in Red uses the better approach from Rebol3 to avoid creation of an extra block for holding both the return value and reference to next expression.>> do/next func [val] [val: val + 1] 'position == func [val][val: val + 1] >> position == [] >> head position == [func [val] [val: val + 1]] >> position == []
do
in Red, when applied to a function value will not fetch the arguments for it, you need to enclose the function call and its argument in a block for proper behavior. The reason for this is that do
is fixed-arity in Red, while it's variable arity in Rebol2/3.do/next [func [val] [val: val + 1]] 'position
[func [val] [val: val + 1]]
block contains a word followed by two blocks. When doing such block, you just invoke func
constructing a function, which is returned as value.lisp >> foo: func [val][val: val + 1] == func [val][val: val + 1] >> code: reduce [:foo 2 3 4] == [func [val][val: val + 1] 2 3 4] >> do/next code 'position == 3 >> position == [3 4]
do
doesn't do deep traversal?do
evaluate each expression it encounters and return the result of the last expression. The evaluation rule for a block is the identity (it evaluates to itself).print
and prin
results?>> prin [print [1 + 2]] 3 3
>> y: function [x] [ error? res: try x res ] == func [x /local res][error? res: try x res] >> z: func [] [ 1 y [ 5 / 0 ] 2 ] == func [][1 y [5 / 0] 2] >> z == 2
>> z: func [] [ 1 y [ 5 / 0 ] ] == func [][1 y [5 / 0]] >> z *** Math Error: attempt to divide by zero *** Where: /
error!
object is not directly accessed it doesn't "explode"z
is word!
with value of error!
:>> type? z == error! >> body-of z == [code: none type: 'math id: 'zero-divide arg1: none arg2: none arg...
z
is a funcz
integer!
>> z: func [] [ 1 y [ 5 / 0 ] ] == func [][1 y [5 / 0]] >> z *** Math Error: attempt to divide by zero *** Where: / >> z 2 == 2
>> reduce [z 2] == [make error! [ code: none type: 'math id: 'zero-divide arg1: none arg2: none arg3: none ... >> first reduce [z 2] *** Math Error: attempt to divide by zero *** Where: /
error!
context?
does not appear to work>> a: context [cat: "meow"] == make object! [ cat: "meow" ] >> b: context [dog: "bark"] == make object! [ dog: "bark" ] >> context? dog *** Script Error: dog has no value *** Where: context? >> context? b/dog *** Script Error: context? does not allow string! for its word argument *** Where: context? >> context? 'dog == make object! [ datatype!: datatype! unset!: unset! none!: none!
>> help context? USAGE: context? word DESCRIPTION: Returns the context in which a word is bound. context? is of type: native! ARGUMENTS: word [any-word!] => Word to check.
context? 'dog
, dog
is not bound in your object, it is created as new word in system/words
.>> x: context [y: 1] == make object! [ y: 1 ] >> b: reduce [in x 'y 'y] == [y y] >> context? b/1 == make object! [ y: 1 ] >> context? b/2 == make object! [ datatype!: datatype! unset!: unset! none!: none! logic!: logic!
>> dog: "bark!" == "bark!" >> b: context [ [ dog: "wimper" [ print system/words/dog [ ] bark! == make object! [ dog: "wimper" ]
system/words
has a value of an anonymous context that contains word dog
with value "bark!"
(that value is also anonymous, btw.)>> dog: b/dog == "wimper" >> dog == "wimper"
>> b: ["asdf"] == ["asdf"] >> s: b/1 == "asdf" >> unset 's >> s *** Script Error: s has no value *** Where: catch >> b == ["asdf"]
foo: bar: func [][print "what's my name?"] a: b: c: context [dog: "wimper"] list: reduce [does [print "what's my name"] context [dog: "wimper"]]
>> b: reduce [context [w: 1] context [w: 2]] == [make object! [ w: 1 ] make object! [ w: 2 ]]
context?
return here?list: reduce [context [dog: "whim"]] context? list/1
>> o: context [dog: "haf"] == make object! [ dog: "haf" ] >> b: reduce [in o 'dog] == [dog] >> equal? o context? b/1 == true
context?
currently tells anything usefulcontext-of
reflector, which we don't have. We would have two options here - 1) context-of my-word
returning the context, where my-word
is bound 2) context-of 'my-word
(or using /any) returning block of context, where my-word
is used. Well, not sure it makes sense though .... context-of
reflector* There is no such reflector in Red nor Rebol, so we can't miss it.context?
is covering the needs already.context?
returning true
or false
would be less confusing to me?
, referring to a function, has to return a logic! value (remember functions have no strict concept of "name"). See length?
and index?
for example.>> o: context [dog: "Alík"] == make object! [ dog: "Alík" ] >> p: context [dog: "Puňta"] == make object! [ dog: "Puňta" ] >> context-of: function [word][collect [foreach value words-of system/words [all [object? get/any value find words-of get value word keep value]]]] == func [word /local value][collect [foreach value words-of system/wo... >> context-of 'dog == [p o]
context-of
. In R3, Rebol started to replace ?
function, which did not return boolean, no??
can be boolean, if we don't go the length-of
route too ...context?
would be less confusing to me if it returned boolean than this:>> x *** Script Error: x has no value *** Where: catch >> context? 'x == make object! [ datatype!: datatype! unset!: unset! none!: none!
help
implementation is not good, there are several replacements worked on right now. The return:
part from Red function is not part of the help
output, so you might have missed it for context?
:>> probe spec-of :context? [ "Returns the context in which a word is bound" word [any-word!] "Word to check" return: [object! function! none!] ]
context?
context-of
. Not sure how useful, but nice indeed :-)>> x
will retrieve the value of the word x
in its bound context. >> context? 'x
will retrieve the context which that specific x
word is bound to. Those are two different properties of words, not to be confused.>> a *** Script Error: a has no value *** Where: catch >> find words-of system/words 'a == [a c d null cause-error routines safer error? quit-return none tru...
system/words
with value unset!
. So when you ask for context of that word later with context?
, it already has a context - system/words
.context?
should be renamed to bound?
, I thought context?
would be more meaningful and accurate, maybe that is not the case.do
is called on the resulting block from load
.bound?
exists in R2, Rebol users wold be familiar with that. But still the same story, some ppl complained, that they thought it is about if the word is bound, or not. I think that *-of
reflectors was a solution Carl started but was not sure about. He opened a pandora box with the likes words-of values-of minimum-of maximum-of
-of
is reserved for naming reflectors, and that is what Carl probably agreed upon.bound?
function. So, it does not seem that Rebol2 users are familiar with it. How many times did you use it?>> help to-
getting all conversion functions, and thought the same could be true for "somehow" getting *-of reflectors. But I don't push for it. It seems you somehow don't like it ...context?
returned before I made a boob of myself - but I assumed that help would show it, and I was just... generally confused.bound?
, wonder if it was added in some later incarnations of R2? Or was it there since the beginning? I lost my Rebol archive, where I had it since the 0.6 version :-(system/words
:>> help to- Found these words: (...) >> find system/words 'to- == true
help
's failure. We should have a new one in the next days anyway.-of
suffix... what are you talking about?lisp >> help "-of" body-of => Returns the body of a value that supports reflection class-of => Returns the class ID of an object keys-of => Returns the list of words of a value that supports reflection layout => Return a face with a pane built from a VID description spec-of => Returns the spec of a value that supports reflection values-of => Returns the list of values of a value that supports reflection words-of => Returns the list of words of a value that supports reflection
context?
to context-of
. Not sure if it could be called a reflector ...context?
returncontext-of
example== func [x][[x]] >> z: f 5 == [x] >> context? z/1 == func [x][[x]] >> system/words = context? z/1 == false >> (context? 'z) = (context? z/1) == false
help
shows return value. Just a deficiency of current helpword!
s as pointers like in c and c++. To reinforce that everything is anonymous :smile: types-of
to get at the input and output types in the spec of a function. Unless there is an easy way already? help
shows you types, when they are specified.>> x: context [] == make object! [] >> object? x == true >> context? x *** Script Error: context? does not allow object! for its word argument *** Where: context? >> source context context: func [spec [block!]][make object! spec] >> source object object: func [spec [block!]][make object! spec]
make object! spec
make x spec
x
make object! spec
is the same within the different versions, but the interface, context
, object
maybe different.. doc mentions that >> ? types-of USAGE: TYPES-OF value DESCRIPTION: Returns a copy of the types of a function. TYPES-OF is a function value. ARGUMENTS: value -- (Type: any)
>> same-type?: func[a [any-function!] b [any-function!]][(types-of :a) = (types-of :b)] >> same-type? :add :subtract == true
spec-of
?types-offunction, you can write one and use it. You can even use the source of the Rebol2 implementation.
same-type?
functions and similar onestypes-offunction is written in Rebol. It is not native!.
types-of
wasn't exactly what I wanted (missing return types when I checked, and I want it specifically for any-function!
). What's the best way I can move forward? Put it in a future milestone? I'm not sure if it's big enough for a REPTypes-of
in R2 seems a bit vague. I don't recall ever using it. It can match specs if they are exactly the same, but not otherwise. I'll see if I can find my old stuff.object/context
are the same, but object?/context?
are not.types-of
in red:>> same-type? :add :subtract *** Script Error: third does not allow action! for its s argument *** Where: third
spec-of
in its place.first :append
is spec, second is body, third is..types-of
helper, we can easily write something to check for func spec compatibility between funcs.object/context
are the same, but object?/context?
are not.context?
, though I don't find bind?
nor bound?
particularly good.types-of
is part of the R2/Forward group of functions that were introduced in R2 2.7.8 (the latest version), written by BrianH, as an attempt to bring forward compatibility with R3. I don't think anyone ever used types-of
in any public script. I never had a need for it too, even in the Red compiler code, I have my own tailor-made version. The use-cases are so rare, that I don't think it would be a useful addition to the Red core functions. There are even more weirder things in R2/Forward, like the title-of
function which is supposed to return the "title" docstring from a function, it has very rare usages, it's trivial to write yourself, and the proposed implementation is flawed in R2 as it doesn't account for optional presence of function attributes...context-of
?...?
functions not returning boolean!
, but context?
is bit unfortunate thanks to object/context
vs. object?/context?
problem. IMO it would be best to remove context
function (even if I am used to it), it is a waste to have it just as duplicate of object
.context
then yes ;)ownership/owned?
, though, to find an owner reflectively.context
. If object/context
are synonyms, so should be object?/context?
. That's a bit tricky, because where does it end? Do we then alias object!
and context!
? We can easily do that to some extent, as I've shown in the past with creating a hashtag!
alias for issue!
, but should we? In this case, context-of
makes sense as it is a reflection of sorts.context!
commented out in Red sources, it may come one day. I like context
also, but not as synonym for object
context!
is in fact an _internal_ type, i.e. it has a number defined (TYPE_CONTEXT) and it has a source file %runtime/datatypes/context.reds
which contains utility functions for context handling. As far as I can tell it will not become exposed to the user (does not need to). I would say that context!
is therefore NOT synonymous to object!
and that context?
would be better called context-of
the more so because the result of this function is of type object!
or function!
.?
feels like a boolean result, at least for mered>> bools: 0 == 0 red>> non-bools: 0 == 0 red>> w: keys-of system/words == [datatype! unset! none! logic! block! paren! string! file! url! ch... red>> forall w [ [ if all [ value? w/1 #"?" = last to-string w/1 ] [ [ either find fetch-help w/1 "Returns true" [ print [w/1 ": boolean"] bools: bools + 1 ] [ print [w/1 ": not boolean" ] non-bools: non-bools + 1 ] ] [ ] even? : boolean odd? : boolean head? : boolean index? : not boolean length? : not boolean tail? : boolean equal? : boolean not-equal? : boolean strict-equal? : boolean lesser? : boolean greater? : boolean lesser-or-equal? : boolean greater-or-equal? : boolean same? : boolean type? : not boolean complement? : boolean negative? : boolean positive? : boolean NaN? : boolean value? : boolean new-line? : not boolean context? : not boolean sign? : not boolean last-lf? : not boolean error? : boolean none? : boolean series? : boolean any-string? : boolean binary? : boolean any-list? : boolean word? : boolean url? : boolean zero? : not boolean string? : boolean suffix? : not boolean object? : boolean file? : boolean dir? : not boolean exists? : not boolean empty? : boolean offset? : not boolean float? : boolean block? : boolean set-word? : boolean function? : boolean unset? : boolean op? : boolean any-function? : boolean tag? : boolean action? : boolean native? : boolean routine? : boolean refinement? : boolean datatype? : boolean map? : boolean path? : boolean ?? : not boolean bitset? : boolean char? : boolean email? : boolean get-path? : boolean get-word? : boolean hash? : boolean integer? : boolean issue? : boolean lit-path? : boolean lit-word? : boolean logic? : boolean pair? : boolean paren? : boolean percent? : boolean set-path? : boolean time? : boolean typeset? : boolean tuple? : boolean image? : boolean vector? : boolean any-block? : boolean any-object? : boolean any-path? : boolean any-word? : boolean number? : boolean immediate? : boolean scalar? : boolean =? : boolean react? : not boolean ? : not boolean == none red>> bools == 72 red>> non-bools == 15
new-line?
, exists?
,zero?
also return booleanlength
for returning the length. Perhaps keep an alias length-of
to keep consistent. The only other exception I see here now is react?
that would become react-of
which should perhaps be react-on
? -t Windows
triggering compiling without using/compiling Redlib? I use -t Windows
because I do not want to get the annoying dosbox, and I don't see a libred being generated somewhere in my red-master folder.?
suffix is used for naming functions formed from a noun or adjective, instead of a verb (we should describe that better in the docs). (Note to myself: rename react?
to reaction?
) Moreover, you'll notice some edge cases (like exists?
) or exceptions sometimes, when no better alternative was found.if find "hello" #"o" [print "found!"]
), so knowing what possible types can be returned from a given function is important, focusing specifically on logic values seems pointless to me.true
values in "boolean context"length-of
I certainly understand that I have to compare result to something, because it's not meant to be used in "boolean context" dir?
and exists?
do return logic!
(and please forget the 'boolean', it will only be confusing, logic!
is also yes/no on/off). And length?
should just become length
.same
:red>> same? true yes == true red>> same? true on == true
length
looks like a variable, in fact this name will often be used as a variablelength
as a separate function and not a method? In my opinion this is a big difference, a.length
looks like getting length of a
while it can call a method, while length a
is a clear function invocation, you can't confuse first one with a variable but it is the case in second exampleI am working in the wrong programming language!
a/length
, not very differentlength
method, how would you do it in Red?lenght-of
would solve it. Well, it is pushing the code readability a bit, but we already opened a pandora box anyway ...view [ main-panel: tab-panel 200x200 [ "tab1" [ button "Click!" [save %mywindow.png to-image main-panel/parent] ] ] ]
dir
for example?>> bfr: "" call/output "dir" bfr *** Access Error: invalid UTF-8 encoding: #{FF393631} *** Where: call
call/output "cmd dir" bfr
, it hangs the process ... probably worth ticketing ....ščř.delme
) also.call
supportrc "-t Windows %environment/console/gui-console.red"
call/output/shell "dir" bfr
extract-from: func [ blk [block!] type [any-type!] /local ret-blk [block!] ][ ret-blk: copy [] foreach elem blk [ if type = type? elem [append ret-blk elem] ] return ret-blk ]
toggle: func[ ][ a-variable: not a-variable return a-variable ] a-variable: false loop 5 [ toggle prin a-variable prin " " ] ; The output toggles print "" toggle-a-variable: func [ variable ][ variable: not variable return variable ] a-variable: false loop 5 [ toggle-a-variable a-variable prin a-variable prin " " ] ; The output is always false print ""
>> loop 5 [ [ a-variable: toggle-a-variable a-variable [ prin a-variable prin " " [ ] true false true false true
not
on a boolean valuecollect-values: func [ "Collect values in a block, by datatype or custom parse rule" block [block!] rule "Datatype, prototype value, or parse rule" /deep "Include nested blocks" /local top-rule v ][ rule: switch/default type?/word rule [ datatype! [reduce [rule]] ; Turn a plain datatype into a parse rule for that type. block! typeset! [rule] ; Blocks and typesets (e.g. any-word!) work directly as rules. ][ reduce [type? rule] ] ; Turn a prototype value into a rule for that value's type. ; If they didn't spec /deep, any-block! skips nested blocks. ; /deep does *not* look into nested path or string values. ;!! We need good examples for `parse into` and its limitations. deep: either deep [ [any-path! | any-string! | into top-rule] ; Don't parse into nested paths or strings ][any-block!] ; any-block! skips nested blocks collect [ parse block top-rule: [ any [set v rule (keep/only v) | deep | skip] ] ] ] ;e.g. [ ; blk: [1 a 2 'b 3 c: 4 :d [a 'b c: :d E 'F G: :H]] ; print mold collect-values blk any-word! ; print mold collect-values/deep blk any-word! ; print mold collect-values blk set-word! ; print mold collect-values blk [set-word! | get-word!] ; print mold collect-values/deep blk [set-word! | get-word!] ; print mold collect-values/deep blk first [a:] ; print mold collect-values/deep blk integer! ; blk: [a/b/c 'j/k/l x/y/z: [d/e/f 'g/h/i t/u/v:]] ; print mold collect-values blk path! ; print mold collect-values blk lit-path! ; print mold collect-values blk set-path! ; print mold collect-values/deep blk path! ; print mold collect-values/deep blk lit-path! ; print mold collect-values/deep blk set-path! ; blk: [[a] [b] (c) [[d] (e) ([f])]] ; print mold collect-values blk block! ; print mold collect-values/deep blk block! ; print mold collect-values blk paren! ; print mold collect-values blk first [()] ; print mold collect-values/deep blk paren! ; print mold collect-values blk any-block! ; blk: [1 2.0 "b" %file a 3x3 [4.4.4.4 #5 50%]] ; print mold collect-values blk [number! | tuple!] ; print mold collect-values/deep blk [number! | tuple!] ;]
toggle-a-variable: func [var] [system/words/a-variable: not var]
loop 5 [ prin toggle-a-variable a-variable prin " "]
>> toggle: func ['word][set word not get word] == func ['word][set word not get word] >> a: false == false >> toggle a == true >> a == true >> toggle a == false >> a == false
length?
for so long that I'm too biased to think of anything but what it currently means. If memory serves, I never had an issue or any confusion about it.length-of/index-of
, I probably wouldn't have had an issue with those either. There is no reason we can't alias them in our own code. Make a lib that does so. If people adopt it and, eventually, no code contains index?/length?
anymore, you've won.person: context [ name: "" age: 0 ] persons: copy [] repeat i 5 [ append persons make person [] persons/:i/name: rejoin ["person: " i] persons/:i/age: rejoin ["age: " (50 + i)] print persons/:i/name print persons/:i/age ] print "" print persons/3/name print persons/3/age
person: context [ name: "" age: 0 ] make-person: func [i][ make person [ name: rejoin ["person: " i] age: rejoin ["age: " (50 + i)] ] ] people: copy [] repeat i 5 [ append people make-person i print people/:i/name print people/:i/age ] print "" print people/3/name print people/3/age
person: context [ _data: none name: does [rejoin ["person: " _data]] age: does [rejoin ["age: " (50 + _data)]] ] people: copy [] repeat i 5 [ append people make person [_data: i] print people/:i/name print people/:i/age ] print "" print people/3/name print people/3/age
to-image
issue, that caused by the special way we handle tab-panel on Windows. We'll fix it once we rewrite the tab-panel widget.extract-from
function, here is one possible implementation:extract-from: func [blk [block!] type [datatype!]][ parse blk [collect any [keep type | skip]] ] extract-from [3 "a" red l "hello" 2 255.0.0 78] integer! == [3 2 78]
context
, func
, ...), you can think as them as "painters", who "paint" their body words in different colors (one for each context), and some words get "re-painted" several times (the last "painter" wins). ;-) Anyway, feel free to ask as much as needed here about that, as long as you still feel your understanding is not complete.use
, modules,...bind
internally.to-image
issue, that caused by the special way we handle tab-panel on Windows. We'll fix it once we rewrite the tab-panel widget.cannot MAKE/TO image!
on stable 0.6.2to-image
. The previous to-image
will be failed when your face is covered by other windows, and also not working when the window is minimized.to-url [http www.example.org]
result in *httpwww.example.org*, or to-url [foo bar]
give *foobar*; as well url? foo:bar
(or any word with ':' in it) give *true*?to-image
should be working now.>> url? to-url 'b == true >> a: to-url 'b == b >> ? a a is a url! of value: b
>> call "dir" == 26416 >> bfr: copy "" call/output "dir" bfr *** Access Error: invalid UTF-8 encoding: #{FF393631} *** Where: call
call
output? I know that I could use call/shell
for now, but I am trying to understand, what could cause the problem for me? E.g. @Rebolek was able to get above working, and his filesystem contains special Czech alphabet chars. Mine (at least in given directory, does not). Or could it be about the Shell configuration on my system? Thansk for any pointers ...ls
works here ...>> url: to-url rejoin ['http "://" 'domain.com] == http://domain.com >> url: to-url 'http == http >> append url "://" == http:// >> append url 'domain.com == http://domain.com
rejoin
, neither for quoting. to-url [http :// domain.com]
works as well. http//domain.com
which is not what you want! >> to-url [http domain.com] == http://domain.com
httpdomain.com
url!
, to-url
etc worked. Thanks, @Oldes, my bad. I understand that without rejoin
the words in block are not evaluated, just joined together (without initial ":"), so not much use in general case. I also understand the case for incremental composition. What I don't understand is the usefulness of url!
, defined in such way, in parsing. For example the code for extract-from
that you gave above, would find g:h
if we use extract-from compose [3 "a" red 1 "hello" 2 255.0.0 g:h] url!
. But if I want to implement eg IRI-s then g:h
is a candidate for IRI but not for URL.url? g:g:f
returns *true*, which it probably should not.form
on a block argument by default when converting to a any-string!
, we should specialize the conversion for url!
.to url!
, here's the result now:>> to-url [http] == http:// >> to-url [http domain] == http://domain >> to-url [http domain.com] == http://domain.com >> to-url [http domain.com 8080] == http://domain.com:8080 >> to-url [http domain.com 43 path] == http://domain.com:43/path >> to-url [http domain.com path] == http://domain.com/path >> to-url [http domain.com file.red] == http://domain.com/file.red >> to-url [http domain.com path file] == http://domain.com/path/file >> to-url [http domain.com path file #anchor] == http://domain.com/path/file#anchor >> to-url [http domain.com path file.red] == http://domain.com/path/file.red
ctrl+shift+m
and check out the formattingdir?is a mezzanine in Rebol and Red
>> source dir? dir?: func [ "Returns TRUE if a file or URL is a directory." [catch] target [file! url!] /local info ][ info: throw-on-error [info? target] either none? info [false] [info/type = 'directory] ]
>> source dir? dir?: make function! [[ {Returns TRUE if the file or url ends with a slash (or backslash).} target [file! url!] ][ true? find "/\" last target ]]
>> source dir? dir?: func [file [file! url!]][#"/" = last file]
>> ? system/build/config/build-basename system/build/config/build-basename is a file! of value: %gui-console-2017-4-8-27033
27033
mean? It used to correspond to a git commit, but there isn't one for 27033
!img: make image! [10x10 255.0.0] save %test-image.png draw img [ fill-pen black pen off circle 10x10 8 ] exists? %test-image.png
false
on that also on Win7, please open a ticket for it.>> a: [b c] == [b c] >> b: [d e] == [d e] >> type? (a/1) == word! >> ? (a/1) b is a block! of value: [d e]
type? (a/1)
saying it is *word* and ? (a/1)
saying it is *block*?source ?
, you will see that it uses a lit-word as argument ('word
), so this means it will consume (a/1)
without evaluating it on function's call, but will evaluate it later, probably in a deep way, that is why you get b
evaluated also. Using ?
or help
is supposed to be used on words, paths and simple values, not expressions. So, you don't need to use ?
in such case, just:>> (a/1) == b >> a/1 == b
block: ["0C0C" "CA" "0407" "DE" "0010" "IT" "000A" "ES"] print index? find/skip block "0010" 2 ; fixed size records
find/skip
works fine, it will skip values according to the skipping size, and does not alter the searched series in any way, so that the returned position is correct: "0010"
is located at position 5. In order to create a "position by records of size 2", you need to do:block: ["0C0C" "CA" "0407" "DE" "0010" "IT" "000A" "ES"] size: 2 ; record size idx: index? find/skip block "0010" size print ["Found at record index" (idx + size - 1) / size]
/skip
allows you to treat the series as if it was made of records, but this is just an abstract representation, the series is not modified in any way. If you want tangible records, you can encapsulate them in sub-blocks (but searching then becomes a bit more complex, as you would need to use Parse or roll your own function for doing a deep search).trim
is sometimes destructive?>> pi2: mold pi == "3.141592653589793" >> trim/with pi2 "." == "3141592653589793" >> pi2 == "3141592653589793"
>> p: pi
mold
creates a new string!
series, while p
is a float!, so it cannot be affected by trim
in any way (trim
does not accept numbers as first argument).>> type? pi == float! >> type? mold pi == string!
help round
:/to => Return the nearest multiple of the scale parameter. scale [number!] => Must be a non-zero value.
float!
by zero for an infinity representation?red>> first spec-of :find == {Returns the series where a value is found, or NONE}
helpr reduce
text-box!
anyway. So, lot of work ;)c
to get into red-console.>> x: 5 == 5 >> x: -x *** Script Error: -x has no value *** Where: x >> x == 5 >> x: - x *** Script Error: - does not allow set-word! for its value1 argument *** Where: -
0 - val
is better then :D--:func [val] [0 - val]
--: :negate
for the heck of it then--no-install
option).rebol -qs --no-install red.r clear
or the shorter form: rebol -qsi red.r clear
rebol --reinstall
worked. No error.rc "red clear"
work?rc "clear"
? )rc "clear"
works. rc "build libRed"
rebuilds it. Also mentioned in the docs. https://doc.red-lang.org/en/libred.htmlobject [parse: func [] bind [parse some thing] this-parse-to-the-right-one]
system/words
?this-parse-to-the-right-one
means.-r
flag.parse mold 'hi/hey/hello rule: [collect [keep to "/"] skip rule | collect [keep to end]] == ["hi" ["hey"] [] ["hello"]]
collect
calls produce nested blocks. You can try to put collect
out of the recursive rule to avoid that.-r
when you changed Red code, like custom console etc.-r
.collect
before..>> collect [1 keep [2 [3 keep a]] collect [keep 4] keep collect [5 keep 6] keep []] == [2 [3 keep a] 6]
collect
, but I've always wondered about the difference, and the strange case of collect
in parse
being a sort of.. anomaly. Conveniently useful, but conceptually dirtykeep
is defined/used?parse/collect
? Cleaner api, just as powerfulparse
.collect
s which are subtly different?copy
and set
, collect
just adds a more sophisticate way to capture. Nesting collect
calls allows you to create a captured block structure that matches the input structure (see my simple HTML parser on the blog article for introducing Parse).collect
command in Parse would not be needed, just using the collect
function would have been enough (though more verbose, as keep
would require paren expressions each time then).parse html tags: [ collect [any [ ws | "</" thru ">" break | "<" copy name to ">" skip keep (load name) opt tags | keep to "<" ]] ]
parse/collect
tags
is a recursive rule, how would parse/collect
know on which recursive rule it should generate a new nested block?collect
rule.tags
rule.. unless you do self-modification of the rule..parse-collect
in terms of parse [] [collect [keep]]
, taking advantage of the fact that most common pattern of collect
being at the beginninginsert alt-tag: copy tags/2 'collect ; how would you nest a block? tags = alt-tags ; should return true
tags
rule which can be used both to collect and not collect?/check
or /only
refinement, disabling the collection, and forcing a returned logic value to signify that the parsing succeeded.collect
rule.collect
in Parse is a rule, but no different than others. It is not a property of "rule blocks". collect
ion and returning logic! . I suppose that's unavoidable due to those reasonscollect
as top collector, then Parse will return the logic value and not the collected list:tags: [ any [ ws | "</" thru ">" break | "<" copy name to ">" skip keep (load name) opt collect tags | keep to "<" ] ] >> parse html [collect set result tags] == true >> result == [html [head [title ["Test"]] body [div [u ["Hello"] b ["World"]]]]]
collect
in the tags
rules to avoid an extra unwanted collected block level.parse
refinement would still be useful to switch off the collecting process and just check the validity of the input. If the input is really big and the collecting is taking a lot of resources, doing a pre-check only (without changing the rules) could be useful.find keys-of o key
?in o 'key
none
if they key doesn't exist.has?
func.none
look the same.none ~= false
none
is falsey.has?: function [obj [any-object!] key [word!]][to logic! in obj key] has: make op! :has? o: object [a: 1 b: 2] has? o 'a has? o 'c o has 'a o has 'c
has
func as standard.has-word?: function [obj [any-object!] word [word!]][to logic! in obj word] has-word: make op! :has-word? o: object [a: 1 b: 2] has-word? o 'a has-word? o 'c o has-word 'a o has-word 'c
contains
, which is no longer, and not hyphenated, but also potentially ambiguous, as is has
, whether you are asking for a key, value, or either one.>> has-word?: function [obj [any-object!] word [word!]][to logic! in obj word] == func [obj [any-object!] word [word!]][to logic! in obj word] >> has-word? #(a: 1) 'a *** Script Error: has-word? does not allow map! for its obj argument *** Where: has-word? >> has-word?: function [obj word ][to logic! in obj word] == func [obj word][to logic! in obj word] >> has-word? #(a: 1) 'a *** Script Error: in does not allow map! for its object argument *** Where: in
either x > y [ true ] [ false ]
:Deither
instead of pick
with logic values because I have to think a lot less when reading it.in
returns true-ish or false-ish valuex > y
, no need to wrap into additional checkin
?logic!
, just a choice I made there. It seemed more appropriate.if in o 'key [... your code]
not none?
in this case.either
)test: { <table> <data> <p>a</p> <p>b</p> <p>c</p> </data> <data> <p>d</p> <p>e</p> <p>f</p> </data> </table> <p>textafter</p>more text } c: parse test [ collect [ thru {<table>} any [ thru {<data>} any [ thru {<p>} keep to {</p>} ] to {</data>} ] to {</table>} to end ] ] foreach [i1 i2 i3] c [ print [i1 i2 i3] ]
thru {}
continues to succeed, and finds textafter
. to
and thru
are great, until they aren't. :^)skip
.To
and thru
don't see any "scope" in your rules, so you advance by one with skip
, and check for elements.>> data: load test == [ <table> <data> <p> a </p> <p> b </p> <p> c </p> </data> <data> <p> d </p> <p> e </p> <p> f < >> c: parse data [collect [thru <table> some [<data> [some [<p> keep skip </p>]] </data>]] to end] == [a b c d e f] >> foreach [i1 i2 i3] c [print [i1 i2 i3]] a b c d e f
test: { <table> <data> <p>a</p> <p>b</p> <p>c</p> </data> <data> <p>d</p> <p>e</p> <p>f</p> </data> </table> <p>textafter</p>more text } p=: [<p> keep to </p> </p>] data=: [<data> any [</data> break | p= | skip]] table=: [<table> any [</table> break | data= | skip] to end] c: parse test [collect any [table= | skip]] foreach [i1 i2 i3] c [ print [i1 i2 i3] ]
any
if they see it. Otherwise they try a sub-rule. If that also fails, they use skip
to advance one element and do it all again.parse
. :^) That rule does just what your original thru {} keep to {
}
did.foreach [a b c] parse test [collect any [{</table>} break | {<p>} keep skip {</p>} | skip]] [print [a b c]] a b c d e f
test: { <table> <data> <p>aa</p> <p>bb</p> <p>cc</p> </data> <data> <p></p> <p>eee</p> <p>f</p> </data> </table> <p>textafter</p>more text } foreach [a b c] parse test [ collect any [{</table>} break | {<p>} keep skip {</p>} | skip]] [print [a b c] ]
test: { <table> <data> <p>a</p> <p>b</p> <p>c</p> </data> <data> <p>d</p> <p>e</p> <p>f</p> </data> </table> <p>textafter</p>more text } one: parse test [ collect [ any [ thru {<table>} keep to {</table>} ] ] ] two: parse to string! one [ collect [ any [ thru {<p>} keep to {</p>} ] ] ] foreach [i1 i2 i3] two [ print [i1 i2 i3] ]
atest: to-block test table-rule: [ some [ thru <table> keep to </table> ] ] table-results: parse atest compose/only [collect (table-rule)] p-rule: [ some [ thru <p> keep to </p> ] ] p-results: parse first table-results compose/only [collect (p-rule)] foreach [i1 i2 i3] p-results [ print [i1 i2 i3] ]
collect
s into one right?copy key-text to
be a better idea?test: { <p>some text</p> <table> <data> <p>a</p> <p>b</p> <p>c</p> </data> <data> <p>d</p> <p>e</p> <p>f</p> </data> </table> <p>textafter</p>more text <table> <data> <p></p> <p>bbb</p> <p>cc</p> </data> <data> <p>dd</p> <p>e</p> <p>f</p> </data> </table> } parse test [ (keeping: off) collect set c any [ {<table>} (keeping: on) | {</table>} (keeping: off) | {<p>} if (keeping) [ahead {</p>} keep (#"-") | keep to {</p>}] | skip ] ] >> foreach [i1 i2 i3] c [print [i1 i2 i3]] a b c d e f - bbb cc dd e f
keep
from acting in sub-rules would be worth having in Parse dialect? This could also provide a way to disable collect
locally or globally from returning its result from parse
call, with minimal effort.copy
and set
be affected by that? What about the input modifying commands: insert
, remove
, change
?if
would not work.some
accept other rules, you can nest them as you wishchar: #"c" parse "abccdef" ["ab" 2 char "def"]
word:
. Is this correct way:rejoin parse "xxxabbsd" [ collect any [ s: copy c skip any [ some c f: keep (copy/part s f) | break ] ] ]
multichar?: func [string [string!] /local c res s f][ parse string [ collect set res any [ s: copy c skip any [ some c f: keep (copy/part s f) | break ] ] ] either empty? res [false][rejoin res] ]
rejoin
-ed, you can just append/part res s f
and drop collect/keep
:multichar?: func [string [string!] /local c res s f][ res: make string! 10 parse string [ any [ s: copy c skip any [ some c f: (append/part res s f) | break ] ] ] either empty? res [false][res] ]
append/part
nicely replaces append ... copy/part
by avoiding the creation of a short-lived intermediary series. ;-)extract: func [ "Extracts tabular-like data from xml" 'from "Just a dummy arg for readability" xml [string!] "Well-formed x[ht]ml string containing tabular data" spec [block!] {Block of 3 tagnames -- for table, row and cell. May be string (without '<>') or block of alternative strings eg. ["ul" | "ol"]} /format frm [block!] {Block of 6 delimiters -- for each level's start and end. Defaults are ["" ^#"^^/" "" ^#"^^/" ^#" " ""]} /local table row cell ws ts te rs re cs ce result level1 level2 rowstart ][ either 3 = length? spec [set [table row cell] spec] [cause-error 'script 'need-value ['spec]] ws: compose [any (charset reduce [space tab lf])] set [ts te rs re cs ce] either format [frm][["" #"^/" "" #"^/" #" " ""]] result: make string! 10 level1: level2: off parse xml [ any [ "</" any [ table (append result te level1: off) | row (if level1 [append result re] level2: off) | cell (if (level1 and level2) [ if not rowstart [append result cs] append result reduce [either empty? content [#"-"][content] ce] ] rowstart: off) ] | #"<" any [ table (append result ts level1: on) | row (if level1 [append result rs level2: rowstart: on]) | cell thru #">" ws if (level1 and level2) [copy content to [ws "</" cell]] ] | skip ] ] print result ]
test: { <sometag> <span>Intro</span> <table1> <tr><td></td><td>b</td><td>c</td></tr> <tr><td>d</td><td>e</td><td></td></tr> </table1> <table2> <tr> <td> aa </td> <td> bb </td> </tr> <tr><td>cc</td><td>dd</td></tr> </table2> <div> <ul> <li>ul text1</li> <li>ul text2</li> <li>ul text3</li> </ul> <p>Para</p> <ol> <li>ol text1</li> <li>ol text2</li> </ol> </div> </sometag> }
red>> extract from test ["table" "tr" "td"] - b c d e - aa bb cc dd
red>> extract/format from test ["table" "tr" "td"] ["" #"^/" " " #"^/" " | " ""] - | b | c d | e | - aa | bb cc | dd
red>> extract/format from test ["table" "tr" "td"] ["" #"^/" "^"" #"^/" ";^"" "^""] "-";"b";"c" "d";"e";"-" "aa";"bb" "cc";"dd"
red>> extract/format from test ["div" ["ul" | "ol"] "li"] [ [ "<table>^/" "</table>^/" "^-<row>^/^-^-<cell>" "^/^-</row>^/" "^/^-^-<cell>" "</cell>" [ ] <table> <row> <cell>ul text1</cell> <cell>ul text2</cell> <cell>ul text3</cell> </row> <row> <cell>ol text1</cell> <cell>ol text2</cell> </row> </table>
extract
func in Red.>> switch type? #() [block! [print "block"] map! [print "map"]] == none
>> switch (type? []) [block! [print "block"] map! [print "map"]] == none
>> switch mold type? #() ["block!" [print "block"] "map!" [print "map"]] map
switch
does not evaluate the root content of his cases
block argument, so map!
in that case is just a word, while type?
returns a datatype. Use type?/word
to return the datatype name as a word.lisp >> (type? 123) = first [integer!] == false >> (type? 123) = first reduce [integer!] == true >> (type?/word 123) = first [integer!] == true
Problem signature: Problem Event Name: APPCRASH Application Name: gui-console-2017-4-14-49641.exe Application Version: 0.9.0.0 Application Timestamp: 58f233f7 Fault Module Name: StackHash_0a33 Fault Module Version: 0.0.0.0 Fault Module Timestamp: 00000000 Exception Code: c0000005 Exception Offset: 00000000 OS Version: 6.1.7600.2.0.0.256.1 Locale ID: 1033 Additional Information 1: 0a33 Additional Information 2: 0a338c230ef4b8e5272da8f93730d1e0 Additional Information 3: c1fb Additional Information 4: c1fbaf0a32e61e4d95746487b7526760
red-15apr17-ea439df.exe
) and it compiles and runs fine. Do you have an anti-virus installed?routine
s in Red too. Soon Red will get its own FFI.C:\ProgramData\Red
and run the console again.Red [Needs: 'View] view [text "hello"]
? Compile it with: red -r -t Windows
first, then try with just
red -t Windows`. Let us know the results.bitset!
, what is stored inside? how do I use it? Couldn't find answers in repl too:>> to-bitset "1" == make bitset! #{00000000000040} >> to-bitset "a" == make bitset! #{00000000000000000000000040} >> to-bitset "b" == make bitset! #{00000000000000000000000020} >> to-integer #"b" == 98
1100010
in bit-form, doesn't look like value in bitset at allbitset!
has been extended in R3 and Red beyond the 256-bit limit of bitsets in R2.red -r -t Windows-Old
?command prompt
output, while trying to run the output exe file? red-02oct16-5ec74dc
, the command prompt
window flashes on-screen with message:Runtime Error 17: Illegal instruction
, and following this message at: xxxxxxxxx
. xxxxxxxx
is the part I can't read because window disappears too quickly.red -c test.red
and red -c test.red Windows
. With red-14apr17-3ff52f9
, both resulted in a 64 kb file. Previous one was 692 kb. Same resulting errors from all exe's in command prompt
.command prompt
output:*** Runtime Error 17: illegal instruction*** at: 1001C6F8h
with smaller exe. Bigger exe - 004185E0h
red -r -t Windows-Old
?red -r -t Windows-Old
runs just fine.Windows-old
and MSDOS-old
target names when compiling. For the GUI console, you need to download the sources (cloning the repo or downloading the source archive), and manually compile it using:red -r -t Windows-old %environment/console/gui-console.red
null
value question to solve first.null
values be converted to in the map.none
values.'null
word, as the key then needs to explicitly be tested against that "special" value (if key = null [...
), instead of a more natural: if not key [...
or either key [...
.map!
and got an access violationnone
values 'none
or 'null
or any other word or special value is equivalent, as long as it tests as true
.none!
value. And all is right with the world.>> m: make map! [foo 1 bar 2 baz #[none]] == #( foo: 1 bar: 2 )
to logic!
relies on what the language considers to be true, which is all values except false
and none
. OTOH, make logic!
will construct the logic value using a more type-oriented rule, so will follow boolean algebra for integers.to logic! 0
was a pitfall in Rebol2, and the cause of unexpected bugs:value: none to-logic any [value 2] == true to-logic any [value 0] == false
body: [print item print [item replace item {a} {b}]] item: {a} bind body 'item do body
a b b
a a b
>> body: [print item print [item replace item {a} {b}]] item: {a} bind body 'item do body a b b >> body: [print item print [item replace copy item {a} {b}]] item: {a} bind body 'item do body a a b
item
and print afterwardsbind
does nothing because body
words already binded to global context, where the item
get's it's value laterprint [item replace {a} {b}]
first reduces the block, then prints the resultreduce [item: {a} replace item {a} {b}] ; ["b" "b"]
item
should be reduced to it's current value "a"
only after that it is replaced by "b"item
word points to the string "a", while replace
changes that exact string>> v: reduce [item: {a} replace item {a} {b}] == ["b" "b"] >> replace item {b} {c} == "c" >> v == ["c" "c"]
reduce [copy item: {a} replace item {a} {b}] ; ["a" "b"]
item
are pointing to the same value here, if you change it all of them are affecteditem
as wellprint
example with what @x8x expected, you can see what I mean.>> reduce [probe item: {a} probe replace item {a} {b}] "a" "b" == ["b" "b"]
replace copy item
then you will end up with same block, but item
will hold the old valuen: 5 until [print n n: n - 1 n < 0]
>> n: 5 until [ print n n: n - 1 n = 0 ] 5 4 3 2 1 == true >> system/build/date == "27-Mar-2017/19:40:47+2:00"
>> n: 5 == 5 >> until [print n n: n - 1 n < 0] 5 4 3 2 1 0 == true >> until [print n n: n - 1 n = 0]
>> parse [a [b c]] ['a ahead block! into [some word!]] == true
ahead
check for type and if it matches, it continues with into
rule. Without this check, into
would accept string also:>> parse [a "b c"] ['a ahead block! into [some word!]] == false >> parse [a "b c"] ['a into [some word!]] *** Script Error: PARSE - matching by datatype not supported for any-string! input *** Where: parse
if
lets you do additional checks in Red, where parse rules are not enough:>> parse [1 x] [set value integer! if (value > 0) word!] == true >> parse [0 x] [set value integer! if (value > 0) word!] == false
then
is half-broken for now, it needs redesign.then
in a while.then
is not the most intuitive command, maybe a renaming will happen on that one.rate 1 now
.rate
value: view [b: base 300x300 rate 10 on-time [b/color: random 255.255.255.0]]
view [box 300x300 [print "test"]]
box
is transparent by default, and hence the event fall on the underlying face
? If I change box
to base
, it works ...[print "test"]
?on-down
box
?on-*
actions. I first used on-click
, but I think it was already repeated many times, that it is for a button and maybe a subject for a change. But on-down
seems to be a default actor, if you don't state one?event
argument?base
, which is a base for some styles, it works. For box
, which seems to be based upon the base
and uses a transparency, it does not work. For what you say - a function with an event, I am not sure what you meant.a: func [fun /local var][ var: 123 fun var ] fun: func[var][print var] a :fun
123
, copiled will do nothing. Any smart way do get that working in compiled code beside putting everything in a do []
?do [fun var]
That's the only way currently to get it compile properly.00110101 11001110
how do I parse them into numbers?2#{}
syntax, but it's still not programmable>> foreach b split "00110101 11001110" space [print to integer! debase/base b 2] 53 206 >>
debase
, thanks!enbase
is its counterpart.#macro generateApi: function[][ code: [ make hash![ foo function[][print "foo"] bar function[][print "bar"] ] ] return code ] api: generateApi api/foo api/bar
Red [] #macro generateApi: function[][ [ context [ foo: function[][print "foo"] bar: function[][print "bar"] ] ] ] api: generateApi api/foo api/bar
expand
to play with macros in the console, which is really nice.reduce
?compose
:D>> h: make hash! compose [foo (func [] [print "foo"]) bar (func [] [print "bar"])] == make hash! [foo func [][print "foo"] bar func [][print "bar"]] >> h/foo foo >> h/bar bar
hash!
is being used here.do expand [ #macro generate-api: function [][ code: [ make hash! reduce [ 'foo function [][print "foo"] 'bar function [][print "bar"] ] ] return code ] api: generate-api api/foo api/bar ]
compose
and reduce
is that reduce only works for 1 block but compose can be done do get all nested blocks as well?? compose
. Compose gives you more control via refinements.compose/deep
would do nested blocks>> a: 1 == 1 >> [a] == [a] >> compose [(a)] == [1] >> compose [[(a)]] == [[(a)]] >> compose/deep [[(a)]] == [[1]] >> compose/deep/only [[(a)]] == [[1]] >> compose/deep/only [([(a)])] == [[(a)]] >> compose/deep [([(a)])] == [(a)]
#macro
unless you want it to happen only at compile time. You can replace with do
and reduce
(or something simpler) reduce
evaluates everything inside the block while compose
only things in parensC
?compose
:smile: one piece of the puzzle!>> a: compose/deep [([([(a: 10)])])] == [([(a: 10)])] >> a: compose/deep compose/deep [([([(a: 10)])])] == [(a: 10)] >> a: reduce compose/deep compose/deep [([([(a: 10)])])] == [10]
set-word!
reduce
stepa: [a: [a: [a: [a: a] ] ] ]
would never fly in an OOP language. >> a: [a: [a: [a: [a: a] ] ] ] == [a: [a: [a: [a: a]]]] >> get a/a/a/a/a == [a: [a: [a: [a: a]]]]
/
were for refinements are the inner blocks accessed in the same way?compose
evaluating the code inside parens, which is a block and block is not evaluated by defaultcompose/deep
is not enough for your example/
path syntax is used for refinements, among others. Quite a lot of stuff is multipurpose like that. For practicality and convenience parens!
is what the current compose is stopping atcompose
ultra-compose
function that will go thru every paren!
just to get some value ;)>> ultra-compose: function [value] [ rule: [ mark: change set val paren! (compose val) :mark rule | ahead block! into rule | skip ] parse value [some rule] value ] == func [value /local rule mark][... >> ultra-compose [([([(a: 10)])])] == [10]
find
?=
while searching?do expand [ #macro make-api: function [body][ reduce [context body] ] #macro make-api-macro: function [body][ make-api body ] api-1: make-api-macro [foo: function [][print "foo"]] api-2: make-api-macro [bar: function [][print "bar"]] api-1/foo api-2/bar ]
find/key block time! :type?
key
should be a refinement for a function to apply to element before comparationfind-if: func [ "Returns a series at the first value that matches a test." series [series!] test [any-function!] "Test (predicate) to perform on each value" /skip "Treat the series as fixed size records" size [integer! none!] ][ either empty? series [none][ forall series [ if test first series [return series] ] ] ] find-if [2 4 6 7] :odd?
find
if you want to support reverse
and other thingslogic!
functions>> vals == [1x5 2x6 3x7] >> key: func [data value fc] [foreach val data [do [:fc value val]]] == func [data value fc][foreach val data [do [:fc value val]]] >> key vals 7 :second == 3x7
#macro generateGraphApi: function[][ [ context [ foo: function[][print "foo"] bar: function[][print "bar"] mac: #macro mac: function[] [ print "mac" ] ] ] ]
find
should be a nice dialect too :Dsearch
. :^)>> value: [absolutely "anything"] == [absolutely "anything"] >> block: [value = get first block] == [value = get first block] >> reduce block == [true] >> remove skip block 2 == [first block] >> reduce block == [false]
do expand [ #macro generateGraphApi: function[][ [ context [ foo: function [][print "foo"] bar: function [][print "bar"] #macro mac: function [][function[] [probe "mac"]] ] ] ] generateGraphApi mac ]
call. I have done something like this in Ruby using the Unix Pseudo Terminal. (pty module in the Ruby Standard Library).
call/console
(from CLI console only if you're on Windows)? If the REPL is relying on standard I/O, it should work (like the Red CLI console), if it has its own handlers, it won't (like the Red GUI console).>> insert skip block 2 'reduce == [first block] >> reduce block == [true]
charset [#"A" - #"Z" #"0" - #"9"]
to string "ABC .. Z0123 .. 9"
?bitset!
and get specific chars by index?none
?>> b: make bitset! [] == make bitset! #{00} >> b/10 == false
>> c: charset [#"a" - #"z"] == make bitset! #{0000000000000000000000007FFFFFE0} >> forall c [ prin c/1 ] *** Script Error: forall does not allow bitset! for its 'word argument
bitset!
is not a series. For the false
, bitsets are virtually infinite, so every non-defined bit will return false
(or true
in a complemented bitset). See: http://www.rebol.com/r3/docs/datatypes/bitset.html#section-28.jpeg
pictures or .mp3
tracks.0.7.0
I/O support?>> ls boot/ bin/ initrd.img.old lib64/ nix/ vmlinuz srv/ opt/ mnt/ var/ etc/ root/ sys/ media/ cdrom/ sbin/ dev/ run/ lost+found/ initrd.img proc/ lib/ home/ usr/ vmlinuz.old tmp/
read
! :sparkles: lisp build-charset: function [bs [bitset!]][ out: make string! len: length? bs repeat i len [ if find bs i: i - 1 [append out to char! i] ] out ] >> build-charset charset [#"A" - #"Z" #"0" - #"9"] == "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
[#"A" - #"Z" #"0" - #"9"]
block instead and make bitset inside a functionbuild-charset [#"A" - #"Z" #"0" - #"9"]
list-by-suffix: function [dir [file!] s [file!]][ remove-each file list: read dir [s <> suffix? file] list ] list-by-suffix %/c/music/only-legally-acquired-songs/ %.mp3
form bitset!
to print nicer? :p other-repl: run-other-repl out: send other-repl some-stuff probe out -> output from other repl
null
value to deal with.length
in remove
work? It seems to only remove one value whatever number I write!?>> x: [1 2 3 4 5] == [1 2 3 4 5] >> remove x /part 4 == 4 >> x == [2 3 4 5]
remove/part
!set 'foobar abra/cadabra 1337 to string! 'blah-blah-blah set 'foobar abra/cadabra 1337 to string! 'blah-blah-blah
compose
block, that would not be an option.x: does [ y: 1 + 1 print "2"]
call y
will be recalculated? >> fn-a: func [][fn-b: does [] fn-c: does []] >> ctx: context [fn-b: does [] fn-c: does [] set 'fn-aa func [][]] >> time-it/count [fn-a] 100000 == 0:00:00.155000001 >> time-it/count [fn-aa] 100000 == 0:00:00.004000001
func
word is bound to global context, there is no reason for it to behave differently, regardless of the call site.>> dt [loop 1000000 [fn-a]] == 0:00:01.209189 >> dt [loop 1000000 [fn-aa]] == 0:00:00.045218
>> x: does [y: [does [1 + 1]] print reduce y] == func [][y: [does [1 + 1]] print reduce y] >> x 2
use
. It was hard for me to read, like JS in some ways, where it's not clear until end what's going on. Like a movie with a twist that makes you have to watch the beginning again.x: does [ y: 1 + 1 print "2"]
call y
will be recalculated? >> x: does [ y: 1 + 1 print y] == func [][y: 1 + 1 print y] >> poke body-of :x 4 41 == 41 >> x 42 >> :x == func [][y: 1 + 41 print y]
strict
mode). ;-)context [ fn-b: does [1] fn-c: does [x] set 'fn-aaaa has [x][ x: 3 fn-c ] bind body-of :fn-c :fn-aaaa ]
block!
to passing a func!
here is a short example:block!
:f: func [block /do /local a b][ a: 1 b: 2 bind block 'a system/words/do block exit ] f [z: 3 print [a + z type? :do]] unset? :z 4 logic ; false
f
wordsf
user that available values are a
and b
do
, have to use system/words/do
z
)func!
:f: func [fun /do /local a b][ a: 1 b: 2 (fun a b) exit ] f func[c /local z][z: 3 print [c + z type? :do]] unset? :z 4 native ; true
c
for a
in this case)do
, no need to know internals of f
>> zero? 1.1 == false >> zero? 1.0 == true >> zero? 1.0 == true >> zero? 2.0 == true >> zero? 3.0 == true >> zero? 12.0 == true >> zero? 123.0 == true >> zero? 1234.0 == true >> zero? 12345.0 == true >> zero? 123456.0 == true >> zero? 1234567.0 == true >> zero? 12345678.0 == false
a
and b
words, not the whole blockf: func [block /do /local o][ o: object [a: none b: none] o/a: 1 o/b: 2 bind block o system/words/do block exit ] f [z: 3 print [a + z type? :do]] unset? :z 4 native ; false
z
is not leaking, it's taken from the same blockz
gets set in the global contextf
is leaking :Dforeach
doesf: func [words block /do /local o] [ o: object collect [ forall words [ keep to-set-word words/1 keep none ] ] o/(words/1): 1 o/(words/2): 2 bind block o system/words/do block exit ]
0:00:17.878778
and a little complicate for the taskf: func [words block /do /local a b] [ a: 1 b: 2 bind block object reduce [to-set-word words/1 a to-set-word words/2 b] system/words/do block exit ]
0:00:05.743286
test.xlsm
in Excel 2010 and 2013 on Windows.>> system/state/trace?: yes == true >> foo: does [1 / 0] == func [][1 / 0] >> foo *** Math Error: attempt to divide by zero *** Where: / *** Stack: launch launch either run while eval-command if either switch either do-command unless case print = type? try either = set catch foo /
#include %environment/console/input.red
%.ico
files in Windows executables (with Icon: %.ico
inside Red header). I'm not sure that it's Red related and want to ask someone to check it on their machine.red>> f: func [a b] [ [ ; newline [ a + b [ print "test" [ 0 ] == func [a b][a + b print "test" 0 ] red>> body-of :f == [a + b print "test" 0 ]
new-line/new-line?
funcs.red>> length? split mold body-of :math "^/" == 14
new-line
is very handy when analyzing data sometimes, and when generating code or data.new-line? tail b
50 shades of blocks
or something; REBOL molds multi-line strings differently, so you can't guarantee ; when they'll use ^/ and fit on a single line, or not. single-line-mold: func [ "Reformats a block/object to a single line." val [any-block!] ] [ replace/all mold new-line/all copy val off "^/" "^^/" ]
%runtime/allocator.reds
.[ 3 4 [ ] == [1 2 3 4 ] >> form b == "1 2 3 4"
block!
s>> mold [1 2 3] == "[1 2 3]" >> mold [ [ 1 [ 2 3 [ 4 5 6 7 8 [ ] == {[^/ 1 ^/ 2 3 ^/ 4 5 6 7 8^/]} >>
>> parse "a" ["b" | (do make error! "parse problem")] *** User Error: "parse problem"
system/catalog/errors/:type/:id
preprocessor/func-arity?
.lisp >> preprocessor/func-arity? spec-of :append == 2 >> preprocessor/func-arity?/with spec-of :append 'append/part == 3
arity?
global function which would accept both word/path would be nice to have.-of
suffix is the convention we use for wrapper functions on reflect
action, so I would use the more common ?
suffix.-of
. :^)-of
, but if you do, it should be for reflector like functions."format
. ;^)arity?: function [ "Returns the fixed-part arity of a function spec" spec [any-function! block!] /with refs [refinement! block! path!] "Count one or more refinements, and add their arity" ][ if any-function? :spec [spec: spec-of :spec] ; Extract func specs to block t-w: make typeset! [word! get-word! lit-word!] ; Typeset for words to count t-x: make typeset! [refinement! set-word!] ; Typeset for breakpoint, set-word is for return: n: 0 ; Arity counter ; Match our word typeset until we hit a breakpoint that indicates ; the end of the fixed arity part of the spec. 'Skip ignores the ; datatype and doc string parts of the spec. parse spec rule: [any [t-w (n: n + 1) | t-x break | skip]] ; Do the same thing for each refinement they want to count the ; args for. First match thru the refinement, then start counting. if with [ either path? refs [ refs: remove to block! refs ; Convert, then remove the first segment forall refs [refs/1: to refinement! refs/1] ; So it works with t-x typeset rule ][refs: to block! refs] ; Convert/copy if not empty? missing: exclude refs spec [ ; See if refs are a subset of spec return make error! append copy "Unknown refinement(s): " mold missing ] foreach ref unique refs [parse spec [thru ref rule]] ; Count refinement args ] n ]
block!
of refs also coerce values to refinement?new-line! [code: if (new-line? code)] parse some-code [to new-line!]
new-line?
function.>> b: [1 2] == [1 2] >> parse b [integer! p: if (new-line? p) to end] == false >> new-line next b true == [ 2 ] >> parse b [integer! p: if (new-line? p) to end] == true
group-by-newline: function [blk [block!]] [ find-new-line: [ code: if (new-line? code) (new-line code false) | end | skip find-new-line ] if new-line? blk [new-line blk false] parse blk [collect [some [keep find-new-line]]] ]
view [field button 100x50 "hello" on-click [reduce face/data ] ]
reduce
isn't quite what I want here for this#do [...]
and it will be accessible by any macro function.face
refers to the button, not the field.view [field button 100x50 "hello" on-click [do face/parent/pane/1/data ] ]
#do [ #include %utilities.red ] #macro ->: func [obj code] [ group-by-newline code ]
#include
could be added in #do
body. Though, why don't you move the #do
inside the included file?system/lexer/pre-load
>> x: [1 2 3 4 5] == [1 2 3 4 5] >> put x 6 9 == 9 >> x == [1 2 3 4 5 6 9]
put
is not accurate enough, it should say: "Replaces, or adds...". Moreover put
does not rely on indexes, but key-matching, poke
is the one relying on an index.>> options: construct load %options.red == make object! [ token: #blahblah ]
construct
. Or maybe just construct
and saving body-of
will work well in Red. new-line/all body-of xxx on
/skip
>> options: [token: #blahblah a: 3 b: 'd c: 3] == [token: #blahblah a: 3 b: 'd c: 3] >> new-line/skip options on 2 == [ token: #blahblah a: 3 b: 'd c: 3 ]
construct
is for bulding objects from blocks, right?somehow-make-object [a b c] [1 2] --> make object! [a: 1 b: 2 c: none]
?*** Script Error: put does not allow string! for its series argument
!?construct
, specifically blocks in spec block format.make-spec: func [words [block!]] [ forall words [words/1: to set-word! words/1] append words none ] set o: context make-spec [a b c] [1 2]
all
there? you don't check the result anywayall
short-circuits execution, so it looks like a type-safety check there. If left/extra is not the correct type, it won't do the addition of the offset
and extra
fields. At least that's my take on it...collect
only on specific match?>> parse [a] [collect [keep 'a]] == [a] >> parse [a] ['a collect [keep 'a]] == [] >> parse [a] [collect ['a keep 'a]] == []
select
is allowed on strings, it would be consistent to allow put
too (I think there's a ticket about that).all [pair? o: left/extra left/offset: left/offset + o / 2]
is equivalent to:if pair? o: left/extra [left/offset: left/offset + o / 2]
if all [expr1 expr2][expr3]
=> all [expr1 expr2 expr3]
if
construct instead.parse
to return [a]
if the first element is a
and empty thing otherwise, using collect/keep
>> parse [a] [collect [keep 'a]] == [a] >> parse [b] [collect [keep 'a]] == []
Domain Specific Languages
is big, and like a Design Patterns book for DSLs. Technical info too, targeted at a broad audience. DSLs in Boo
is smaller and more relaxed, with some nice sections to explain things to those not familiar with the concept, all in the context of the author's Boo language, which is .NET based. Language Implementation Patterns
and an ANTLR reference are good choices. Terrence Parr is deeply technical, so more suited to building more capable DSLs, but also good to think about what tools we'll want to build. The Brodie books on Forth are good, for thinking about building vocabularies. There are a lot of other compiler books as well, some of which aren't too deep. A different book that I really enjoyed is Masterminds of Programming
which is interviews with language designers. keep
will actually match next pattern and keep it only if it was successful?>> shell [ls %/ | grep "i"] == [%initrd.img %sbin/ %lib64/ %vmlinuz %bin/ %media/ %lib/]
shell
dialect was in my head for a long time, it seems now I understand Red enough to implement it :)>> apply: func [f arg] [f arg] == func [f arg][f arg] >> apply :first [1 2 3] == 1
>> my-func: func [] [print "hello"] == func [][print "hello"] >> invoke: func [f] [do f] == func [f][do f] >> invoke :my-func hello
reducewill also cause the function to be evaluated:
>> invoke: func [f] [reduce f] == func [f][reduce f] >> invoke :my-func hello
>> to-block "a-ok" == [a-ok] >> to-block "4-ok" *** Syntax Error: invalid integer! at "4-ok" *** Where: do >> to-block "ok-a" == [ok-a] >> to-block "ok-4" == [ok-4]
>> [4-ok] *** Syntax Error: invalid integer! at "4-ok]" *** Where: do
to-block!
does.to
will behave with different types.To block!
info would be good to add to red-by-example.Red[] my-func: func [] [print "hello"] invoke: func [f] [reduce [] f] print type? invoke :my-func
function
reduce [] fevaluates f in the macro and
reduce fgives a compile error.
Red[] #do [ invoke: func[f] [f] ] #macro test: function [] [ f1: func[] [print "hello"] invoke :f1 [] ] test print "success"
call
? call
runs external program, while I want to make a shell
functions in Red and have a dialect which works flawlessly with files & stuffcall
with shell commands?shell
only works on windows last I checkedcall/shell
I meanon-menu
without using actors?system/state/trace?: on self: func [/parent /local error stack][ set/any 'error try [make-an-error] stack: split form error #" " pick stack (length? stack) - either parent [6][5] ] fun1: func[][fun2] fun2: func[][print ["I am" self "and I have been called by" self/parent]] fun1
I am fun2 and I have been called by fun1
stack: func [/local error block][ set/any 'error try [make-an-error] system/state/trace?: on block: load form error system/state/trace?: off remove/part block 12 ] fun1: func[][fun2] fun2: func[][print ["parent:" first back find stack 'fun2]] fun1
parent: fun1
trace
was more visible in rebolpath data/y/x: is not valid for none! type
message. Am I just missing something obvious here?Red [] grid: object [ data: [ ["A" "B" "C"] ["a" "b" "c"] ] item: func [ x [integer!] y [integer!] value [string!] ][ data/y/x: value ] ] datagrid: grid print "Set by path:" datagrid/data/2/1: "TwoOne" probe datagrid/data Print "Set by func:" datagrid/item 1 2 "OneTwo" probe datagrid/data
[data/:y/:x: value ]
.== [1 2 x 11 y 12] >> x: 1 y: 2 == 2 >> reduce [data/x data/y] == [11 12] >> reduce [data/:x data/:y] == [1 2]
on-change
and on-deep-change
as noted in http://www.red-lang.org/2016/03/060-red-gui-system.htmlon-face-deep-change*
, but I haven't use it yet myself.on-deep-change
. Cheers. :)>> a: [1 2] == [1 2] >> b: [3 4] == [3 4] >> append/only a b == [1 2 [3 4]] >> a/3: form a/3 == "3 4" >> b == [3 4] ; how would I make this a string without a reactor of some sort>
form a/3
, you are creating a new series, so you can't affect the original block. Only way would be: b: a/3: form a/3
length?
is different :smile: dk@ubuntu:~/Downloads$ cat hello.red Red [] print "Hello World!" dk@ubuntu:~/Downloads$ ./red-01may17-a8be796 hello.red Compiling compression library... Compiling Red console... Hello World! dk@ubuntu:~/Downloads$ ./red-01may17-a8be796 -c hello.red -=== Red Compiler 0.6.2 ===- Compiling /home/dk/Downloads/hello.red ... Compiling libRedRT... ...compilation time : 614 ms Compiling to native code... ...compilation time : 18259 ms ...linking time : 249 ms ...output file size : 573212 bytes ...output file : /home/dk/Downloads/libRedRT.so ...compilation time : 43 ms Target: Linux Compiling to native code... ...compilation time : 776 ms ...linking time : 66 ms ...output file size : 38240 bytes ...output file : /home/dk/Downloads/hello dk@ubuntu:~/Downloads$ ./hello Hello World! dk@ubuntu:~/Downloads$ ./red-01may17-a8be796 -r hello.red -=== Red Compiler 0.6.2 ===- Compiling /home/dk/Downloads/hello.red ... ...compilation time : 603 ms Target: Linux Compiling to native code... ...compilation time : 18388 ms ...linking time : 182 ms ...output file size : 534304 bytes ...output file : /home/dk/Downloads/hello dk@ubuntu:~/Downloads$ ./hello Hello World!
-t
is mostly used for cross-compilation.red/red/france
si tu préfères. ;-)gtk
branch. Though, only a few widgets are available and very basic Draw support.view [field button 100x50 "interpet" on-click [do face/parent/pane/1/data ] ]
Red [needs 'view] editor: layout [ button 75x25 "Interpret" on-click [print "Running" do a/text ] a: area 400x400 ] view editor
view [text "text" button [unview]]
entered in the field will unview the second window only when the button is clicked. What are you entering in a
?Red [needs 'view] editor: layout [ button 75x25 "Interpret" on-click [print "Running" do a/text ] a: area 400x400 ] view editor
area
of the first window.a
set to? Now you run it again. What is a
set to? Same question for editor
. do
ing live coding like this, globals can be your friend or enemy.a
. What I see here is that it opens the second window the first time, but not a second time once it's closed.? area
doesn't do anythinga
is in the console.Area
is a word used in View/VID, but is not in the global context.a
is named? instead of referenced via the top level face?a
refers to its area
face. Now you open a second one and a
points to the new one. Now you close the second one and...what does a
refer to?a
refers to after you close the second window.a
in the first then it should refer to nothinga
refers to when you close the window. It's tempting to think that Red should unset things, but that's not how it works. Run your code, then close the window. In the console, type:a/text: "Test" view editor
view layout [ button 75x25 "Interpret" on-click [print "Running" do face/parent/pane/2/text ] area 400x400 ]
set make word! append "compile-" form name function args compose/deep [ code: state/code-to-compile while [current: pos/1 not tail? pos: next pos] [ if tail? next pos [ probe current probe first code code/:current: (body) ] code: code/:current ] ] 3 func *** Script Error: code is not in the specified context *** Where: set-path
args
contain?set make word! append copy "compile-" form name function args compose/deep [ code: copy state/code-to-compile current: first pos while [not tail? pos] [ if tail? next pos [ code/:current: (body) ] code: code/:current pos: next pos current: first pos ] ]
set make word! append copy "compile-" form name function args compose/deep [ code: copy state/code-to-compile current: first pos while [not tail? pos] [ if tail? next pos [ change/only at code current (body) ] code: code/:current pos: next pos current: first pos ] ]
red-062.exe
.until [not empty? ask ""]
Do
requires you to know where the file is. #include
is meant to find files in known locations, without specifying a full path to them, relative or absolute. Sometimes I prefer do
(no need to load
separately) to make my intent clear.do-file
internally. I have to run as well, but will look into it later.Do
requires you to know where the file is. #include
is meant to find files in known locations, without specifying a full path to them, relative or absolute. without-preload: function [body [block!]][ saved: :system/lexer/pre-load system/lexer/pre-load: none do body system/lexer/pre-load: :saved ] system/lexer/pre-load: func [...][ ... without-preload [... load ...] ... ]
Red
?Red
?not a Red program!
, which had me confused for a bitRed
tho, so isn't that much of a problem. More a bump when coming/converting from Rebol2Rebol Roses are red and I'm using Red. After taking RED pill there's no way back, it's all rEd rED ReD reD! [] [__] [____] ;-- only "Red" immidiately followed by a block counts as a header Red[] print 42
load
inside without-preload
the load
function will return an empty block every time.system/lexer/pre-load: func [src part][ without-preload [ load src ] ] probe load "1 + 1" ; => [] system/lexer/pre-load: func [src part][ without-preload [ ;load src ] ] probe load "1 + 1" ; => [1 + 1]
without-preload
was just meant to be an example of how to avoid the infinite recursion, it does not return the last value of the body block. You can easily modify it to do so, or just set a word to load
output to keep it. But the real issue with what you want to do is that pre-load
needs to return a string!
value, as it's just a preliminary stage (as its name implies) before load
, which expects an any-string!
and not a block!
.system/lexer/pre-load: func [src part][ without-preload [ load src ] "here is a string" ] probe load "1 + 1" ; => []
system/lexer/pre-load: func [src part][ "here is a string" ] probe load "1 + 1" ; => [1 + 1], should not "here is a string" be here?
system/lexer/pre-load: func [src part][ change src "I am here" ] probe load "1 + 1" ; => "I am here"
system/lexer/pre-load: func [src part][ append src " interesting..." ] probe load "1 + 1" ; => [1 + 1 interesting...]
system/lexer/pre-load: func [src part][ without-preload [ x: form load src ] append clear src x ] probe load "1 + 1" ; => []
Red
?Red
followed by a block is used by the lexer to find the beginning of a Red script, passing everything before it. In Rebol, you have the same feature, but Rebol being a unique name, the odds you will find it in random text followed a squared brackets are very low, so it doesn't matter if you write it with capitals or not. In case of Red, it's a common word, so risks for finding false positives are high, so capitalizing the first letter is a way to reduce such risk.system/lexer/pre-load: func [src part][ without-preload [ x: form load src ] append clear src x ] probe load "1 + 1" ; => []
Red[]
Red...any whitespaces...[...]
.>> length? {^^} == 1
>> [{a^b}] == ["ab"]
read
text string, carets do not have to be escaped:>> write %test {a^^b} >> print read %test a^b >> length? read %test == 3 >> parse read %test [#"a" #"^^" #"b"] == true
>> parse read https://duckduckgo.com/?q=%5E&t=ffsb&atb=v35-2a_&ia=web [to #"^^" mark: (print copy/part mark 40)] ^ at DuckDuckGo</title><link rel="styles
call
at the same time? This is what I'm trying:>> in-text: "test" == "test" >> out: "" == "" >> call/console "which cat" C:\Program Files (x86)\Gow\bin\cat.EXE == 0 >> call/input/output "cat" :in-text :out *** Runtime Error 1: access violation *** at: 773793D5h
/output
working by itself. I'll try it with just /input
, but I can't do it right now. I was a little uncertain with the double refinements if I could have been doing something screwy there>> tin: "test" == "test" >> tout: "" == "" >> call/input/output "cat" tin tout == 0 >> tin == "test" >> tout == "t^@e^@s^@t^@"
append
without modifying the original series!
and just returning the appended value? Like immutability and all that.call
call
to work in the console? Can you call Red that way? Can you successfully pass an arg to a called program? t/data/(t/selected)
append "red.exe -r " t/data/(t/selected)
-> this will result first in red.exe -r file.red
, then red.exe -r file.redfile.red
etc...append copy "red.exe -r " ...
or write special function for it.call/wait/shell/output append copy "red.exe -r " t/data/(t/selected) out: copy ""
/output
is useful to catch the result of the operation, /wait
and /shell
are useful to make it work. Do not ask me why, it works for me that way and I don't know why ;)append copy
?rejoin ["red.exe -r " t/data/(t/selected)]
/wait
does./wait
also./wait
or /output
, but then you would need some other mechanism to catch the end of compilation.input/output
. For now, it's old-school.on-time
handler to some face with rate
i.e. 1 (1 times per second) and run some code there. But that can wait until you have other things ready :)face!
can have only one font!
property which has only 1 color. text-box!
supports more font styles, but it is still under development.parse
or view
is only good for basic cases. Without some kind of annotation, tools will need to scan blocks, trying various rulesets against them, to heuristically determine what they *might* be. Overlapping dialects will still need hints to disambiguate.integer!
to a block!
from reds#system [ a: [4 2 4 555 5 5] ] test: routine [x [block!] return: [block!]] [ block/rs-append x as red-value! a/1 x ]>
as
does not create a red-value! struct! by itself.form
so that only every other element gets converted to a string? Something like...form skip [ "one" "two" "three" "four"] 2
>> blk: ["one" "two" "three" "four"] == ["one" "two" "three" "four"] >> collect [foreach [a b] blk [keep reduce [to word! a :b]]] == [one "two" three "four"]
var person = { firstName:"John", lastName:"Doe", age:50, eyeColor:"blue" };
person: [firstname: "John" lastname: "Doe" age: 50 eyecolor: "Blue"] print [person/firstname person/lastname person/age person/eyecolor]
var person = new Object(); person.firstName = "John"; person.lastName = "Doe"; person.age = 50; person.eyeColor = "blue";
obj: context [firstname: "" lastname: "" age: 0 eyecolor: ""] person: make obj [] ; create a new object person/firstname: "John" person/lastname: "Doe" person/age: 50 person/eyecolor: "Blue" print [person/firstname person/lastname person/age person/eyecolor]
>> person: #() == #() >> person/name: "John Doe" == "John Doe" >> person/age: 50 == 50 >> person == #( name: "John Doe" age: 50 )
red >> person: context [firstname: lastname: age: eyecolor: none] == make object! [ firstname: none lastname: none ... >> Joe: make person [firstname: "John" age: 50] == make object! [ firstname: "John" lastname: non... >> Joe/eyecolor: 'blue == blue >> ? joe firstname string! | John lastname none! | none age integer! | 50 eyecolor word! | blue
false
on opt
and any
:>> alpha2: charset "abcdef" == make bitset! #{0000000000000000000000007E} >> parse "abc" [#"a" #"b" opt alpha2 #"c"] == false >> parse "abc" [#"a" #"b" any alpha2 #"c"] == false >> parse "abc" [#"a" #"b" any alpha2] == true
>> parse "abc" [#"a" #"b" opt alpha2 mark: #"c"] == false >> mark == ""
>> alpha2: charset "abcdefg" == make bitset! #{0000000000000000000000007F} >> parse "abdc" [#"a" #"b" ahead any alpha2 #"c"] == false
ahead
, but length of jump is not known in advance. to
or thru
would do the trick, but they would not fail on non-alpha2
to
should be used, otherwise thru
would eat up digits too:>> parse "abdddddd2c" [#"a" #"b" ahead any alpha2 thru #"c"] == true >> parse "abdddddd2c" [#"a" #"b" ahead any alpha2 to #"c"] == false
to
doesn't work neither.react
to itself?react
examples?on-time
events?view [base 200x200 rate 5 on-time [face/color: random 255.255.255]]
time!
as rate? rate
and got nothingview [base 200x200 rate 0:0:0.5 on-time [face/color: random 255.255.255]]
? rate
cannot help you, because rate
is VID keyword and there is no dialect auto-documentation (yet?).0:0:0.5
is 1 time per second?0:0:1
is 1 time per second0:0:0.5
is half a second per framerate 30
is 30 times per second and rate 0:0:30
is one tick every 30 secondsfunction!
or native!
or a datatype!
it recognizes the word and gives it a color.alpha: charset [#"a" - #"z" #"A" - #"Z"] ending: "m" ; or ["m" end] >> parse "abcm" ["abc" copy _1 to ending if (parse _1 [any alpha]) ending] == true >> parse "abcxyzm" ["abc" copy _1 to ending if (parse _1 [any alpha]) ending] == true >> parse "abc123m" ["abc" copy _1 to ending if (parse _1 [any alpha]) ending] == false
/case
, /withspec
(shows generated spec with result of parsing) and /speconly
(prints generated spec only). No backreferences and changing. Wildcards are possesive as in parse
. I was stuck in nesting groups. Could use some help if anyone is interested. Some examples:>> regex "abracadabra" "^^ab(.a)+bra$" == true >> regex/withspec "Red is beautiful" "^^Red.{4}be" [#"R" #"e" #"d" 4 anychar #"b" #"e" to end] == true
ls
and now ~~poor man's parse~~ regexes!build
. To work around this problem I use a copy of this function
build2, which allowed to implement groups, but only on one level. I think I have somewhere missed some elementary thing, but I just cannot see it.
One error messge, I keep getting, is this:
I see the source of the problem, it is here:
When recursively calling
build, string
sgets changed, and
t`is out of sync. text-box!
that provides required support functions, or implement in yourself with Draw. But for standard faces, it is missing yet.text-box!
, it is the easiest way to do things like this.text-box
in the documentation https://doc.red-lang.org/en/view.htmlarea
and the other face types are implemented.modules/view/backends
.%area.reds
...view [base 100x100 red at 50x50 base 100x100 blue]
view [base 100x100 255.0.0 at 50x50 base 100x100 0.0.255.127]
append
?remove
face/pane: []
would that work?clear
to empty a series.clear face/pane
should workclear
will keep reference to the same block, will just remove everything from itface
to pair! [4 5]
(100,200)
into the console and you should see why you got the result you did.hash
?>> a: [a a a] == [a a a] >> bind a/1 context [a: 1] == a >> reduce a == [[a a a] [a a a] [a a a]]
[1 [a a a] [a a a]]
>> object #(a: 5) *** Script Error: object does not allow map! for its spec argument *** Where: object >> make object! #(a: 5) *** Syntax Error: invalid construction spec: #(a: 5) *** Where: make >> to-object #(a: 5) *** Script Error: to-object has no value *** Where: catch
find/match
Maxim.== make hash! [a 1 b 2 c 3] >> extract h 2 == make hash! [a b c]
extract
, I would newer find it by myself :) thanks>> a: [a a a] == [a a a] >> a/1: bind a/1 context [a: 1] == a >> reduce a == [1 [a a a] [a a a]]
qf
, right? ;^)#(+ %1 %2)
invalid argument
as it happens with pairs and so on>> f: qf [ reduce [ _ _ ] ] == func [_1 _2][reduce [_1 _2]] >> f 1 2 == [1 2] >> f: qf [ reduce [ _3 _2 _1 ] ] == func [_1 _2 _3][reduce [_3 _2 _1]] >> f 1 2 3 == [3 2 1]
hash
?hash!
is just a block!
with fast lookups, so it's free-form, there is no enforced structure, in hash!
every value is a key. It's up to the user how you want to use and structure a hash!
series.call
? Is it not recommended? map!
as a replacement for a missing set!
type.qf
example aboveset!
is
! Looking forward to your final version and usage examples. parse "ab" [any [any #"a"] #"b"]
[some [any #"a"] #"b"]
[some [opt #"a"] #"b"]
any
and opt
always succeed, so having a wrapping loop depending on them is a sure way to loop infinitely. ;-)stack
elements' syntax, please?stack: [none make point! [-1 0 2] [any [some #"a"] #"b"] make point! [0 -1 2] make point! [0 0 2] -1 none make point! [0 1 1] [[some #"a"] #"b"]]
point!
) is used to record 3 offsets, though those can depend on the rule type. The third value is either a block value is it's a block rule or an internal ID for other types of rules. I can't say much more without explaining in details Parse's internals, though, you should find all the related info pretty easily from Parse sources. Feel free to ask any question about it.point!
currently has no accessor defined, the only actions are make
, form
and mold
. Though, you should be able to load
the molded output, and extract the stored values that way, until the type gets completed.>> parse "cab" [thru [(_1: [(cs_1: charset [#"a" #"b"]) some cs_1]) _1] end] == false >> parse "cab" [thru [some cs_1] end] == true >> parse "cab" [thru [_1] end] == false >> parse "cab" [thru [(_1: [some cs_1]) _1] end] == false >> parse "cab" [thru [_1] end] == true
>> parse "cab" [(cs_1: charset [#"a" #"b"] _1: [some cs_1]) thru [_1] end] == true
SET_RETURN(var)
, where var
is a red-block!
variable pointing to your block value.defined-or-not: func [ 'word ][ either not error? try [o][true][false] ] print defined-or-not o o: 2 print defined-or-not o
word *** Script Error: word has no value *** Where: catch unset? :word ; true value? 'word ; false
ft: make font! [name: "Menlo" size: 12] txt-box: make text-box! [ text: "Hello aBc" font: ft size: 100x300 styles: [ 1 5 255.0.0 bold italic 7 3 0.255.0 underline 10 3 backdrop 200.200.255 font-size 28 strike ] ] view [ b: base 300x300 do [b/flags: [Direct2D] b/draw: compose [text 60x100 (txt-box)]] button "Info" [ txt-box/target: b txt-box/layout probe txt-box/offset? 3 probe txt-box/offset? 11 probe txt-box/index? 10x3 probe txt-box/line-height 5 probe txt-box/line-height 11 probe reduce [txt-box/height txt-box/width txt-box/line-count] ] ]
Help
is showing internal object
's methods... is it ok?>> help system/options/float pretty? | logic! | false full? | logic! | false on-change* | function! | [word old new] >> probe system/options/float make object! [ pretty?: false full?: false ]
help
. I let @greggirwin judge when he'll be back.help/all
help
on objects. It didn't matter what it printed. So, only would be helpful for newcomers if that is reduced.none!
values printed. Just 2 functionsred >> ? atest type | word! | window size | pair! | 80x52 ; enable? | logic! | true ; visible? | logic! | true pane | block! | length: 1 [make object! [type... ; on-change* | function! | [word old new /local srs same-... ; on-deep-change* | function! | [owner word target action new ...
none!
, logic!
and function!
would have been really helpful. But then, what about discover-ability? parent
is just as usefulred >> ? atest type | word! | window size | pair! | 80x52 pane | block! | length: 1 [make object! [type... parent | none! | none
/all
or /deep
options. IIRC, @Oldes had an option in his help
code to suppress none
values. For something like parent
, how can it know that's a special value that should be shown, and (@rebolek) how does it know what is a special "internal" value? Is it just based on the naming convention? And does that convention hold everywhere?_on-change*
and _on-deep-change*
are specially checked symbols in objects right now, so it's not a convention.|
between columns?|
, it just confuses me./all
or /deep
or anything like that. Better to let it how it is.. .or add internal setting the same way like you can customize dividers.%environment/natives.red
contains the specs in Red, and %runtime/natives.reds
contains the Red/System code, with totally different specs. The connection between the two is deeply buried in the compiler and the interpreter.source
. I will think about that more.native!
s could be rewritten on the fly, people would demand it ;)move-it: func [ ][ frame1: (mod frame1 2) + 1 im/image: imgs/(frame) ] img: load http://games.freebasic.net/BASICGaming/Issue2/HowToLesson1/SPRITES24bit.bmp imgs: copy [] frame: frame1: 1 repeat i (img/size/x * img/size/y) [ if img/(i) = 255.0.255 [img/(i): 240.240.240] ] repeat x 12 [ xy: as-pair (x - 1) * 48 + 1 0 append imgs copy/part at img xy 48x40 ] view/options compose [ base 800x600 transparent at 380x240 im: image 100x100 at 10x10 text font-size 20 {Press left, up, down or right key and hold them down} do [im/image: imgs/1] ][ actors: object [ on-key: func [ key event ] [ if event/key = 'down [ im/offset/y: im/offset/y + 4 frame: 0 + frame1 move-it ] if event/key = 'up [ im/offset/y: im/offset/y - 4 frame: 2 + frame1 move-it ] if event/key = 'left [ im/offset/x: im/offset/x - 4 frame: 4 + frame1 move-it ] if event/key = 'right [ im/offset/x: im/offset + 4 frame: 6 + frame1 move-it ] ] ] ]
view [ style s: text 100x35 font-size 20 s "line 1" return s "line 2" ]
view [ style s: text font-size 20 s 100x35 "line 1" return s 100x35 "line 2" ]
directions: [northeast east southeast south southwest west northwest north] repeat i (length? directions) [set directions/(i) i] ;probe south room: context [ name: exits: [0 0 0 0 0 0 0 0] ] rooms: copy [] loop 4 [append rooms make object! room] ; 4 rooms rooms/1/name: "kitchen" rooms/2/name: "dinerroom" rooms/3/name: "studyroom" rooms/4/name: "salon" repeat i 4 [ set to-word rooms/(i)/name i ] rooms/(kitchen)/exits/(south): salon probe rooms/(kitchen)/exits/(south)
rooms: [kitchen [make object! [exits: [...]]]]
>> rooms/:kitchen/exits/:south: salon == 4
rooms
is just an array of objects, so you cannot expect that something like: rooms/kitchen
will work as it selects by name, but in your case kitchen
is just index.rooms/:kitchen
is same like rooms/(kitchen)
or rooms/1
, because :kitchen
is of type get-word!
probe kitchen == 1 probe type? kitchen == integer! probe south == 4 probe type? south == integer!
rooms/kitchen
works because the word kitchen
is in rooms
. It's looking that part up based on name. If you use :kitchen
, or (kitchen)
then you are looking it up by index (using the value of kitchen
). The word south
is not in exits
, so it doesn't find itrooms
, what do you see? To access a value via path syntax, using a word, e.g., 'kitchen
, that word needs to be in the block/object. Do you see 'kitchen
in rooms
? Now think of another way to do it, using select
. What would you use as the key/value to select on?probe type? 'kitchen
in the console. Using a get-word!
or paren!
evaluates the word.#include %environment/console/input.red
and compile in release mode (-r
option).direction: "south" set to-word direction 4 probe south == 4
probe south
, you are passing the south
word which was not defined before, or at least, the compiler does not see where it is defined, so it will signal an error. The compiler does a static checking of your source code, while the interpreter processes the code on-the-fly. The compiler can detect some simple errors that way and generate better code. So, you can either make the compiler happy by declaring a south
word before (like south: none
), or disable such checks by the compiler by adding the following entry inside your Red [...]
header: Config: [red-strict-check?: no]
.face/state/1
. It's documented [there](https://doc.red-lang.org/en/view.html#_show_function) under "State facet" section. Easiest way for you is to pass that value to a routine, then from the routine, you can call the OS API.Red [ ] if file: request-file [contents: read file] print "prints file path and contents of text file" print "--------------------------------------------" print "" print file print "" print contents
call
command using it. I'm on windows, so using del
here:== %xxxyyyzzz.tmp >> form reduce ["del" to-local-file file] == "del xxxyyyzzz.tmp" >> exists? file == true >> call form reduce ["del" to-local-file file] == 12148 >> exists? file == false
ctrl+shift+m
shows markdown help. Use three backticks to post large amounts of code>> f1: %foo == %foo >> f2: %bar == %bar >> foreach f [f1 f2] [print f] f1 f2
reduce
it works. Is this the correct/idiomatic way to do this? (It's like (list f1 f2)
vs. '(f1 f2)
in Lisp, I guess.)>> foreach f reduce [f1 f2] [print f] foo bar
foreach f [f1 f2] [print f]
just loops over [f1 f2]
and prints f1
and f2
. f1
and f2
which you have done in the second example.>> reduce [f1 f2] == [%foo %bar]
foreach f reduce [f1 f2] [print f]
now give the right result. I think this is the correct way.reduce
whole block, or get
each value individually. For example:>> foreach f [f1 f2] [print get f] foo bar
get
.Compose
is another good word to become familiar with.Red [ ] view/flags [size 200x100 h5 "Hello"]'resize view[size 200x100 h5 "Hello"] view/flags[size 200x100 h5 "Hello"]'popup
all [equal? a1 a2 equal? a1 a3]
>> a1: 1 == 1 >> a2: 2 == 2 >> a3: 3 == 3 >> a1 = a2 == false >> false = a3 == false
logic!
value, so you can't chain them that way. You'll be able to chain such operation once we add HOF support, or you can write a custom HOF now if you prefer. ;-)all
return none
on failure, which actually doesn't matter much, none
in conditions is treated same as false
.1 = length? unique reduce [...]
, or...; ALL? is too close to ALL all-are?: func [ ; every? all-are? ;; each? is-each? each-is? are-all? all-of? "Returns true if all items in the series match a test" series [series!] test "Test to perform against each value; must take one arg if a function" ][ either any-function? :test [ foreach value series [if not test :value [return false]] true ][ if word? test [test: to lit-word! form test] either integer? test [ parse series compose [some quote (test)] ][ parse series [some test] ] ] ] e.g. [ all-are? [1 2 3] integer! all-are? [1 2 3] :integer? all-are? [x x x] word! all-are? [x x x] 'x all-are? [x x y] 'x ; Your case a1: 1 a2: 2 a3: 3 blk: reduce [a1 a2 a3] all-are? next blk blk/1 a1: 1 a2: 1 a3: 1 blk: reduce [a1 a2 a3] all-are? next blk blk/1 ]
path!
s when it comes to metaprogramming with red: [Change word to path](https://stackoverflow.com/q/44250466/5798459)red code: load https://github.com/red/code/raw/master/Showcase/last-commits.red bcode: change/only find copy code 'view 'view/flags append next bcode quote 'resize do head bcode
pane
doesn't resize thowin: layout [lst: text-list data list] win/actors: object [ on-resizing: function [face [object!] event [event!]][ lst/size: face/size - (lst/offset * 2) ] ] events: read https://api.github.com/repos/red/red/events list: parse events [collect [any [thru "message" 3 skip keep to ["\n" | {"}]]]] view/flags win [resize]
foreach
-like fashion is often simpler and faster.quote
in Lisp?lit-word!
type, which evaluates to the corresponding word!
. And for other things, there is a quote
function which returns a single argument bypassing evaluation of it>> [a] == [a] >> 'a == a >> quote 'a == 'a >> quote (a) == (a)
quote
. ;-) What is the meaning of (a)
?paren!
is another type of series, like block!
, but its contents get evaluated when you evaluate it. It's often used when you want to partially evaluate a block using the compose
functionparen!
that contains some other stuffarea font [size: 12 color: blue] 300x300
. But view [text "asdf" font [color: blue]]
doesn't work.font-color blue
.help mold
was enteredRETURNS:
is missing, is it assumed that the return type is unset! ?[any-type!]
. It's not enforced today.default!
which exlcudes unset!
. It's possible that return vals could do that as well, but @dockimbel will have to say.related
category in Rebol help is done manually. While I think it's very useful, I don't think it should be part of function's specs. There are other useful things like examples, that should be part of some extended help, but not part of specs.[any-type!]
is probably a better default (so we can keep it compatible with current behavior in Redbol).return:
is not the same typeset as un-spec'd args.RETURNS:
be mandatory for a help entry?prin
and print
return unset!
?>> set/any 'my-word print "This doesn't work" This doesn't work >> my-word *** Script Error: my-word has no value *** Where: catch >> set/any 'my-word [print "This works"] == [print "This works"] >> my-word == [print "This works"] >>
>> set 'my-word [print "You are setting your word to block!"] == [print "You are setting your word to block!"]
/any => Allow UNSET as a value rather than causing an error.
>> set/any 'x print 1 1 >> set 'x print 1 1 *** Script Error: x needs a value *** Where: set
protect
works?protect
?unset!
values. As unset!
is a first-class datatype, such cases can happen.Unset!
has meaning as a value, albeit a special non-value. Zero is also a special non-value, if you are the first people discussing its...value. We can use unset!
to reset things, which can be very useful. Taking a step back, we may find that doing symbolic work can leverage it. As Nenad noted, it exists for a reason, but we may not see all its uses and importance in our own work.nodes: #(
"node1" make object! [
location: make object! [
x: 1845.305786132813
y: 2421.185546875
z: 131.25244140625
]
connections: ["node2"]
name: "node1"
])
make
instead of the object.red nodes: [node1: [location: [x: 1 y: 2 z: 3] connections: ["node2"] name: "node1"]] nodes-map: to-map nodes
put
*object!*s instead of *block!*s like I've done. Maybe converting the objects to blocks before you put into a map would be useful?>> node: context [location: [x: 1 y: 2]] == make object! [ location: [x: 1 y: 2] ] >> node1: make node [name: "node1"] == make object! [ location: [x: 1 y: 2] name: "node1" ] >> to-block node1 == [location: [x: 1 y: 2] name: "node1"]
load
them back, you need to stick to datatypes which have a literal form (objects don't have one), until we get the construction syntax implemented (the /all
refinement for mold
and save
).Compiling to native code... *** libRedRT Error: definition not found for red/OS-image/ctx-to-cgimage
environment/console/console.red
console
. Does it include the compiler?$ ~/src/red/console -c foo.red *** Error: cannot access argument file --== Red 0.6.2 ==-- Type HELP for starting information.
%red.r
found in source file using redred
commands, but you have to proxy it thru rebol>> btest: ['BMP make object! [thing: none]] == ['BMP make object! [thing: none]] >> length? btest == 4 >> length? dtest: reduce btest == 2 >> dtest == [BMP make object! [ thing: none ]]
btest <> dtest
red >> atest: [btest: func [] []] == [btest: func [] []] >> length? atest == 4 >> length? ctest: reduce atest == 1 >> ctest == [func [][]]
#[object! [a: 1]]
versus make object! [a: 1]
? I consider the first one nicer.func [][]
>> f: func[][print "hello"] >> mold/all :f == {#[function! [][print "hello"]]}
reduce
)>> length? blk: ["foo" #[function! [][print "hello"]]] == 2 >> blk/2 hello >> type? pick blk 2 == function!
>> blk/1: next blk/1 == "oo" >> mold/all blk == {[#[string! "foo" 2] #[function! [][print "hello"]]]} >> blk == ["oo" func [][print "hello"]]
map!
in Rebol for a long time. Finally, we have a literal form! And...wait, it's *only* a literal form. We have to be careful what we wish for, and then think about how/where/when to use each option. mold/all
, it looks useful!mold/all
in Red:make
it.#[construction! syntax]
could be thought of as an alternative to make
native!
s to https://gist.github.com/rebolek/dc1bb8c17f0c97e4dbf918126fcab6f1 . It's much bigger than original version, because there are some useful string manipulation functions, like entab
, detab
, indent
or match-bracket
.file-dir: %/C/Users/name/code/ file-list: make block! 1000 filter: [any [thru ".htm" opt [1 skip]]] ; dynamically built from wildcard expr *.htm? scan-dir: func [dir list rule /local files] [ files: sort load dir foreach file files [ either find file "/" [ scan-dir dir/:file list rule ][ if parse file rule [append list dir/:file] ] ] ] scan-dir file-dir file-list filter
C:\Users\Old Man>red --cli Compiling compression library... Compiling Red console... *** Compilation Error: undefined symbol: exec/terminal/emit-string *** in file: %/C/ProgramData/Red/red-console.red *** in function: exec/ctx434~terminate *** at line: 338 *** near: [ terminal/emit-string "^[[?2004l" ]
value?
and op!
>> x: 1 == 1 >> value? x == true >> value? 'x == true >> value? y *** Script Error: y has no value *** Where: value? *** Stack: >> value? 'y == false >> value? 'y/is-it == true >> value? '/ == true >> value? '+ == true
value?
lit-word!
to value?
it is evaluated with get
, any other type is just examined directly against unset!
.path!
tests: ['y/is-it '/ '+* '+] forall tests [print reduce [type? first tests value? first tests first tests]]
get
on those doesn't return anything?TYPE_WORD
https://github.com/red/red/blob/master/runtime/natives.reds#L1824-L1839>> value? first ['a] == true >> value? first [a] == false >>
>> value? first ['a/b] == true >> value? first [a/b] == false ;<==== now it is: true
value? first [insert/tail]
and value? first [insert/whatever]
value? first [insert/tail]
: true
and false
in the second case intuitively is my first answera/b
could mean different things, so my second thought is what I would intuit depends on type?
of path! ?a/b
in *syntax* might mean *symantically* (path! , refinement! , object! , nested block! , other(?))set
from the networkvalue?
isn't using a lit-word! arg.*** Script Error: a has no value *** Where: value? *** Stack:
path!
values.value? 'this/or/that
value? 1
, but what happens if you disallow it?>> value? [this or that] == true
that
had a value with value? 'this/or/that
Your form says (to me) "Does this block have a value?"true
with one or more '/ I can see it causing confusionvalue?
to disallow certain things, I guessget
s faultunset? 'a
should be true. There's no value set.is-the-return-value-of-the-expression-unset?
>> type? unset! == datatype! >> unset? unset! == false >> unset? unset 'a == true
>> b: 2 == 2 >> unset? b == false >> value? b == true >> unset 'b >> unset? b *** Script Error: b has no value *** Where: unset? *** Stack: unset?
unset?only seems to return
truewhen the result from a function evaluation is an
unset! value.
>> unset? prin "" == true
unset?is to check the result of function evaluations. Perhaps @dockimbel could confirm this?
>> stats == 3317760 >> loop 100 [s: copy [] s: read %c.txt] == {<some stuff> >> stats == 13824000
s: clear ""
& s: none
in an attempt to ditch the content, but I still see the memory usage increase>> unset? first reduce [()] == true
unset?
and value?
aren't intended to be consistent. That is, they don't have the same purpose. Unset?
checks the exact type of value, just like integer?
or string?
.value?
answers the question "If I evaluate x
, will I get a value?". If you ask that of literal values, like integers, strings, etc. it will always be true, because they evaluate to themselves. Words are the exception, and paths are the tricky bit as I noted, where you could argue from either side and we just have to choose.clear:
>> write %c.txt "michael" >> s: copy "" == "" >> stats == 3317760 >> loop 100 [clear s s: read %c.txt] == "michael" >> stats == 3317760
readis consuming memory. (The current IO features are temporary and will be replaced in release 0.7.0).
loop 100 [s: copy [] s: read %c.txt]
, the s: copy []
is useless code. You are creating a new block, copied from a literal one, and making s
word refer to it. Then on next expression, you are making s
word refer to a string series created from reading a file.... You should drop the "variables" concept when using Red (Red has no variables, just words which can refer to values), as it will get into your way.unset?
checks if the argument value is of unset!
type. How that argument value is created is irrevelant (same as for any other function call and arguments, evaluation rules are applied to arguments before the function call).value?
returns true if the argument type is not unset!
or in case of a word, if it has a context and refers to a value.copy []
was a stupid typo, it should have been copy ""
I guess. I agree about variable.. it's an old habit. Personally word doesn't really work for me since word usually means a 32-bit int, but I guess this is the baggage of the past to let go :smile: - the main point is basically already discussed, which is some more development is needed to make Red more robust for long operations like looping (reading files in for processing).s:
is useless code if the next expression sets s
to another value. You loop should be just: loop 100 [s: read %c.txt]
. There is no "variable initialization" in Redbol languages, because there is no "variables".tab
as last character. Maybe caused by xml files? (I'm not able to reproduce with my
, but maybe that's too simplistic)Ctrl+k Ctrl+m
, then gui console) . It's nice once setup. Could probably use the code on other systemsto-string
, silly me)to-
words complete, so I don't know what other hyphen words there are that don't complete. Also words like change-dir
; attempt 1 >> stats == 3317760 >> loop 231 [s: read %c.txt] == {aaaaaaaa^/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> stats == 3317760 ; attempt 2 >> stats == 3317760 >> loop 232 [s: read %c.txt] == {aaaaaaaa^/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> stats == 5419008
%c.txt
file?probe stats/info
before and after the loop, so I can have a more detail look at the memory usage?>> probe stats/info [[[9998 2 10000] [7036 2964 10000]] [[4 1048572 1048576] [1592856 504296 2097152]] []] == [[[9998 2 10000] [7036 2964 10000]] [[4 1048572 1048576] [... >> loop 231 [s: read %c.txt] == {aaaaaaaa^/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> probe stats/info [[[9998 2 10000] [8063 1937 10000]] [[4 1048572 1048576] [1848 2095304 2097152] [2080960 16192 2097152]] []] == [[[9998 2 10000] [8063 1937 10000]] [[4 1048572 1048576] [1848 2095304 2097152] [2080960 16192 209...
>> probe stats/info [[[9998 2 10000] [7036 2964 10000]] [[4 1048572 1048576] [1592856 504296 2097152]] []] == [[[9998 2 10000] [7036 2964 10000]] [[4 1048572 1048576] [1592856 504296 2097152]] []] >> loop 232 [s: read %c.txt] == {aaaaaaaa^/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> probe stats/info [[[9998 2 10000] [7775 2225 10000]] [[4 1048572 1048576] [2984 2094168 2097152] [2087820 9332 2097152]] []] == [[[9998 2 10000] [7775 2225 10000]] [[4 1048572 1048576] [2984 2094168 2097152] [2087820 9332 2097...
3317760
before and after the loop 231
does not match with the stats/info
report, stats
should return about 5MB memory usage after the loop, according to the reserved blocks from stats/info
.loop 231
test with both stats
and probe stats/info
before and after the loop?>> stats == 3317760 >> probe stats/info [[[9998 2 10000] [7042 2958 10000]] [[4 1048572 1048576] [1592444 504708 2097152]] []] == [[[9998 2 10000] [7042 2958 10000]] [[4 1048572 1048576] [1592444 504708 2097152]] []] >> loop 231 [s: read %c.txt] == {aaaaaaaa^/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> stats == 3317760 >> probe stats/info [[[9998 2 10000] [7784 2216 10000]] [[4 1048572 1048576] [36 2097116 2097152] [2096856 296 2097152]] []] == [[[9998 2 10000] [7784 2216 10000]] [[4 1048572 1048576] [36 2097116 2097152] [2096856 296 2097152...
stats
reported value, which is inconsistent with the allocated memory chunks. No additional tests needed for now, thanks. binary!
hexadecimal value to a bit sequence? E.g. 14
=> #{0000000E}
=> #{00001110}
bitset!
red >> enbase/base to-binary make bitset! [0] 2 == "10000000" >> enbase/base to-binary make bitset! [0 - 7] 2 == "11111111" >> enbase/base to-binary make bitset! [0 2 4 6] 2 == "10101010" >> enbase/base to-binary make bitset! [8 16] 2 == "000000001000000010000000" >> enbase/base to-binary make bitset! [8 8 8] 2 ; repetitions doesn't matter == "0000000010000000"
print
or probe
command into parse
spec influences the parsing process? E.g:>> parse "abc" [to [s: "bc"] 2 skip] == true >> parse "abc" [to [s: (print s) "bc"] 2 skip] abc bc c == false
value? non-bound-word
value? bflmpsv
bflmpsvz
gets evaluated and the result of the evaluation is passed to value?
false
and then quit?catch
catch
?>> all [value? 'abc type? abc] == none >> abc: 123 == 123 >> all [value? 'abc type? abc] == integer!
>> abc: 1 == 1 >> type? abc == integer! >> unset 'abc >> type? abc *** Script Error: abc has no value *** Where: type? *** Stack:
abc
had been bound, it does prevent type checking. unset!
be appropriate?abc
isn't a word? I thought it was just an unbound wordunset!
, but they are still non-existent and lead to error.value?
should return true or false no matter what is thrown at it.type?
could return unset!
for non-existent wordstype?
returns unset!
if you pass unset value to it. You have to understand that the error happens *before* unset value is passed to type?
.>> attempt [value? sdfdfsfg] == none
value?
>> foreach word [ton of unbound words][print value? word] false false false false >> foreach word [ton of unbound words][print type? get word] *** Script Error: ton has no value *** Where: get *** Stack: >> foreach word [ton of unbound words][print type? get/any word] unset unset unset unset
value? unbound-word
and gets an error instead of false
. Scratches head. >> foreach word [ton of unbound words] [print type? get word] *** Script Error: ton has no value *** Where: get *** Stack: >> word == ton >>
>> foreach word [ton of unbound words] [print type? get/any word] unset unset unset unset >> word == words >>
foreach
unset 'word
>> x: 1 == 1 >> foreach x [1 2 3][print x] 1 2 3 >> x == 1
x
.function
constructor, the iteration words will be locally bound.>> a: [print i] == [print i] >> b: [print i * 2] == [print i * 2] >> foreach i [1 2 3] a 1 2 3 >> foreach i [1 2 3] b 2 4 6 >> foreach i [1 2 3] get pick [a b] random true 1 2 3 >> foreach i [1 2 3] get pick [a b] random true 2 4 6 >> i: 10 == 10 >> do a 10 ;-- [print i] is still bound to global context, because a copy was created by FOREACH
type btype c as string end type type objtype a as integer c as btype end type dim x as objtype x.a = 123 x.c = "hello" print x.a ' 123 ' is ; in Red print x.c ' "hello"
b: object [ c: none ] obj: object [ ; object or context a: none c: b ] obj/a: 123 obj/c: "hello" print obj/a print obj/c
type btype c as string end type type objtype a as integer v(4) as btype ' I can't translate this end type dim x as objtype ' This makes the object x.a = 123 x.v(1).c = "hello" x.v(2).c = "test" x.v(3).c = "3" x.v(4).c = "4" print x.a ' "hello" print x.v(1).c ' "hello" print x.v(2).c ' "test" print x.v(3).c ' "3" print x.v(4).c ' "4"
v
is basically a block!
:obj: object [ a: 123 v: ["hello" "test" "3" "4"] ]
>> data: read/binary http://www.google.com == #{ 3C21646F63747970652068746D6C3E3C68746D6C206974656D73636F70653D22 22206974656D747970653D22687474703A2F2F7363686... >> to string! data *** Access Error: invalid UTF-8 encoding: #{ED206C65} *** Where: to *** Stack: >> text: rejoin collect [foreach char data [keep to char! char]] == {<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="cs"><head><meta content="text/html;...
parse
where it *really* helps.¹tìstí
instead of štěstí
), that conversion function is good enough.recursive: func [ n ][ print n either n = 1 [ return 1 ][ return recursive(n - 1) ] ] recursive 200
base
faces can be made transparent right now. I'm sure a solution will come. Someone built one for R2, using just the Win APIs. It's likely not a high priority though.parse
and there are few things that I don't understand:>> parse ["a"] [not "b"] == false
parseis not advancing the input with
not ruleand
none:
>> parse ["a"] [not "b"] == false >> parse ["a"] [not "b" skip] == true >> parse ["a"] [none] == false >> parse ["a"] [none to end] == true
notand
nonedo not advance the input.
--assert parse [a] [not 'b 'a]
parse
to return true
.>> parse [b] [not 'a (print "[not 'a] succeeded") | none (print "[not 'a] failed")] [not 'a] succeeded == false >> parse [a] [not 'a (print "[not 'a] succeeded") | none (print "[not 'a] failed")] [not 'a] failed == false
none
and not
rules, they don't match the input elements. none
in that wiki is the opposite of the official description:none
*never* advances the input position. The mentioned exception does not exist, it's a wrong interpretation of what looks like a buggy case in Rebol2's Parse implementation."%~dp0red-exe.exe" %*
Red [] print "test"
Red [] print "test"
14jun17-8e742ef
and wonders what was causing it... <script language="Red"> [Red [] prin "You just ran the hidden RED script! on " print now/time] </script> ...
path-thru
seems suspicious to me. I think that *-thru
functions are not finished.fork
able processes onlycharset
"on-the-fly" inside parse
rule?_: charset "abcd" parse data [5 _]
parse data [5 (charset "abcd" or something like that)]
>> parse "abcd" reduce [4 charset "abcdefghijklmn"] == true
system/locale
>> cz: #(find: ["Vrací sérii v místě,kde je nalezena hodnota, nebo NONE"]) == #( find: [{Vrací sérii v místě,kde je nalezena hodnota, nebo NONE}] ) >> localize: function [locals fc][spec: spec-of :system/words/:fc if string? first spec [spec/1: locals/:fc/1]] == func [locals fc /local spec][spec: spec-of :system/words/:fc if string? first spec [spec/1: locals/:fc/1]] >> localize cz 'find == {Vrací sérii v místě,kde je nalezena hodnota, nebo NONE} >> ? find USAGE: FIND series value DESCRIPTION: Vrací sérii v místě,kde je nalezena hodnota, nebo NONE. FIND is an action! value. (...)
help
function.>> en: #() == #() >> foreach word words-of system/words [all [value? :word function? get word string? string: first spec-of get word extend en reduce [word reduce [string]]]] == none >> probe en #( collect: [ {Collect in a new block all the values passed to KEEP function from the body block} ] math: [ {Evaluates a block using math precedence rules, returning the last result} ] last: ["Returns the last value in a series"] source: [ "Print the source of a function" ] (...)
spec-of
will always return a modifiable spec for the func? I only wonder because I think that may have changed at some point. It's useful for things like this, but could also cause issues I think. I'm all for having the localized text in a structure, though. Help
could probably support it pretty easily, by wrapping the spec-of
calls to take an optional locale, effectively using your localize
idea on a single func at a time, on demand.Help
would also need its own localization, as you say. help
instead of patching is probably better, I agree.file-list: read %/C/some-folder/ rules: [parse file [some [thru %.htm skip]] parse file [some [thru %index to end]]] ; wild-cards for %*.html and %*index* foreach file file-list [bind rules 'file either all rules [print file][prin "nope."]]
parse
twice instead of combining the rules into a composite rule with |
. Also, why notsuffix?
? all
. If you're only trying to match %index.html, your code is fine. And you shouldn't need bind
at all in this case.file-list: [%a.x %b.htm %c.y %d.html %e.z %f.index %index.html] rules: [ parse file [thru %.htm opt %l] parse file [thru %index to end] ] foreach file file-list [ print either any rules [file]["nope."] ]
>> SELECT %*.js* FROM %/C/web/assets/*/data/ 5 files found. %/C/web/assets/img/data/images.json %/C/web/assets/styles/data/styles.js %/C/web/assets/js/data/jquery-1.10.2.min.js %/C/web/assets/js/data/odyssey.js %/C/web/assets/data/regions.json
blockrules Red will return the last value it evaluated, i.e. the result of
parse file [thru %index to end]
. I think you need to wrap the two calls to parse in all [ ... ]
file-list: [%a.x %b.htm %c.y %d.html %e.z %f.index %index.html] rules: [ parse file [thru %.htm opt %l] parse file [thru %index to end] ] foreach file file-list [ print either all rules [file]["nope."] ]
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. 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 any-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
join
function, it's trivial (or just copy/paste the Rebol2 one if you prefer).%macros.red
:Red [] #macro [@answer] func [s e] [42]
%main.red
file:Red [] #include %macros.red probe @answer
%main.red
gives me @answer
, but I want 42
!#include
expands all macro directives and deletes them (and all macro calls) before actual inclusion. Is there any way to suppress this?Red [] #macro say-answer: func [] [42] answer: say-answer
Red [] #include %macros.red probe answer
Red [] #macro [@answer] func [s e] [42] answer: @answer
Red [] #include %macros.red probe answer
Red [] iterate: func [ 'index [word!] bump [integer!] body [block!] /back /local range ][ range: collect [repeat :index bump [keep get :index]] if back [reverse range] foreach :index range [do body] ; <-- problem lies here ] iterate/back i 5 [prin i]
54321
*** Red Compiler Internal Error: Script Error : add-symbol expected name argument of type: word *** Where: comp-foreach *** Near: [add-symbol word: pc/1 add-global word ]
iterate-back: func [ 'index [word!] bump [integer!] body [block!] ][ set :index bump while [(get :index) > 0] [ do body set :index (get :index) - 1 ] ]
round
I meaned cipher round
, in terms of cryptography.p-box: [ [prin "w"] [prin "a"] [prin "t"] ] foreach round p-box [do round]
wat
as expected, but after that original round
function is lost forever:probe round 3.5
[prin "t"]
, but actually we wanted 4.0
. Moreover, if you'll try to compile this script:*** Compilation Error: missing argument *** in file: <snip> *** near: [round]
p-box: [ [prin "w"] [prin "a"] [prin "t"] ] do reduce has [round] [foreach round p-box [do round]] probe round 3.5
wat 4.0
round
was overwritten. original-round: :round
Foreach
/iterators don't bind the word, as you note. When we get a good answer from Team Red on this, we'll add it to the wiki.[aaa]
contains a single word. You would have to store that, form it, and parse that.#macro use: func [words [block!] code [block!] /local word object][ reduce ['do bind code make object! collect [foreach word words [keep to set-word! word] keep none]] ]
Area
won't do that. It's just a native multiline text style. What you want is text-box
, or Bolek's rich text approach, used in his Gritter client. It shouldn't be long before we get more info on text-box
. text-box
available here: https://github.com/qtxie/red/wiki/Text-box!-Usagetext-box
instead of custom Draw rich-text.save
/load
does not work for you?>> save %object.red make object! [a: 1 b: 2] >> o: do load %object.red == make object! [ a: 1 b: 2 ]
#define TRUTHVAL(E) ((E->type & NOT) ? (E->str->val == TRUE) ? FALSE : TRUE : (E->str->val))
if (TRUTHVAL (Rule[i]->con) == TRUE) continue;
AND-: 0 NOT-: 2 e: context [type: 0 str: [val: 0]] truthval: func [ e ][ either ((e/type and NOT-) = NOT-) [ either (e/str/val = true) [ return false ][ return true ] ][ return true ] ] ; using AND- e/type: and- e/str/val: true if ((truthval e) = true) [ print "yes1" ] ; using NOT- e/type: NOT- e/str/val: true if ((truthval e) = true) [ print "yes2" ]
save/all
and mold/all
(serialized format) are not implemented yet, so you probably would have to implement your own saver.>> thing: make object! [foo: "Bar"] == make object! [ foo: "Bar" ] >> make map! body-of thing == #( foo: "Bar" )
Red [ Title: "Mapify" Date: 11-Jul-2017 Author: "Christopher Ross-Gill" ] mapify: func [thing [object! block!] /local key value][ case [ object? thing [ make map! collect [ foreach [key value] body-of thing [ keep key keep/only either find [block! object!] type?/word :value [ mapify :value ][ :value ] ] ] ] block? thing [ collect [ foreach value thing [ keep/only either find [block! object!] type?/word :value [ mapify :value ][ :value ] ] ] ] ] ]
#macro TRUTHVAL func [E] [ either E/type and NOT [ either E/str/val = true [ false ][ true ] ][ e/str/val ] ]
NOT
, it will have been defined before the TRUTHVAL macro.>>example case case [ <condition1> [<actions1>] ... <conditionN> [<actionsN>] ] >>
NOT: 2 e: context [type: 0 str: [val: 0]] #macro TRUTHVAL func [E] [ either E/type and NOT [ either E/str/val = true [ false ][ true ] ][ e/str/val ] ] e/type: NOT e/str/val: true print TRUTHVAL NOT e/type: AND e/str/val: true print TRUTHVAL AND
not xor
gate, but probably an illusion of my simplification0 0 1 1 0 0 0 1 0 1 1 1
>>example case case [ logic! [do-blk] ... logic! [do-blk] ]
case [ true [print "hi"] ]
example
function that does it recursivelytype?
to get a datatype!
, then choosing the simplest non-empty example of that datatype from a pre-defined listPS red> .\view-test.exe Windows 10 build 15063 -- on-change event -- face : face word : font old : none new : object -- font on-change event -- word : parent old : none new : block *** Access Error: cannot open: %../bridges/android/samples/eval/res/drawable-xxhdpi/ic_launcher.png *** Where: decode *** Stack: load
REBOL/View 2.7.6.3.1 14-Mar-2008
Windows 10 build 15063
problem then.. (except @Oldes seems to have the same problem on win7)--== Red 0.6.2 ==-- Type HELP for starting information. >> do %tests/view-test.red Windows 7 build 7601 -- on-change event -- face : button word : font old : none new : object
red.r
acts as a wrapper, it can pass the command-line to the Red console binary. Such passing is only active when the wrapper is encapped and runs as an executable (it's just for end-user convenience).%quick-test\runnable
), the interpreted tests are also compiled, but wrapped in a do [...]
to force interpretation.print
in stand alone app without console.~~~started test~~~ pointer-compile ~~~finished test~~~ pointer-compile No of tests 2 No of asserts 2 Passed 2 Failed 0
print
in stand alone app without console.print
instead of silently quitting ;-)-d -r
but not with -t Windows -r
quit
in the sources to halt. Then I was able to see the problem :smile: throw-error "Windows target requires View module (
Needs: View in the header)"
compiler.r#4609, when I ran hello.exe
music: 80000005 --> play *** Runtime Error 1: access violation *** at: 004202DA
bass-test.reds
works.. probably some regression.. I will check that later.object!
with specified fields. My gut tells me that I should harness parse
power. Can anyone point me into right direction and suggest some elegant way to do this task? (I've comed up with something like copy value1 5 binary! copy value2 2 binary! ...
, haven't checked yet).issue!
values from function as error-codes? :Pskip
, not binary!
. You can create an object before you parse, then bind the parse rule to that objectlisp thing: make object! [value1: value2: none] parse binary-value bind [copy value1 5 skip copy value2 2 skip] thing probe thing
make map! parse binary-value [ collect [ keep ('value1) keep 5 skip keep ('value2) keep 2 skip to end ] ]
/usr/lib/x86_64-linux-gnu/libcurl.so.4
/.red/console-2017-4-12-1647: error while loading shared libraries: libcurl.so.4: cannot open shared object file: No such file or directory
dpkg --add-architecture i386
apt-get update
apt-get install libc6:i386 libcurl3:i386
gtk
branch).bass-test.red
file and have it working as expected, you must first revert this commit - https://github.com/red/red/commit/6f89becc879a1d3e8775196273b95fb704298adf @dockimbel don't want to risk it before incoming 0.6.3 release. Red [ ] print "great job"``` and get the following error:** Script Error: Invalid compressed data - problem: -3
`. red
binary needs to be wrapped in a shell script if you want to invoke it that way. Alternatively, you can directly use the Red console binary (it's cached in your $HOME/.red/
folder, you can copy it out and rename it to red-console
for example). The console binary should work fine with your command. The 0.6.4 release should solve that issue definitely.red/Russia
room :bear:, there's at least three of us here.reduce
also not only the color red, but an explanation that this means rojo
is better imho.parse
, VID
, Draw
, etc) and embeddability? Say, "How I created fancy GUI for my Erlang app with Red under 2 minutes"~/red red -c --no-runtime hello.red -=== Red Compiler 0.6.3 ===- Compiling /home/mvelesyuk/red/hello.red ... Target: Linux Compiling to native code... *** Red/System Compiler Internal Error: Script Error : Cannot use path on none! value *** Where: emit-epilog *** Near: [if any [ fspec/5 = 'callback all [ attribs: compiler/get-attributes fspec/4 any [find attribs 'cdecl find attribs 'stdcall] ] ] [ offset: locals-size + locals-offset emit #{8DA5} emit to-bin32 negate offset + 12 emit #{5F} emit #{5E} emit #{5B} ] emit ]
--no-runtime
only applies to Red/System programs and is not consistent with building a Linux target. So the 'bug' is that the compiler tried to compile the program..red
file extension. -t msdos
PS E:\> Red/red/test Program 'test.exe' failed to execute: %1 is not a valid Win32 application At line:1 char:13 + Red/red/test <<<< . At line:1 char:1 + <<<< Red/red/test + CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException + FullyQualifiedErrorId : NativeCommandFailed
-no-runtime
do?--no-runtime
option is intended to compile programs for "minimal" environments such as Arduino.view
, are you running it on Linux?parse "aaa" [while ["a" | (probe "Foo")]]
parse "" [while [skip]]
will still return true, and I understand the desire to avoid a nasty loop parse "" [while []]
, however I've hit a case where this behaviour is desirable and am having some issues working around it. WHILE should always be *'use with utmost caution'* in any situation anyhow : )parse "" [end fail]
no-title
flag looks identical to the one with no-border
flag. Is it Windows-specific or bug?win: layout [backdrop yellow text "test"] win/flags: [no-border] view win
win: layout [backdrop yellow text "test"] win/flags: [no-title] view win
field
maximum text length and allow user to input only specific characters, say only digits? I've already played around with on-key
(didn't work as expected) and on-change
(got stack overflow) handlers to no avail.field/data
.view [f: field hint "type something" on-detect [print "!"]]
view [ f: field 100x20 hint "type something" on-key-up [ if 5 = length? f/text [remove back tail f/text] ] ]
'stop
, even on key down doesn't do it. I'm out tomorrow, but will try to remember to look into this if nobody beats me to it.>> system/view/capturing?: yes == true >> view [f: field hint "type something" on-detect [print "!"]] ! ! !
event
object?shadow
field in font
object? ([see Red/Vew docs](https://doc.red-lang.org/en/view.html#_font_object)).lisp
in code fences? ;)Lisp
is too generic, so they probably have specific, per-Lisp dialect IDs. I guess any random string would do too.text
worksview [f: field on-enter [f/color: red wait 0.3 f/color: white]]
on-time
blink: function [f [object!] mode [logic!]][ f/color: get pick [red white] mode f/rate: either mode [0:0:0.3][none] ] view [f: field on-enter [blink f on] on-time [blink f off]]
on-time
rate for every one-shot event is error-prone approachnot
in parse
?>> parse [x] [not 'y] == false >> parse [x] [not ['y]] == false >> parse [3] [number!] == true >> parse [3] [not number!] == false >> parse [x] [not number!] == false >> parse [x] [not [number!]] == false
not
does not advance the input:>> parse ["1" 1] [not number! string! number!] == true
r1
it goes into infinitive loopany
in a sub-rule where the main rule includes any
will always send parse into an infinite loop. (The cure is usually that one of them should be some
).
the whole rule I use is:tag: [t: open-tag (print ["in-tag" t]) any [text | tag] close-tag] open-tag: ["<" some alphanum-with-specials ">"] close-tag: ["</" some alphanum-with-specials ">"] text: [any [not ">" skip]]
some
then empty tags will not be parsedahead break
tag: [t: open-tag (print ["in-tag" t]) any [ahead [not "<"] text | tag] close-tag]
any
Red [] parser: context [ state: none rules: [ any [ number! (append state 'number) | word! (append state 'word) | time! (append state 'time) ] ] run: func [input] [ state: copy [] parse input rules state ] ]
>> do %state.red *** Script Error: append does not allow none! for its series argument *** Where: append *** Stack: do-file probe
rules
value is composed when the object is createdconstruct
instead of context
, but not sure it will solve your casestate
inside rules is not the state
in context - why the fix helps and if the fix helps how come the state doesn't change >> parser: context [ [ state: none [ rules: [ [ any [ [ number! (append state 'number) | [ word! (append state 'word) | [ time! (append state 'time) [ ] [ ] [ run: func [input] [ [ state: copy [] [ parse input rules [ state [ ] [ ] == make object! [ state: none rules: [ any [ number! (append... >> p: make parser [] == make object! [ state: none rules: [ any [ number! (append... >> p/run [1 2 3] *** Script Error: append does not allow none! for its series argument *** Where: append *** Stack:
state: copy []
does set the object's state, doesn't it?>> parser: context [ [ state: none [ rules: [ [ any [ [ number! (append state 'number) | [ word! (append state 'word) | [ time! (append state 'time) [ ] [ ] [ run: func [input] [ [ state: copy [] [ parse input rules [ state [ ] [ ] == make object! [ state: none rules: [ any [ number! (append state 'number) | word! (append state 'word) | ... >> parser/run [1 2 3] == [number number number]
>> system/build == make object! [ date: 19-Jul-2017/17:41:32+02:00 config: make object! [ config-name: 'Linux OS: 'Linux OS-version: 0 ABI: none >>
--== Red 0.6.3 ==-- Type HELP for starting information. >> Red [] == [] >> >> parser: context [ [ state: [] [ rules: [ [ any [ [ number! (append state 'number) | [ word! (append state 'word) | [ time! (append state 'time) [ ] [ ] [ run: func [input] [ [ self/state: copy [] [ parse input rules [ self/state [ ] [ ] == make object! [ state: [] rules: [ any [ number! (append s... >> >> p: make parser [] == make object! [ state: [] rules: [ any [ number! (append s... >> probe p/run [1 2 3] [] == [] >> probe system/build make object! [ date: 20-Jul-2017/3:12:09+02:00 config: make object! [ config-name: 'Windows OS: 'Windows OS-version: 0 ABI: none link?: true debug?: false build-prefix: %/C/ProgramData/Red/ build-basename: %gui-console-2017-7-17-55847 build-suffix: none format: 'PE type: 'exe target: 'IA-32 cpu-version: 6.0 verbosity: 0 sub-system: 'GUI runtime?: true use-natives?: false debug-safe?: true dev-mode?: false need-main?: false PIC?: false base-address: none dynamic-linker: none syscall: 'Linux export-ABI: none stack-align-16?: false literal-pool?: false unicode?: true red-pass?: true red-only?: false red-store-bodies?: true red-strict-check?: true red-tracing?: true red-help?: true legacy: [no-touch] gui-console?: true libRed?: false libRedRT?: false libRedRT-update?: false GUI-engine: 'native modules: [View] show: none command-line: none ] ] == make object! [ date: 20-Jul-2017/3:12:09+02:00 config: make object! [ config-name: 'Windows OS: 'Windows OS-version: 0 ABI: none link?: >>
Red []
in the console?state
inside the parse rule instead of the parser
context:parser: context [ rules: [ (state: copy []) any [ number! (append state 'number) | word! (append state 'word) | time! (append state 'time) ] ] run: func [input] [ parse input rules state ] ]
Red []
:)run
was rebinded, this is why I get empty blockparser/run
directly.rules
block should be rebound to the cloned object. Please open a ticket, so I can fix it asap.%lib.red
, %file1.red
, file2.red
and %main.red
. Both %file1.red
and %file2.red
#include
%lib.red
with some pre-defined constants and functions. %main.red
in turn #include
s %file1.red
and file2.red
. %lib.red
be included twice and should I deal with this duplication at compile time with #if
or #either
? I think this called "inclusion guards" or something :)#include
does support that feature, though I'm not sure how reliable it is. It is currently primitive and needs a reimplementation, to move it out from the compiler to the preprocessor, where we could add that. Red/System's one does include once only.do
this included file twice and won't cause any overhead at run-time?/extern
refinement which @greggirwin showed here :point_up: [12 июля 2017 г., 21:37](https://gitter.im/red/red/welcome?at=59665039c101bc4e3a7a9139), does it really exists? (it neither worked for me nor makes any sense)func
#do [ unfold: func [ range [block!] /local spec [block!] index [integer!] bump [integer!] ][ to string! collect [ while [not tail? range][ spec: head remove at take/part range 3 2 forall spec [poke spec 1 to integer! to char! form first spec] set [index bump] spec until [keep to char! index (index: index + 1) > bump] ] ] ] ] #macro letters: func [][unfold [a - c]] probe letters ; == "abc" probe letters ; ?? ""
letters
body block!
is used as argument? (it works with unfold copy [a - c]
)range
in unfold
, so you need to clone it, either when passing to unfold
, or better inside unfold
.>> parse "foo" [and "f" to end] == false
op!
value, matched against the input, and failing so you get a false
as result. I remember a ticket for something similar, asking for a more stricter checking. If you can't find that ticket you can open a new one. Currently this is allowed in Red and Rebol2:>> parse reduce [:append :mold :or :xor :and][append to end] == true
#macro my-macro: #include %my-function.red
there %my-function.red
contains something like func [][1 + 1]
#macro my-macro: do %my-function.red
?do
will run at runtime anyway, so you can't make my-macro
at compile time like that*** Preprocessor Error: Syntax error *** Where: #macro my-macro: do %my-function.red func *** Throw Error: no catch for throw: halt-request *** Where: throw *** Stack: expand-directives expand
do %my-function.red
in console?#macro my-macro: func [] [do %my-func.red] probe [my-macro]
%my-func.red
isfunc [][42]
*** Script Error: PARSE - get-word refers to a different series! :s *** Where: parse *** Stack: expand-directives expand
parse
keywords (with %xml.red and %html-tools.red):>> page: xml/decode read http://www.red-lang.org/2013/11/041-introducing-parse.html >> tables: select-by-tag page 'table >> foreach table tables [print mold get-table table/table/tbody] [ ["ahead rule " {: look-ahead rule, match the rule, but do not advance input.}] ["end" {: return success if current input position is at end.}] ["none" ": always return success (catch-all rule)."] ["not rule" ": invert the result of the sub-rule."] ["opt rule" ": look-ahead ^/rule, optionally match the rule."] (...)
names: ["joe" frank" "lou" "don"] sort/compare names function [a b] [a < b]
true
to sort values. See this example:>> names: ["frank" "louise" "jo" "donnnie"] == ["frank" "louise" "jo" "donnnie"] >> sort/compare names function [a b] [(length? a) < (length? b)] == ["jo" "frank" "louise" "donnnie"]
[-1 0 1]
for [< = >]
comparisons.>> blk: [[b b] [b a] [a b] [a a]] == [[b b] [b a] [a b] [a a]] >> sort/compare copy blk func [a b] [case [a/1 < b/1 [-1] a/1 > b/1 [1] 'else [0]]] == [[a b] [a a] [b b] [b a]]
false
returned) or kept at same position (true
returned).lisp >> sort/compare names function [a b] [print [a b] a < b] frank joe lou joe don lou don joe don frank == ["don" "frank" "joe" "lou"]
do %one.red do %two.red
load
). Macros are accumulated and applied globally. You can constraint that using #local
and #reset
[directives](https://doc.red-lang.org/en/preprocessor.html).do
invokes the interpreter, so whatever you put after it, is not compiled. The compiler "equivalent" of do
is the #include
directive. The #include
directive is converted to do
when the script is run from the interpreter, so that the symmetry is preserved.find
without destroying the series if needle is not found but the series is reassigned? Eg:>> s: [a b c] == [a b c] >> s: find s 'c == [c] >> head s == [a b c] >> s: find s 'd == none >> head s *** Script Error: head does not allow none! for its series argument *** Where: head *** Stack:
>> s: [a b f d a c] == [a b f d a c] >> s1: clear [] >> while [s: find/skip s 'a 2][attempt [append s1 copy/part s 2 s: skip s 2]] >> s == none >> s1 == [a b a c] >> head s *** Script Error: head does not allow none! for its series argument *** Where: head *** Stack:
s
is a long block used over and over again to search/extract different values, then failed search is scary.>> s == [1 2 3] >> all [t: find s 3 s: t] == [3] >> s == [3] >> all [t: find s 4 s: t] == none >> s == [3]
any
.>> s: [a b c] == [a b c] >> s: find s 'c == [c] >> head s == [a b c] >> s: any [find s 'd s] == [c] >> head s == [a b c]
module!
type that needed to be implemented first?do
function which will load and evaluate a Red file (when it is supplied with a file!
value) and the [pre-processor #include
directive](https://doc.red-lang.org/en/preprocessor.html#__include).with
. As I am trying to mimick /all
refinement with find
I need to stop while
when search fails. @rebolek 's solution works well:>> s: [a b d f a c] == [a b d f a c] >> s1: clear [] while [all [t: find/skip s 'a 2 s: t]][attempt [append s1 copy/part s 2 s: skip s 2]] >> head s == [a b d f a c] >> s1 == [a b a c]
>> s1: clear [] while [s: any [find/skip s 'a 2 s]][attempt [append s1 copy/part s 2 s: skip s 2]]
while
".load
script without Red header and without preface (i.e. without any data before Red header)?parse [thru src: to end] src
, but then I can't figure out how to write
:confused: it should be Red
keyword, then optional spacers, then block!
.load %script.red
, that's how it works in Rebol, but I think that Red does not support preface text yet.>> print read %test.red blabla, Red[] print 1 + 1 >> load %test.red *** Syntax Error: invalid value at ",Red[]print 1 + 1"
>> next next load first parse read %test.red [collect [to "Red[" keep to end]] == [print 1 + 1]
load
:Red[]
, load
ing a %file
?Red[...
, ignoring encoding.>> next next load find read/binary %test.red "Red[" == [print 1 + 1]
"Red ["
is error-proneload first parse read %file.red [collect [thru "Red [" thru "]" keep to end]]
thru "]"
is the main problem.>> parse "Red [" [(ws: charset reduce [#" " cr lf tab]) "Red" any ws #"["] == true
Red Green </html> not actual Red code Red [ blah []] "actual Red code"
parse
is actually better that find
, but collect
is not needed. This would be enough IMO:>> script: {Red Green </html> not actual Red code Red [ blah []] "actual Red code"} == {Red Green </html> not actual Red code Red [ blah []] "actual Red code"} >> parse script [(ws: charset reduce [#" " cr lf tab]) some ["Red" start: any ws #"[" p: to end | skip]] == true >> code: next next load skip start -3 == ["actual Red code"]
load %image.png
file with metadata containing created with Red [embedded version]
(that's too unlikely to happen, right?)Needs: ['View 'MadeUpModule]
and got an error that "module not found: MadeUpModule" so there's at least a way to get Red to search for inclusions through Needs: ['x]
?view
is in the modules folder of red sources. It's the only one, the code for that is probably a stubload/all
is in place, will that do what you want?This is a preface! Roses are red, the pill is RED too! rEd [_] [___] [_____] Red [[[][[]][[[]]][[[[]]]]]] source-of: func [ "get source of the script without preface and header" script [file!] /local blanks [bitset!] source [string!] ][ parse/case read script [ (blanks: charset reduce [cr lf space tab] i: 0) thru ["Red" any blanks ahead "["] some [ "[" (i: i + 1) | "]" (i: i - 1) | if (i = 0) source: break | skip ] to end ] return load source ] probe source-of system/options/script
i
is leaking :sweat_smile:Red[Title: "]]]"]
? ;)series!
This is a preface! Roses are red, the pill is RED too! rEd [_] [___] [_____] Red [ "]]]" {]]]} {"{"}} {^{} ] source-of: func [ "get source of the script without preface and header" script [file!] /header "get only header instead" /local blanks [bitset!] head [block!] source [string!] i [integer!] ][ ; skip preface and Red keyword parse/case read script [ (blanks: charset reduce [cr lf space tab] head: copy [] i: 0) thru ["Red" any blanks ahead "["] s: to end ] ; now parse the source directly parse load s [set head block! source: to end] return either header [head][source] ] probe source-of system/options/script probe source-of/header system/options/script
load
FTW!!! :clap: Red
keyword followed by [
with optional blanks in between counts as a start of the header?Red/System
as well, plus optional BOM. From %lexer.r:header: [ pos: thru "Red" (rs?: no) opt ["/System" (rs?: yes stack/push 'Red/System)] any-ws block-rule (stack/push value) | (throw-error/with "Invalid Red program") end skip ] program: [ pos: opt UTF-8-BOM header any-value opt wrong-end ]
to-date: func [dt][either float? dt [1-Jan-1970 + to time! dt][to date! dt]] to-float: func [dt][either date? dt [to float! difference dt 1-Jan-1970][to float! dt]]
date: now/precise ; 4-Aug-2017/2:16:10.183843+02:00 epoch-with-subseconds: to-float date ; 1501805770.183843 to-date epoch-with-subseconds ; 4-Aug-2017/0:16:10.183843
.gitignore quick-test/quick-test.log quick-test/runnable/ system/tests/source/units/auto-tests/ tests/source/units/auto-tests/ crush.dll
lib*
to ignore files spawned by libRedRT compilationquick-test/quick-test.log quick-test/runnable/ system/tests/source/units/auto-tests/ tests/source/units/auto-tests/
quick-test.red
or quick-test.reds
.port!
datatype which will enable full I/O support is planned for Version 0.7.0. The Trello card for 0.7.0 under Milestones lists the protocol support planned to be provided in Version 0.7.0.call
facility eventually, but not 100% sure ....curl
executable on the command line.curl
but now Red supports everything I needed from it.closure: func [ vars [block!] "Values to close over, in spec block format" spec [block!] "Function spec for closure func" body [block!] "Body of closure func; vars will be available" ][ func spec compose [(bind body context vars)] ] closed-fn: closure [var: 1] [n] [var: var + n]
closure
that's modeled on. Credit to him.compose
can be omittedbind
returns block with words binded to anonymous context one way or anothertype? var
could give different results) then it's not statically typed (and its dynamic typing is missing something I don't know the name of; would otherwise have to give an error if a variable is assigned a value of a type different from its current values (and so essentially is locked to the first type it gets--of the init)).>> answer: 42 == 42 >> type? answer == integer! >> type? 'answer == word!
answer
nor the type of 42
, but you may rebound answer
word to a different value with a different type.var: 42
then var
can be setted only to integer!
values?ctx: context [ on-change*: func [var old new][ if not-equal? type? old type? new [ print "nay" self/var: old ] ] var: 42 ] probe ctx/var ctx/var: "abracadabra" probe ctx/var ctx/var: 10 probe ctx/var
on-change*
O.Octrl+shift+m
for more infofld-1/text: "Straw"
, you could set it on a button press event like in form-1
if you want to load dynamicallycontext-2/fld-1/text: "Straw"
init-form
to not work, except putting view form-2
at the endred Red [ Title: "Test title" Needs: View ] context-2: context [ ; File: %form.2red form-2: layout [ below text "Field 1" fld-1: field 200 text "Field 2" fld-2: field 200 text "Field 3" fld-3: field 200 ] init-form: [ ; can dynamically load from db here fld-1/text: "Straw" fld-2/text: "Wood" fld-3/text: "Bricks" view form-2 ] ] context-1: context [ ; File: %form1.red form-1: layout [ button "Call form-2" [do context-2/init-form] ] view form-1 ]
compose
repetitious VID
code like the field
sview/no-wait
red
libRed is put in my project workspace..r
and .dll
files from there? It's cluttering up my project's top directory>> do %red.r none == none >> redc/main/with "-o my-libRed -r libred/libRed.red" "-o my-libRed -r libred/libRed.red" -=== Red Compiler 0.6.3 ===- Compiling red/libred/libRed.red ... ...compilation time : 1665 ms Target: Darwin Compiling to native code... ...compilation time : 42735 ms ...linking time : 507 ms ...output file size : 1318912 bytes ...output file : red/my-libRed.dylib
build libRed
after a git merge. (I don't know the code well enough to be certain). --config [export-ABI: 'stdcall]
to the arguments if you are running on Windows.FOR
?for
dialect](https://github.com/red/red/wiki/REP-0101---For-loop-function).rc
to invoke the Red toolchain from a Rebol console, and pass it a string representing the command-line.to
creates a new value, copying the underlying buffers if any. as
just coerces a series type to another compatible type in the same type class, underlying buffers are shared. to
is defined for almost all types, while as
is only defined for any-string!
and any-block!
type classes.To/as
note added to https://github.com/red/red/wiki/Primer.cfor
functionality?) of the variants put forward in this proposal.for
is supposed to be used as a red runtime functionrange!
object or similar may be more useful in my opinion...reds
file (it gives me *** Compilation Error: unknown directive macro
) but they work fine in Red proper :Padata: [0 [204.255.204 "Information"] 1 [255.255.153 "Warning"] 2 [255.204.204 "Error"]] bgcolor: first select adata kind msgtype: second select adata kind
pick
behavior, not select
. You could wrap it in a helper func, or use a map!
. Map will be the cleanest there, but if you need it to be a block, a wrapper isn't bad.adata: #(0 [204.255.204 "Information"] 1 [255.255.153 "Warning"] 2 [255.204.204 "Error"]) kind: 1 bgcolor: first select adata kind msgtype: second select adata kind bgcolor: adata/:kind/1 msgtype: adata/:kind/2
adata: [[204.255.204 "Information"] [255.255.153 "Warning"] [255.204.204 "Error"]] kind: 1 bgcolor: adata/:kind/1 msgtype: adata/:kind/2
red adata: [Information 204.255.204 Warning 255.255.153 Error 255.204.204] kind: 1 msgtype: pick extract adata 2 kind ; not sure about this bgcolor: select adata msgtype
?func?
extract
works!to
creates a new value, copying the underlying buffers if any. as
just coerces a series type to another compatible type in the same type class, underlying buffers are shared. to
is defined for almost all types, while as
is only defined for any-string!
and any-block!
type classes.any-block!
includes hash!
, and as
is not defined on hash!
(do a ? as
in the console and you will see).compose
isn't necessary in this case, need to pull out the code, and font
word was missingred bfont: make font! [size: 15 style: [bold]] view [ button "Clear" 70x50 [ f/text: copy ""] font bfont ]
#define
for macros. adata: [[204.255.204 "Information"] [255.255.153 "Warning"] [255.204.204 "Error"]] kind: 1 bgcolor: first adata/:kind msgtype: second adata/:kind
adata: [[204.255.204 "Information"] [255.255.153 "Warning"] [255.204.204 "Error"]] kind: 1 set [bgcolor msgtype] adata/:kind
>> blk: [print (var)] == [print (var)] >> fn: func [var] [do compose blk] == func [var][do compose blk] >> fn 12 *** Script Error: var has no value *** Where: compose *** Stack: fn
>> blk: [print var] == [print var] >> fn: func [var] [do blk] == func [var][do blk] >> fn 12 *** Script Error: var has no value *** Where: print *** Stack: fn
>> blk: [print var] == [print var] >> fn: func [var] [do bind blk 'var] == func [var][do bind blk 'var] >> fn 42 42
>> blk: [print var] == [print var] >> o1: object [var: 1] == make object! [ var: 1 ] >> o2: object [var: 2] == make object! [ var: 2 ] >> do-in: func [ctx blk][do bind blk ctx] == func [ctx blk][do bind blk ctx] >> do-in o1 blk 1 >> do-in o2 blk 2
with
function. @rebolek has a multi-binding example, but this will give you the idea:with: func [ object [object!] body [block!] ][ do bind/copy body object ] e.g. [ o: object [a: 1 b: 2] oo: object [c: 3 d: 4] oo: object [a: 3 b: 4] with o [a + b] with oo [a + b] ]
do-in
, but just a simple name change and it looks like a built-in feature of other languages.oo:
twice?#define
in Red or #macro
in Red/System.issue!
) in it that gets evaluated only at the expansion site.#macro
vs #define
is a general issue.#include
s in a context
#define
is the name used to feel more like C? That is, could macros in R/S also use #macro
as the name? (aside from the effort to change them all, of course)#define
is used on purpose yes. I don't think that using #macro
name in R/S would help (actually, it would rather bring confusion), as R/S macros have little in common with Red ones. The R/S ones are optionally parametrized templates, while Red ones are functions.?function?
at expansion site of a macro wherein a path to a function is constructed. The function takes no arguments but is not called (-s
output shows code that when copied and compiled manually works as intended)insert
to put values into a series at a given position. By default that will be the head, but you can use find
, at
, or skip
to insert at different positions.append
returns the head of the series while insert
returns the position just after the insert.head insert tail
append
/insert
. I stumbled upon repend
and it was just confusing (first thought it was like a reverse of append
or something?)repend
is appending while reducing:>> c: 2 append [1] [c] == [1 c] >> repend [1] [c] == [1 2]
>> b: 1 c: 2 >> repend [b][c] == [b 2] >> append [b] reduce [c] == [b 2] >> reduce append [b][c] == [1 2]
append arg1 reduce arg2
:)>> b: 1 c: 2 >> append reduce [b][c] == [1 c] >> repend [b][c] == [b 2]
#macro ['foo word!] func [[manual] s e][ obj: s/2 obj2: load append form obj "-o2" obj2-s: to-set-word obj2 fn: to-path reduce [obj2 'baz] new-body: reduce [ obj2-s obj 'print fn ] change/part s new-body e ] obj: object [ baz: does [42] ] foo obj
-s
gives:[ obj: object [ baz: does [42] ] obj-o2: obj print obj-o2/baz ]
lisp
as the lang for highlighting here, though I just use the ticks.-s
works, as you say.obj
instead, in the path, it's fine. Red [] obj: object [ baz: does [42] ] obj-o2: :obj print same? obj obj-o2 print do [obj-o2/baz] print obj-o2/baz
>> d: now == 11-Aug-2017/15:35:08-04:00 >> d + 10 == 21-Aug-2017/15:35:08-04:00 >> e: now/date == 11-Aug-2017 >> e + 10 == 20-Aug-2017
>> about Red for Windows version 0.6.3 built 9-Aug-2017/9:43:46+02:00 >> d: now == 11-Aug-2017/22:01:24+02:00 >> d + 10 == 21-Aug-2017/22:01:24+02:00 >> e: now/date == 11-Aug-2017 >> e + 10 == 21-Aug-2017
>> d: now == 11-Aug-2017/16:14:16-04:00 >> d + 10 == 21-Aug-2017/16:14:16-04:00 >> e: now/date == 11-Aug-2017 >> e + 10 == 20-Aug-2017 >> now/date + 10 == 20-Aug-2017 >> about Red for Windows version 0.6.3 built 11-Aug-2017/16:08:13-04:00
>> now/date + 10 == 20-Aug-2017 >> d: now == 11-Aug-2017/16:28:50-04:00 >> d + 10 == 21-Aug-2017/16:28:50-04:00 >> e: now/date == 11-Aug-2017 >> e + 10 == 20-Aug-2017 >> about Red for Windows version 0.6.3 built 11-Aug-2017/16:25:22-04:00
== %gui-console-2017-8-9-31253 == [11-Aug-2017 none] == 0 == 21-Aug-2017/0:00:00
>> system/build/config/build-basename == %gui-console-2017-8-3-49893 >> reduce [e: now/date e/timezone] == [11-Aug-2017 -4:00:00] >> e/timezone: 0 == 0 >> e + 10 == 21-Aug-2017/0:00:00
timezone
set? @meijeru too?>> g: now/date == 11-Aug-2017 >> g/timezone == -4:00:00
>> system/build/config/build-basename == %gui-console-2017-8-9-31253 >> reduce [e: now/date e/timezone] == [11-Aug-2017 none] >> e/timezone: 0 == 0 >> e + 10 == 21-Aug-2017/0:00:00
>> h: now/time == 17:14:07 >> h: now/date == 11-Aug-2017 >> h/timezone == none >> h + 10 == 20-Aug-2017
>> e: now/date/utc == 11-Aug-2017 >> e + 10 == 21-Aug-2017
now/date/utc
return right now for you?now/date
.now
just sets the time to zero and exits if /date
is used, but also has a platform component. now
.write-clipboard
help
is your friend as well.'print 'do reduce [fn]
type? obj/baz
says it's a path but it's special somehow as it normally auto invokes.loop
macro shows how.hotlink: funct [ {Return a onedrive hot link from a share link} u [url!] ][ link: rejoin [ https://api.onedrive.com/v1.0/shares/u "!" enbase u "/root/content" ] write clipboard:// link return link ]
object
block evaluation behavior. Is there a practical or technical reason for why I can't initialize a word in a context with the same name? Could this be a bug?>> a: 5 == 5 >> c: context [a: a] *** Script Error: a has no value *** Where: a *** Stack: context
>> c: context compose [a: (a)] == make object! [ a: 5 ]
>> f: does ["hello"] == func []["hello"] >> f == "hello" >> c: context compose [f: (:f)] == make object! [ f: "hello" ]>
>> a: 5 == 5 >> o: make object! [ [ probe context? 'a [ a: 1 [ probe context? 'a [ ] make object! [ a: unset ] make object! [ a: 1 ] == make object! [ a: 1 ]
a
is first added to the context to which o
is bound. By the time a: a
is evaluated a
exists in the context but is unset
.a
to which you wish to bind the a
in the object context. For example:>> a: 5 == 5 >> f: func[a][print a] == func [a][print a] >> o: make object! [ [ a: system/words/a [ f: get in system/words 'f [ f a [ ] 5 == make object! [ a: 5 f: func [a][print a] ]
>> a: 5 == 5 >> f: func[a][print a] == func [a][print a] >> c: make object! compose/deep [ [ a: (a) [ f: first [(:f)] [ f a [ ] 5 == make object! [ a: 5 f: func [a][print a] ]
in
before, but it never clicked for me how that could be used.any-type!
.any!
but that's cool#macro
system coming to R/S; something I'd mentioned before and got mixed up. Thanks!word!
s in a specific scope.word!
s in a specific scope.dir?: func [ "Returns TRUE if a file or URL is a directory." [catch] target [file! url!] /local info ][ info: throw-on-error [info? target] either none? info [false] [info/type = 'directory] ]
info?
dir?: func [file [file! url!]][#"/" = last file]
>> a: what-dir == %/c/program%20files%20%28x86%29/rebol/view/ >> dir? a == true >> snip a == %/c/program%20files%20%28x86%29/rebol/view >> dir? a == true
>> a: what-dir == %/C/Users/XX/XXX/Red/ >> dir? a == true >> snip a == %/C/Users/XX/XXX/Red >> dir? a == false
dir?
for the sake of expediency without thinking it through. load
for example, but that seems rational, you know a "design decision" as you say. But in the case of dir?
or words like it, it comes across as thoughtless and hacky.dir
, it's called *simpleio* after all😀 dir
, it's called *simpleio* after all😀 dir?
functionality as written. Many lines of code later, in troubleshooting after trying to port from REBOL to Red, it became clear the Red version of dir?
had diminished functionality. Looking at the source, that version seemed to be a hack merely to get it coded. If it isn't so be it. dir?
to give you the option to check one way or the other.dir?
difference too some time ago and thought that reason is that proper io id not implemented yet.data: make object! [ name: address: city: postal: province: country: dob: none ] db-data: [ ["Name" "John Smith"] ["Address" "123 Main Street"] ["City" "Vancouver"] ["Postal" "V1P3S4"] ["Province" "BC"] ["Country" "Canada"] ["DoB" 1960-07-22] ["IsCustomer" 1] ]
foreach row db-data [ all [ key: load row/1 key: in data key set key row/2 ] ]
parse
:parse db-data [some [into [set name string! set value any-type! (set in data load name value)]]]
do
dialect somewhere in the codeinterpreter
, not sure if it is what I'm looking for:parse
:Ddo
dialect
is either DSL
(i.e. string based) or eDSL
(i.e. realised in language constructs). If do
is a dialect and it's not string based, then it's probably embedded in Red, which doesn't make any sense to me, since do
**is** Red interpreter :Ddo
), perhaps we should just establish the terminology and explain what is a _Red dialect_?view
in Java or Python, so is it a Red dialect? or which language dialect is it?#sicp
_dialect_ ;)) during self-study. As for university - it was plain old C and Python in my case.a: [1 2 3] == [1 2 3] >> b: next a == [2 3] >> b == [2 3] >> take a == 1 >> b == [3]
b
in this example still return [2 3]
after take a
as a reference, i.e. without copying?list!
type in Rebol2, that I would like to bring to Red (implemented as a linked list), which has fixed references (Rebol2):>> l: make list! [a b c] == make list! [a b c] >> ref: at l 3 == make list! [c] >> remove l == make list! [b c] >> ref == make list! [c]
list!
hash!
field for records, but not for such tracking. Thanks for the hint. I'll try it.>> men: make deep-reactor! [recs: copy [1 "Rudolf" 2 "Heinrich" 3 "Joshua"]] == make object! [ recs: [1 "Rudolf" 2 "Heinrich" 3 "Joshua"] ] >> client: object [ids: [2 3] recs: is [r: clear [] forall ids [append/only r find/skip men/recs ids/1 2] r]] == make object! [ ids: [2 3] recs: [[2 "Heinrich" 3 "Joshua"] [3 "Joshua"]] ] >> remove/part men/recs 2 == [2 "Heinrich" 3 "Joshua"] >> men/recs == [2 "Heinrich" 3 "Joshua"] >> client/recs == [[2 "Heinrich" 3 "Joshua"] [3 "Joshua"]] >> remove/part men/recs 2 == [3 "Joshua"] >> client/recs == [none [3 "Joshua"]] >> insert men/recs [2 "Adolpho"] == [3 "Joshua"] >> client/recs == [[2 "Adolpho" 3 "Joshua"] [3 "Joshua"]]
deep-reactor!
refering to its own fields:client: make deep-reactor! [ids: [2 3] recs: is [r: clear [] forall ids [append/only r find/skip men/recs ids/1 2] r]] *** Script Error: set-quiet does not allow set-word! for its word argument *** Where: set-quiet *** Stack:
system/script/header
returns none
.>> rule: [p: any [['&& | '||] word!] (probe p) | word! p: (probe p) opt rule] == [p: any [['&& | '||] word!] (probe p) | word! p: (probe p) opt rule] >> parse [a && b || c && d && e] rule [a && b || c && d && e] == false
== [p: some [['&& | '||] word!] (probe p) | word! p: (probe p) opt rule] >> parse [a && b || c && d && e] rule [&& b || c && d && e] [&& b || c && d && e] == true
any
condition:>> parse "bflmpsvz" [any "xxxxxxxxxxx" to end] == true
don't care but advance the input anyway
? :)advance the input anyway, but care if it matches
:)>> x?: no parse "xxxaadds" [any ["x" (x?: yes)] to end] x? == true
paren!
if needed?>> blank: [(ws: charset " ^-^/") any ws] == [(ws: charset " ^-^/") any ws] >> func-rule: ["func" blank #"(" thru #")"] == ["func" blank #"(" thru #")"] >> parse "func(blabla)" func-rule == true >> parse "func (bleble)" func-rule == true
/a
and a
are the same key, as far as I understand.map: func [ "apply function to elements of the series" series [series!] spec [block!] body [block!] ][ collect [ foreach :spec series [ keep do reduce compose [func spec body (:spec)] ] ] ]
>> map [1 2 3][x][x + 1] == [2 3 4] >> map [1 2 3 4 5 6 7 8 9][x y z][x + y * z] == [9 54 135]
collect
/keep
combo, as for filtering, here's a draft:filter: func [series will-do?][ collect [ foreach thing series [ if will-do? thing [keep thing] ] ] ]
>> filter: func [data body][collect [foreach value data [if do bind body 'value [keep value]]]] >> filter [1 2 3 4 5][value > 3] == [4 5]
remove-each
that way too :-) Wonder, how expensive it is using binding ...>> filter-each: function ['word data body][ insert copy body reduce [to set-word! word none] collect [ until [ change next body first data if do body [keep first data] data: next data tail? data ] ] ]
>> dt [loop 1000000 [filter [1 2 3 4 5][value > 3]]] == 0:00:11.30457 >> dt [loop 1000000 [filter-each value [1 2 3 4 5][value > 3]]] == 0:00:14.77291
keep-each: func [ "Keeps only values from a series where body block returns TRUE." 'word [get-word! word! block!] "Word or block of words to set each time (will be local)" data [series!] body [block!] "Block to evaluate; return TRUE to collect" ][ remove-each :word data compose [not do (body)] data ] e.g. [ filter: :keep-each filter x [1 2 3] [x = 2] filter x [1 2 3] [odd? x] filter res [1 2 3] [odd? res] filter [x y] [a 1 b 2 c 3] [all [odd? y 'c = x]] filter x [(1 2) (2 3) (3 4)] [x = first [(2 3)]] ]
foreach/remove-each
and functional HOFs.parse
integer!
s?>> parse [1][1] *** Script Error: PARSE - invalid rule or usage of rule: 1 *** Where: parse *** Stack:
>> parse [1][1 1 1] *** Script Error: PARSE - invalid rule or usage of rule: 1 *** Where: parse *** Stack:
quote
)>> parse [1][1 1 quote 1] == true
>> random/seed now >> random 10 == 5 >> random/seed now >> random 10 == 5 >> random/seed now >> random 10 == 5
/seed
the result is different from 5. This makes me think that seeding takes the "wrong" part of the date!
value. This is confirmed by seeding with now/time
.randomize
in Red? Should be pretty easy to port, though we'll want some good tests.randomize: func [ "Reseed the random number generator." /with seed "date, time, and integer values are used directly; others are converted." ][ random/seed either find [date! time! integer!] type?/word seed [seed] [ to-integer checksum/secure form any [seed now/precise] ] ]
>> b: #{00112233445566778899} == #{00112233445566778899} >> parse b [some [#{44} (print 'found!) | skip]] found! == true
some [ ... | skip]
in a top rule :smile: to
and thru
are powerful, but may be too greedy because of how they work. If you start with [a | b | c | skip]
as a basic plan, moving more specific rules up the chain, that's not a bad way to start. Parse
can be a devious master/mistress. When I see guru parse designs, I sometimes have to tease them apart bit by bit to understand them.parse
- what parts of the Red (and Rebol) are considered dialects (apart from obvious math
, view
, draw
and parse
itself)?Charset
is a little one.Do
is not a dialect, correct. It's the other one: Function specs.do
it.zero: [0 3 #{00}] byte: [1 [#{12} | #{22} | #{0B} | #{1E}]] uint: [zero byte] code: [4 uint] rule: [some [copy result code | skip]]
cs/8: charset {[](){}"@:;} ;-- not-file-char cs/23: charset {[](){}";} ;-- not-url-char ;-- couldn't the above be?... cs/8: union s/23 charset "@:" ;-- not-url-char + not-file-char
make
is the function that actually creates objects everywhere, and like Gregg said, it's normal Red code.context
different from the *system context* to store all the words that are defined in that *block* .object
and context
are synonymousurl-rule: [ #":" not [not-url-char | ws-no-count | end] any [#"@" | #":" | ahead [not-file-char | ws-no-count] break | skip] e: (type: url! store stack do make-file) ]
cs/23: charset {[](){}";} ;-- not-url-char
cs: [- - - - - - - - - - - - - - - - - - - - - - - - - - - -] ;-- memoized bitsets
[0 1 0 1 0]
from [0 0 0]
and [1 1]
blocks?== 840 >> b1: [0 0 0] == [0 0 0] >> b2: [1 1] == [1 1] >> collect [repeat i max length? b1 length? b2 [if b1/:i [keep b1/:i] if b2/:i [keep b2/:i]]] == [0 1 0 1 0]
collect
too, doesn't look elegantinterleave: func[a b][ out: make block! add (al: length? a) (bl: length? b) ; <-- like here, vs. collect either al > bl [ r: a diff: al - bl share: bl ][ r: b diff: bl - al share: al ] repeat i share [ repend out [a/:i b/:i] ] repeat j diff [ append out r/(i + j)] out ] zip: func[a b][ out: make block! (2 * m: min length? a length? b) repeat i m [ repend out [a/:i b/:i] ] out ]
>> fastest [sin PI] [10 + 20] == [10 + 20]
extract
for an interleaving functionextract
then it comes to table-like structures, but I'm not sure if it's applicable in this case>> extract [0 1 0 1 0] 2 == [0 0 0] >> extract/index [0 1 0 1 0] 2 2 == [1 1]
interleave3: func[b1 b2][ ; slow out: make b1 (add length? b1 length? b2) repeat i max length? b1 length? b2 [if b1/:i [append out b1/:i] if b2/:i [append out b2/:i]] out ] interleave4: func[a b][ ; faster, nearly as fast as pre-allocation for vector! slightly faster for block! for some reason either (al: length? a) > (bl: length? b) [ r: a diff: al - bl share: bl ][ r: b diff: bl - al share: al ] collect [ repeat i share [ keep a/:i keep b/:i ] repeat j diff [ keep r/(i + j)] ] ]
interleave4
, note that func
doesn't capture local words [r diff share a1 b1]
. Use function
to capture them automatically, or /local
with func
.rejoin
a Series of Strings with commas in between the strings? so something on the lines of:>> foo ["a" "b" "c"] == "a,b,c"
delimit
func for R2, but it uses forskip
which we don't have in Red yet. In the meantime:make-dlm-str: func [blk ch [char!] /local str][ str: copy "" foreach val blk [append str val append str ch] take/last str str ] make-dlm-str ["a" "b" "c"] #","
replace
model may be what you want, or not, if you're strings have spaces in them.>> replace/all form ["a a" "b" "c"] space comma == "a,a,b,c"
extract
function about which I asked recently>> x: [0 1 0 1 0] == [0 1 0 1 0] >> extract x 2 == [0 0 0] >> extract/index x 2 2 == [1 1] >> ; now I want x back from [0 0 0] and [1 1]... how?
>> commize: func [x][rejoin next collect [foreach v x [keep reduce [comma v]]]] == func [x][rejoin next collect [foreach v x [keep reduce [comma v]]]] >> commize ["a a" "b" "c"] == "a a,b,c"
>> parent: object [] == make object! [] >> clone1: copy parent == make object! [] >> clone2: copy parent == make object! [] >> equal? class-of :parent class-of :clone1 == true >> equal? class-of :parent class-of :clone2 == true
class-of
is TBD and I'm not sure if it should be used like thatclass-of
.make-with-proto
helper func.forskip
a *lot*, but it's been useful a number of times.do %simplediff.red similarity-of: func [ before [string!] after [string!] ][ round 200% * ( length? rejoin collect [ foreach [disposition part] diff before after [ if disposition = '= [keep part] ] ] ) / ( add length? before length? after ) ] probe similarity-of "Pencilvaneya" "Pennsylvania"
parse "..." none.
Should probably be split "..." #" "
>> parse "Foo, Bar" none == ["Foo" "Bar"]
split
without argument with default action as parse "..." none
would be nice. With refinement /with dlm
combine: func [blocks][ out: clear [] num: length? first blocks repeat i num [foreach b blocks [append out pick b i]] ] trim combine [[1 1 1][0 0]] == [1 0 1 0 1]
trim combine [[1 1 1][0 0][2 2 2]] == [1 0 2 1 0 2 1 2]
combine: func [blocks][ out: clear [] num: 0 forall blocks [num: max num length? first blocks] repeat i num [foreach b blocks [append out pick b i]] trim out ]
merge
dialect with detailed spec, kinda merge [1 1 1][2 0 after each 3-rd] --> [1 0 0 1 1 0 0]
collect/keep
>> 3-rd *** Syntax Error: invalid integer! at "3-rd" *** Where: do *** Stack: load
skip
is a special keyword to skip valueparse
to parse and insert stuff at the same time>> d: [1 1 1 1 1 1 1] == [1 1 1 1 1 1 1] >> parse d [ any [skip 2 [ p: (insert p 0) skip ] skip ] ] == false >> d == [1 0 0 1 1 0 0 1 1 0 0 1 1 0]
parse
:Dmerge: func [blk spc][ parse spc [any [set times integer! set num integer! 'after 'each set skp integer!]] blk: skip blk 1 while [yes][ blk: insert/dup blk num times if any [tail? blk skp > length? blk] [break] blk: skip blk skp ] head blk ] >> merge [1 1 1][2 0 after each 2] == [1 0 0 1 1 0 0]
text >> block: [ 1 [joe was here] 2 [mary is there] 3 [jim will be gone]] == [1 [joe was here] 2 [mary is there] 3 [jim will be gone]] >> head remove/part find block 2 2 == [1 [joe was here] 3 [jim will be gone]]
>> block: [] == [] >> repeat i 1000 [append block make object! compose [index: (i)]] == [make object! [ index: 1 ] make object! [ index: 2 ] make object! [ index: 3 ] make object! [ index: 4 ] make object! [ index: 5 ] make ... >> o: block/345 == make object! [ index: 345 ] >> o: block/345/index == 345
>> b: compose [(make object! [a: 1 b: 2]) (make object! [a: 3 b: 4])] == [make object! [ a: 1 b: 2 ] make object! [ a: 3 b:... >> get in first b 'a == 1 >> get in second b 'b == 4 >> b/1/a == 1 >> b/2/b == 4
>> b: [] == [] >> a: make object! [id: "i1"] == make object! [ id: "i1" ] >> append b a == [make object! [ id: "i1" ]] >> print b/1/id i1 >> print b/a/id *** Script Error: path b/a/id is not valid for none! type *** Where: print *** Stack:
>> b: [] == [] >> a: object [id: "i1"] == make object! [ id: "i1" ] >> append b a == [make object! [ id: "i1" ]] >> b/1/id == "i1" >> b/a/id *** Script Error: path b/a/id is not valid for none! type *** Where: catch *** Stack: >> append b compose [a: (a)] == [make object! [ id: "i1" ] a: make object! [ id: "i1" ]] >> b/a/id == "i1"
flatten: func [tree [block!] /level lvl /local rule l][ (l: -1) rule: [(l: l + 1) some [ ahead block! if (any [not level l < lvl]) into rule (l: l - 1) | keep skip ]] parse tree [collect rule] ] >> flatten/level [0 [1 1] 0 [[2 2 [3 3]]]] 1 == [0 1 1 0 [2 2 [3 3]]] >> flatten/level [0 [1 1] 0 [[2 2 [3 3]]]] 2 == [0 1 1 0 2 2 [3 3]] >> flatten [0 [1 1] 0 [[2 2 [3 3]]]] == [0 1 1 0 2 2 3 3]
ahead block! into rule | keep skip
?form
loses tons of information>> b: [] p: b repeat i 1000 [repend/only p [i []] p: last p] == [1000 []] >> flatten: func [data][ret: copy [] i: 0 rule: [(i: i + 1) some [ahead block! into rule | set value skip (append ret value)]] parse data rule] == func [data][ret: copy [] i: 0 rule: [(i: i + 1) some [ahead block! into rule | set value skip (append ret value)]] parse data rule] >> flatten b *** Script Error: PARSE - stack limit reached *** Where: parse *** Stack: flatten >> last ret == 832
>> form [1 [2 [3]]] == "1 2 3" >> mold [1 [2 [3]]] == "[1 [2 [3]]]"
mold
is not helpful in this case.flatten: func [ "Returns a block, with all sub-blocks replaced by their contents." block [any-block!] "(modified)" ][ forall block [ if block? block/1 [change/part block block/1 1] ] block ] e.g. [ flatten [1 [2 [3 [4] 5] 6] 7] flatten [1 [2 [3 [4] 5] 6] 7 [8]] flatten at [1 [2 [3 [4] 5] 6] 7] 2 ]
flatten
skips initial deeper nestings: >> flatten [[[2 2] 1] 0] == [[2 2] 1 0]
change
continues after changed index, and if first element of last flattened block is block it doesn't look at it, I think.>> flatten [0 [[2 2] 1]] == [0 [2 2] 1]
flatten
needs a small change to handle deeply nested blocks:flatten: func [ "Returns the block, with all sub-blocks replaced by their contents." block [any-block!] "(modified)" ][ forall block [ if block? first block [ until [ not block? first back change/part block first block 1 ] ] ] block ]
flatten: func [ "Returns the block, with all sub-blocks replaced by their contents." block [any-block!] "(modified)" /local idx-before idx-after ][ forall block [ if block? first block [ until [ idx-before: index? block change/part block first block 1 idx-after: index? block not block? first skip block idx-before - idx-after ] ] ] block ]
text >> flatten [1 [2 [3 [4]]]] == [1 2 3 4] >> flatten [[[[1]]] [2 [3 [4]]]] == [1 2 3 4] >> flatten [[[[[1]] 5] 6] [2 [3 [[4]]]]] == [1 5 6 2 3 4]
flatten: func [b [block!] /deep /local r value rule][ either deep [ local: make block! length? b rule: [ into [some rule] | set value skip (append local value) ] parse b [some rule] local ] [ r: make block! length? b head any [foreach v b [insert tail r v] r] ] ]
local
word to keep values.>> block: collect [repeat i 1000 [keep make object! compose [index: (i)]]] == [make object! [ index: 1 ] make object! [ index: 2 ] make object! [ index: 3 ] make object! [ index: 4 ] make object! [ index: 5 ] make... >> find-object: func [block object][forall block [if equal? object block/1 [return block]]] == func [block object][forall block [if equal? object block/1 [return block]]] >> find-object block make object! [index: 335] == [make object! [ index: 335 ] make object! [ index: 336 ] make object! [ index: 337 ] make object! [ index: 338 ] make object! [ index: ...
>> find-object: func [block word value][forall block [if equal? select block/1 word value [return block]]] == func [block word value][forall block [if equal? select block/1 word value [return block]]] >> find-object block 'index 335 == [make object! [ index: 335 ] make object! [ index: 336 ] make object! [ index: 337 ] make object! [ index: 338 ] make object! [ index: ...
find-object
returns series at index where your object was foundfind
's functionality, that returns position in block, you can change it to return just value (object).>> time-it/count [to block! form b] 1000 == 0:00:14.147
_(:3」∠)_
dangflatten
. I made some tests using rebolek's b: [] p: b repeat i 800 [repend/only p [i []] p: last p]
for nested block. According to my experiments the fastest code to deep-flatten blocs is following:flatten-deep1: func [tree [block!] /local rule][ rule: [any [into rule | keep skip | none]] parse tree [collect rule] ] >> time-it/count [flatten-deep1 copy b] 1000 == 0:00:01.438
collect into
.flatten-deep2: func [tree [block!] /local rule out][ out: copy [] rule: [some [into rule | keep skip | none]] parse tree [collect into out rule] out ] >> time-it/count [flatten-deep2 copy b] 1000 == 0:00:01.526
flatten-deep3: func [data /local i ret value][ ret: copy [] rule: [some [into rule | set value skip (append ret value)]] parse data rule ret ] >> time-it/count [flatten-deep3 copy b] 1000 == 0:00:02.184 flatten-deep4: func [b [block!] /local value rule][ local: make block! length? b rule: [ into [some rule] | set value skip (append local value) ] parse b [some rule] local ] == 0:00:02.201 >> time-it/count [flatten-deep4 copy b] 1000 flatten-deep5: func [ "Returns a block, with all sub-blocks replaced by their contents." block [any-block!] "(modified)" ][ forall block [ if block? block/1 [ change/part block block/1 1 block: skip block -1 ] ] block ] >> time-it/count [flatten-deep5 copy b] 1000 == 0:00:02.473
flatten-deep6: func [ "Returns the block, with all sub-blocks replaced by their contents." block [any-block!] "(modified)" /local idx-before idx-after ][ forall block [ if block? first block [ until [ idx-before: index? block change/part block first block 1 idx-after: index? block not block? first skip block idx-before - idx-after ] ] ] block ] >> time-it/count [flatten-deep6 copy b] 1000 == 0:00:04.224
flatten: function [ "Returns a block, with all sub-blocks replaced by their contents." block [any-block!] "(modified)" ][ while [p: find block block!][change/part p p/1 1] block ]
Copy
is likely the difference. Mine is meant to modify in place. >> time-it/count [flatten-tv-deep1 [[1 2 3 [4 5 6 [7 8 9 [10 11 12 [13 14 15 [16 17 18 [19 20]]]]]]]]] 100000 == 0:00:01.702 >> time-it/count [flatten copy [[1 2 3 [4 5 6 [7 8 9 [10 11 12 [13 14 15 [16 17 18 [19 20]]]]]]]]] 100000 == 0:00:00.93
copy
. Otherwise 999 test would go on flat block_(:3」∠)_
>> b: [] p: b repeat i 800 [repend/only p [i []] p: last p] == [800 []] >> b == [[1 [] [2 [] [3 [] [4 [] [5 [] [6 [] [7 [] [8 [] [9 [] [10 [] [11 [] [12 [] [13 [] [14 [] [15 [] [16 [] [17 [] [18 [] [19 [] [20 [] [21 [] [22...
b
, but deep1
hits the parse
stack limit. Wonder why it doesn't for you.b
generation is fine, probably why Bolek did that.collect
we don't have a choice.collect
is great for collecting. For more advanced control, you can use Red code.Lest
uses this a lot in R3.collect
is faster, but yes, certainly changing in-place is also needed. flatten: function [ "Returns a block, with all sub-blocks replaced by their contents" block [any-block!] /in-place "Modify block argument in place" ][ either in-place [ while [p: find block block!][change/part p p/1 1] block ][ rule: [any [into rule | keep skip | none]] parse block [collect rule] ] ]
>> time-it/count [flatten copy b] 1000 == 0:00:01.497 >> time-it/count [flatten/in-place copy b] 1000 == 0:00:06.583 >>
| none
for in your deep1
version? We also need to add back the ahead
check for block values, otherwise strings in the block are a problem, and parens just vanish.ahed
is certainly needed in general case. I put | none
in there because my initial version didn't catch empty blocks:flatten: func [tree [block!] /level lvl /local rule l][ (l: -1) rule: [(l: l + 1) some [ ahead block! if (any [not level l < lvl]) into rule (l: l - 1) | keep skip ; | none ]] parse tree [collect rule] ] flatten b == [1 [] 2 [] 3 [] 4 [] 5 [] 6 [] 7 [] 8 [] 9 [] 10 [] 11 [] 12 [] 13 [] 14 [] 15 [] 16 [] 17 [] 18 [] 19 [] 20 [] 21 [] 22 [] 23 [] 24 [] 25 [] ...
| none
at place:>> flatten b == [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 ...
flatten2: func [tree [block!] /level lvl /local rule l][ rule: [some [ into rule | keep skip ]] parse tree [collect rule] ] >> flatten2 b == [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 ...
| none
>> time-it/count [flatten2 copy b] 1000 == 0:00:01.576
| none
>> time-it/count [flatten2 copy b] 1000 == 0:00:01.496
db: [ integer [data block] ... integer [data block] ]
map!
that is key/data by defaultparse db [some [integer! block!]]
, using a key
rule if you need more than integer values checked by type.stylize
once to do it, it needed to be compiled into Red, but I think it should be possible to have stylize
even in interpreted Red.system/view/VID/styles
where styles are defined, try to add your style there.system/view/VID/styles
reverse
to see my block as fixed sized record? Like that:>> reverse/record [1 2 3 4] 2 >> [3 4 1 2]
stylize
is better, would be to include the styles into the layout block. e.g.:>> ss: [style ok-button: button "OK"] == [style ok-button: button "OK"] >> view head insert [ok-button button "Cancel"] ss
layout/styles
:ss: [ ok-button: [ default-actor: on-click template: [type: 'button size: 60x23 text: "OK"] ] ] view layout/styles [ok-button button "Cancel"] ss
template
.para
para!
is related only to text positioningtemplate
and default-actor
to a face?probe Text-list!
?screen
with window
children>> l: layout [base "inspect me"] == make object! [ type: 'window offset: none size: 100x100 ... >> dump-face first l/pane Type: base Style: base Offset: 10x10 Size: 80x80 Text: "inspect me" == make object! [ type: 'base offset: 10x10 size: 80x80 ...
pane
by indexes is tricky, maybe there's a better waycompose
styles, right.object!
is just like any other value, you can print
, mold
, form
, probe
it or whatever. It also supports reflection:>> obj: object [answer: 42] == make object! [ answer: 42 ] >> words-of obj == [answer] >> values-of obj == [42]
reverse: func [ series /skip rec /part len /local i ][ rec: any [rec 1] either 0 = ((length? series) % rec) [ len: any [len length? series] i: 1 loop (len / rec - 1) [ i: i + rec series: at head series i insert head series take/part series rec ] head series ][cause-error 'user 'message ["Wrong length of series or skip!"]] ] >> reverse/skip/part [1 2 3 4 5 6] 2 4 == [3 4 1 2 5 6] >> reverse/skip [1 2 3 4 5 6] 2 == [5 6 3 4 1 2] >> reverse [1 2 3 4 5 6] == [6 5 4 3 2 1] >> reverse/skip [1 2 3 4 5 6] 3 == [4 5 6 1 2 3]
obj: object [answer: 42] == make object! [ answer: 42 ] words-of obj == [answer] obj: object [question: 12] == make object! [ question: 12 ] words-of obj == [question]
obj
to a new object!
, the original one is lost forever, hence no answer
fieldView
in header can be written without a quoteobj: make obj [question: 12]
, later we will have extend obj [question: 12]
but it is not yet implemented. obj: make obj [question: 12]
you are not extending an existing object, but creating a new one and rebinding the word obj
to newly created object.make object! [answer: 42 question: 12]
.--> match: [#"^"" thru #"^"" | #"'" thru #"'" | e: #">" break | input: "]" ==> not matched match: [#"'" thru #"'" | e: #">" break | skip] input: "]" ==> not matched match: [e: #">" break | skip] ; (1) input: "]" match: [thru #"^"" | #"'" thru #"'" | e: #">" break | skip ; (2) input: "]" ==> not matched match: [#"'" thru #"'" | e: #">" break | skip] ; (3) input: "]" ==> matched return: true == true
break
and skip
works here. Does break
return to the beginning of the rule after (1)? Does it match (there is no ==> [not] matched
)>> var: "some text" == "some text" >> view compose [text (rejoin ["var holds" space var])]
>> ammo: 9'000 == 9000 >> view compose [text (rejoin ["Ammo holds:" space ammo])]
red/gui-branch
](https://gitter.im/red/red/gui-branch) room, as I never actually tried to create an app with multiple windows (I believe @honix did)>> ammo: 9'000 == 9000 >> t: rejoin ["Ammo holds:" space ammo] == "Ammo holds: 9000" >> view [text t]
ammo
values if it changesa: layout [text "window 1"] b: layout [text "window 2"] view/no-wait a view b
view
inside a block?view
is enough, @honix showed a trick with multiple windowsview
is a function that expects a valid VID block>> var: random 6 == 1 >> form var == "1" >> txt: form var == "1" >> view [text txt]
Ctrl + Shift + M
and meditate on Markup, it easier to help then question is formatted nicely ;)view
s"?view/no-wait
on all windows, then call do-events
.a: layout [text "window 1"] b: layout [text "window 2"] view/no-wait a view/no-wait b do-events
help
and source
in the console, even if you don't understand everything you see yet.make-character: does [ random/seed now/time str: [random 6] dex: [random 6] con: [random 6] per: [random 6] view/no-wait [ size 450x500 return h5 "Name: " 100x30 name-field: field "" [print ["name-field holds " face/text] ] return h5 "Epithet: " 100x20 epithet-field: field "" [print ["epithet-field holds " face/text] ] return h5 "Occupation: " 100x20 occupation-field: field "" [print ["occupation-field holds " face/text] ] return return across text "Strength: " 100x20 str-text: text [str] [print ["str-text holds " str] ] progress "str / 100" return across text "Dexterity: " 100x20 dex-text: text [dex] [print ["dex-text holds " dex] ] progress "dex / 100" return across text "Constitution: " 100x20 con-text: text [con] [print ["con-text holds " con] ] progress "con / 100" return return across text "Personality: " 100x20 per-text: text [print ["per-text holds " per] ] progress "per / 100" return return return button "Create" button "Abandon" ] ] view [ button "Make character" [make-character] ]
view
call, at the end, starts the event loop. Then, any other windows you show can, but don't have to, use /no-wait
.form
is a function that gets value and returns it's string representationview [size 200x200 text "first" do [view/no-wait [size 100x100 text "second"]]]
panel
style inside a window...or what @9214 just said. view
, because they're standalone examples on their own...
, but want to ..."view compose [...]
I meant that you should try to use compose
in a similar way in your code, i.e. inserting it between your view
and whatever [...]
follows.compose
d block is not a valid VID description of a UI*-text
functions which you've inserted, view
can't figure out what this means and squeaks :mouse: rename
. Is there a quick and dirty way to do it in Red?>> rename: func [old new][write new read old delete old] == func [old new][write new read old delete old] >> write %foo "test" >> rename %foo %bar == true >> read %bar == "test" >> read %foo *** Access Error: cannot open: %foo *** Where: read *** Stack:
call
.split-path
/binary
for the above func, just to be safe.attempt
is already thererename
. 0.x.x
version of a language in production? :boom: write/info
could help, but I don't know the specstext >> write %test.red [object [a: 1] object [b: 2]] >> load %test.red == [object [a: 1] object [b: 2]]
>> write %777.txt [object [a: 1] object [b: 2]] >> bb: load %777.txt == [object [a: 1] object [b: 2]] >> type? bb == block! >> type? bb/1 == word!
text >> write %test.red [object [a: 1] object [b: 2]] >> reduce load %test.red == [make object! [ a: 1 ] make object! [ b: 2 ]]
save
sort
compare none
with other values?>> sort [2 1 3 6 5 none] == [1 2 3 5 6 none] >> sort/compare [2 1 3 6 5 none] func [a b][a < b] *** Script Error: cannot compare none with 6 *** Where: < *** Stack:
sort
putting it last, and what about strings?>> sort [none "a" "c" "b"] == ["a" "b" "c" none]
none
values are moved to the beginning, instead of end as in sort
. >> vals: [#"a" "a" %a 'a a a: :a /a <a> #a none 1 1.0 1% 1x1 () [] "" a:// 1:1:1 1/1/1] == [#"a" "a" %a 'a a a: :a /a <a> #a none 1 1.0 1% 1x1 () [] "" a:// 1:01:01 1-Jan-2001] >> sort copy vals == [[] () "" "a" %a a:// 1 #"a" 1.0 a: 'a :a /a a none #a 1x1 1% 1:01:01 <a> 1-Jan-2001]
reduce*
that reduces unset!
to none!
is trivial, adding support for errors is much harder.>> reduce+ [1 + 1 print "asdf" now] asdf == [2 none 31-Aug-2017/22:42:02+01:00]
>> reduce+ [1 + 1 1 / 0 now] == [2 none none 0 31-Aug-2017/22:42:10+01:00]
>> reduce+ [bound-word non-bound-word] *** Script Error: non-bound-word has no value
none
.forall
and replacing unbound words / errors with none
. Yours' is nicer :)1 + 1
?attempt
whether item has type or value and skipping if it has.1 + 1
. right?2
.>> reduce+ [none 2 + non-existing] == [none none none none] >> reduce+ [non-existing] *** Script Error: tail? does not allow none! for its series argument
none
s?none
?do/next
does not advance the position in block, so I have to do it manually. I don't know where, so I just skip one value and do/next
again until error is gone.>> reduce+ [2 + non-existing] == [none none none] >> reduce+ [non-existing + 2] == [none none 2]
save
does mold
for you and lot of other things (see source for details). write
is good for writing raw text, save
for Red's data and code.red/bugs
>> context [alive?: yes count: 0 set 'dude func [/state] compose [either state [return (self)][count: count + 1]]] == make object! [ alive?: true count: 0 ] >> kill: func [s-func][set in s-func/state 'alive? no :s-func] == func [s-func][set in s-func/state 'alive? no :s-func] >> dude == 1 >> dude == 2 >> dude == 3 >> kill :dude == func [/state][either state [return (self)] [count: count + 1]] >> dude/state == make object! [ alive?: false count: 3 ]
compose
self
reference from function's body -- there will be no other way but to use well-defined interface of /set-foo
/get-foo
and et ceterain
usage; @JacobGood1's closure func closure: 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)] ] ; @dockimbel's closure func closure2: func [vars spec body][ bind (body-of spec: func spec body) (context vars) :spec ]
spec
to the function is just because spec
is already captured by the func
(being an argument), so reusing it avoids leaking some other temp word in the global context (or needing to create a temp word)?closure: func [vars spec body][func spec bind body context vars]
compose
closure1: func [vars spec body][bind body-of spec: func spec body context vars :spec] closure2: func [vars spec body][func spec bind body context vars] gen1: closure1 [x: 0][/local x][x: x + 1] gen2: closure2 [x: 0][/local x][x: x + 1] >> gen1 == 1 >> gen1 == 2 >> gen2 *** Script Error: + does not allow none! for its value1 argument
func
after binding the body
(as in closure2
) rebinds x
to none
, but binding the body
after creation of func
(closure1
) leaves x
with desired binding._(:3」∠)_
restart
for the above gen1
:restart: func [f][bind body-of :f context reduce [to-set-word last spec-of :f 0]] >> restart :gen1 == [x: x + 1] >> gen1 == 1 >> gen1 == 2
reduce
instead of..." and bam, here it isws: charset " ^/^M^-"
>> to-integer #"^M" == 13 >> to-integer #"^/" == 10 >> to-integer #"^-" == 9
ws: charset reduce [space newline carriage-return horizontal-tab]
>> to-integer #"^|" *** Syntax Error: invalid char! at {#"^^|"} *** Where: do *** Stack: load
newline
, space
etc are just a sugar:>> reduce [newline space tab lf] == [#"^/" #" " #"^-" #"^/"]
>> foreach i spec-of :reduce [ if type? i = word! [print type? i] ] string word block refinement string word block string
if word? i
is simplerop!
s are "hungry" on left side. You could use parens though.red-05sep17-0f19dc1.exe
doesn't create an executable in ProgramData. In that directory is created crush dll and 10 red/reds files. I use Win 10.>> ? char! null #"^@" newline #"^/" slash #"/" tab #"^-" lf #"^/" dbl-quote #"^"" space #" " CR #"^M" dot #"." escape #"^[" sp #" " comma #","
D:\Program\Red>red-05sep17-0f19dc1.exe Compiling Red GUI console... *** Loading Error: file access error: %inflate.reds *** in file: %/D/Program/Red/call.reds *** at line: 125
do
it from Wine repl?/local
is very useful, and a neat peek into how func
operates. In this case I think it's also worth pointing out that the /local
is not needed since the local words are bound to a new context
and don't leak... maybe that is just pointing out the obvious.*edit some *.reds files* > vim *build fresh Red console* > rebol --do "do/args %red.r \"-r %environment/console/console.red\"" *run test gui with this console* > ./console tests/draw.red
Closure
, as we look at the design and implementation alternatives, shows why I love Red so much. We get to peek inside, without too much complexity, and see how things work. Sometimes I do have to burn a few brain cells to understand advanced trickery, but at least it's manageable. I learn so much, and think in new ways, even after many years with Redbol languages.closure
interface so it aligns well with the function
interface. The /local
example is a good one there. PoLS and all that. But it also sparked a thought here about how we can take this in new directions, which plays into Red being full stack. That is, use Red for most things, but Red/System when you need its capabilities. Going in the other direction, we can create a func spec dialect that supports stronger typing constraints, but also gives us context control. gen-user: super-fun [ [ info [object!] (protect vet as user-info-proto) seed [string!] (keep) "Hashed with last seed" ] /keep [keys count] /reuse [buffer [string!] n [integer!]] /init [seeded?: no] return: [object!] (vet as user-proto) ][...]
vars
some words which are declared /local
inspec
.gen-user: super-fun [ ; Spec for the func we're making. Parens are dialected control attributes. ; e.g. 'protect ensures the object passed in can't be modified in any way. ; 'vet compares an object (duck-typing) against a known interface. ; ' keep closes over the arg [ info [object!] (protect vet as user-info-proto) seed [string!] (keep) "Hashed with last seed" ] ; /keep closes over local values /keep [keys count] ; /reuse "resets" values without reallocating if possible /reuse [buffer [string!] n [integer!]] ; /init ...yeah, maybe we don't need this /init [seeded?: no] return: [object!] (vet as user-proto) ][...]
messages: copy [] obj: object [ me: msgs: none on-deep-change*: function [ owner word target action new index part ][ probe owner ] ] o1: make obj [ me: "o1" msgs: messages ] o2: make obj [ me: "o2" msgs: messages ]
messages
, only o1
reacts:>> insert messages ["Hi!"] [make object! [ me: "o1" msgs: ["Hi!"] ]]
make deep-reactor!
. Is it possible for both o1
and o2
to react on the change of same series? Red [ purpose: "Observer pattern example" ] ; See: http://www.red-lang.org/2016/03/060-red-gui-system.html blog entry ; Lots of name choices to consider. subject-proto: object [ _conns: copy [] ; observer connections on-deep-change*: func [owner word target action new index part][ ; The _conns check here is something we could support, so you could ; observe the changes to the observer list. if word <> '_conns [ foreach conn _conns [ attempt [conn/on-change owner word target action new index part] ] ] ] observer?: func [obj [object!]][ not none? find words-of obj 'on-change ] attach: func [obj [object!]][ ; /with words [word! block!] either observer? obj [ if not find _conns obj [append _conns obj] ; single-entry registrar ][ print mold obj return make error! "The given object doesn't look like an observer." ] obj ] detach: func [obj [object!]][ ; /with words [word! block!] take find _conns obj ] ] observer-proto: object [ on-change: func [owner word target action new index part][ print ['on-change owner word target action new index part] ] watch: func [obj [object!] "Subject"][obj/attach self] unwatch: func [obj [object!] "Subject"][obj/detach self] ] ;------------------------------------------------------------------------------- pub: make subject-proto [blk: copy [] str: copy ""] obs!: make observer-proto [ id: none on-change: func [owner word target action new index part][ print ['Observer id 'on-change '| 'word_ word 'act_ action 'val_ mold new 'idx_ index 'part_ part] ; owner target ] ] sub-a: make obs! [id: "A"] sub-b: make obs! [id: "B"] sub-a/watch pub sub-b/watch pub append pub/blk 1 append pub/str #"A" append pub/blk [2 3 4] take at pub/blk 3 sub-a/unwatch pub append pub/str "BCD"
/with
support, to control what you watch, but this already gnawed at me enough that I had to get it out here so my brain would let it go for a bit.Red [needs: 'view] v: layout [text "Some Text"] v/menu: ["File" ["Load" m-load "Save" m-save "Save As" m-saveas] ] v/actors: make object! [ on-menu: func [face [object!] event [event!] /local ep][ ep: event/picked switch/default ep [ 'm-load [print "Load"] 'm-save [print "Save"] 'm-saveas [print "SaveAs"] ][ print ["something is wrong here: " ep " = 'm-load --> " ep = 'm-load type? ep] ] ] ] view v
something is wrong here: m-save = 'm-load --> false word something is wrong here: m-load = 'm-load --> true word
switch
:switch/default ep [ m-load [print "Load"] m-save [print "Save"] m-saveas [print "SaveAs"] ][
>> do %messages.red >> insert gitter/messages ["Newbe" "Start"] Newbe: Hello! How many arguments does 'do-actor' have? Guru: 'do-actor' has 3 arguments! Newbe: And what are these arguments? Guru: These are 'face', 'event' and 'type'. Newbe: Cool! But how many refinements does 'to-percent' have? Guru: 'to-percent' has 0 refinements! Newbe: But how many arguments does 'dir' have? Guru: 'dir' has 1 argument! Newbe: And what is this argument? Guru: It is 'dir'. Newbe: Isn't that cute! But how many refinements does 'to-bitset' have? Guru: 'to-bitset' has 0 refinements! Newbe: But how many arguments does 'to-date' have? Guru: 'to-date' has 1 argument! Newbe: And what is this argument? Guru: It is 'value'. Newbe: Cool! But how many refinements does 'find' have? Guru: 'find' has 11 refinements! Newbe: And what are these refinements? Guru: One newbe can ask more than 10 gurus can answer. I have to do some work now. Have a nice day! BTW These are 'part', 'only', 'case', 'same', 'any', 'with', 'skip', 'last', 'reverse', 'tail' and 'match'. :) Newbe: You are my hero! Happy coding! Waiting for next release!>
area
?>> print read %Dropbox/red-tests/macro.red Red [] print "Testing Macros" print #switch config/OS [ Windows ["Windows"] Linux ["Unix"] MacOSX ["MacOS"] ] >> do %Dropbox/red-tests/macro.red *** Script Error: syntax-error does not allow none! for its s argument *** Where: syntax-error *** Stack: do-file expand-directives expand
text-box!
style is intended for that. You could also do it with Draw commands. Area
isn't what you want either. You could use panel
, but there is no standard scrolling panel yet. @rebolek has probably done the most work in this area.MacOSX
to macOS
some time ago and the doc was not updated.Red/System
the core language?+1
, -1
and loop
in core language to implement "sugar" like addition, multiplication, division etcparse
:^)(...)
after parse rules?text-box!
mention. Doesn't '!' denote a data type?group-box
? I can handle the selector line by myself until edge
comes out.text-box
is build in separate repository by Qtxie. text-box
may be the exact answer to my use-case.text:
string. block!
and string!
), words, contexts, numbers, actions (just a subset, not all of them) should be all you need for a working Redbol core.op!
s :-)apply
(not yet available in Red), so paths could be left out of a minimal core.+1
being used more than regular addition>> o: context [a: 1 b: 2] == make object! [ a: 1 b: 2 ] >> words-of o == [a b] >> values-of o == [1 2] >> reduce words-of o == [1 2]
>> z: [] append z 'o == [o] >> print words-of reduce z/1 1 2
print
reduces, so just use something else:>> z: [] append z 'o == [o] >> probe words-of reduce z/1 [a b] == [a b]
print mold
for exampleprint mold
is good :+1: :relieved:apply
func?apply :+ [1 2] => 3
>> apply: func [fn args][do reduce head insert args :fn] == func [fn args][do reduce head insert args :fn] >> apply :add [1 2] == 3
mapeach
probably to avoid confusion. mapeach: func [fn blk][ collect [foreach i blk [keep fn i]] ]
map: func [ "apply function to elements of the series" series [series!] spec [block!] body [block!] ][ collect [ foreach :spec series [ keep do reduce compose [func spec body (:spec)] ] ] ]
>> parse [a 1 b 2 c 3][(w: []) collect into w [some [keep word! | skip]]] == true >> w == [a b c]
>> parse [a 1 b 2 c 3][(w: tail [-->]) collect into w some [keep word! | skip]] == true >> head w == [--> a b c]
>> parse [a 1 b 2 c 3][collect set w some [keep integer! | skip]] == true >> w == [1 2 3]
map
@9214 ?>> map [1 2 3 4][x][x * 2] == [2 4 6 8]
spec
with more than one word doesn't work as expected, seems that I screwed up somewhere and forgot to check itfunc [x][x * 9]
func
every time then you can embed it inside a definition?func [x y][x + 1 y *2]
wait
in the help, but is it included yet? I tried it and it hangs the console.cause-error
?now/time/precise
) change a bit between runs.type? Item = word!
give me different results?blk: [green two red 5 dog]
foreach item blk [either type? item = word! [print "word"][print "not word"]]
foreach item blk [either word! = type? item [print "word"][print "not word"]]
word! = type? item
is word! = (type? item)
, but type? item = word!
is type? (item = word!)
. Also, I suggest you to just use word? item
.>> reduce [now/time/precise wait 00:00.1 now/time/precise] == [12:14:58.251 none 12:14:58.352]
map
with a fresh Red from today:>> map [1 2 3 4][x y][reduce [x + 1 y * 2]] == [2 2 none 2 4 4 none 2]
map
-ish funcs floating around.do reduce compose [func spec body (:spec)]
is quite a bit of overhead, which passing a func avoids.C:Users
and try>> map [1 2 3 4][x y][reduce [x + 1 y * 2]] == [2 4 4 8] >> about Red for Linux version 0.6.3 built 2-Sep-2017/20:48:21+05:00
>> map [1 2 3 4][x y][reduce [x + 1 y * 2]] == [2 4 4 8] >> about Red for Linux version 0.6.3 built 15-Sep-2017/13:32:54+05:00
>> map [1 2 3 4][x y][reduce [x + 1 y * 2]] == [2 4 4 8] >> about Red for Windows version 0.6.3 built 15-Sep-2017/13:36:49+05:00
cause-error 'user 'message ["Error message"]
Red [] x1: x2: x3: x4: x5: x6: x7: x8: x9: [] x: [x1 x2 x3 x4 x5 x6 x7 x8 x9] random/seed now/time/precise foreach i x [ i: copy reduce i loop 9 [append i random 9] print i ]
i
into x1
, x2
etc?x/x1: i
?xN
words for?x
.random/seed now/time/precise size: 9x9 matrix: collect [loop size/y [keep/only collect [loop size/x [keep random 9]]]] new-line/all matrix yes ?? matrix
matrix/:y/:x
.collect/keep
combo separately to learn it if it's new to you.size: 9x9 matrix: make block! size/y loop size/y [ row: make block! size/x loop size/x [append row random 9] append/only matrix row ] new-line/all matrix on
size-text
to calculate the width of current text and compare it to the field's width. You could put such code in a on-key-down
handler for that field, and when the limit is reached return 'stop
to block further keys from been accepted. I'll let someone else provide an example code for that.view [ f: field on-key-down [ l: length? f/text if all [l l > 6][ remove back tail f/text ] ] ]
view [ f: field on-key-down [ all [ attempt [4 < length? f/text] remove back tail f/text ] ] ]
detect
event and block the event from propagating there:system/view/capturing?: yes view [f: field "" on-detect [if 4 <= length? f/text [return 'stop]]]
detect
events are not emitted by default (for performance reasons), so the capturing?
flag needs to be set to allow them.system/view/capturing?: yes view [ f: field "" on-detect [ all [ 4 <= length? f/text attempt [8 <> to integer! event/key] return 'stop ] ] ]
""
it starts to detect every event (mouse hover in particular) and spits various errors in console. Why is that?system/view/capturing?: yes view [ f: field on-detect [ all [ event/type = 'key-down string? f/text 4 <= length? f/text attempt [8 <> to integer! event/key] return 'stop ] ] ]
>> map [1 2 3 4][x y][reduce [x + 1 y * 2]] == [2 4 4 8] >> about Red for Windows version 0.6.3 built 14-Sep-2017/13:15:36-06:00
set [x y] [[1 2][3 4]]
text >> map [1 2 3 4][x y][compose/deep [[(x)(y)]]] == [[1 2] [3 4]]
>> map [1 2 3 4][x y][reduce [reduce [x y]]] == [[1 2] [3 4]]
set [a b] map [1 2 3 4][x y][reduce [x + 1 y * 2]]
and have a
be [2 3 4 5]
and b
be [2 4 6 8]
>> set [a b] reduce [map [1 2 3 4][x][x + 1] map [1 2 3 4][x][x * 2]] == [[2 3 4 5] [2 4 6 8]] >> a == [2 3 4 5] >> b == [2 4 6 8]
>> map [1 2 3 4][a b c d][reduce [map [a b c d][x][x + 1] map [a b c d][x][x * 2]]] == [[2 3 4 5] [2 4 6 8]]
parse
rules here:mal-scalar: [ any whitespace [ p: (probe p) "nil" keep ('nil) | "true" keep ('true) | "false" keep ('false) | tmp: mal-number keep (to-integer tmp) | tmp: mal-string keep (tmp) | tmp: mal-keyword keep (to-get-word tmp) | tmp: mal-symbol keep (to-word tmp) ] ] mal-map: [ (tmp-series: copy []) collect into tmp-series [ "{" any [not "}" mal-scalar] "}" ] keep (to-map tmp-series) ] mal-list: [ (tmp-series: copy []) collect into tmp-series [ "(" any [not ")" mal-scalar] ")" ] keep (tmp-series) ] mal-vector: [ (tmp-series: copy []) collect into tmp-series [ "[" any [not "]" mal-scalar] "]" ] keep (tmp-series) ] mal-syntax: [ (error: false) any whitespace collect [ ahead "(" mal-list (probe "found list") | ahead "{" mal-map (probe "found map") | ahead "[" mal-vector (probe "found vector") | mal-scalar | (error: true) keep some [not whitespace skip] fail ] ]
>> mal/parser/run "(1 2)" "1 2)" "2)" "found list" == [1 2] >> mal/parser/run "[1 2]" "1 2]" "2]" "found vector" == [1 2] >> mal/parser/run "{1 2}" "1 2}" "2}" *** Syntax Error: invalid integer! at "2}" *** Where: do *** Stack: to-integer
"2}
to map!
key (or value), it starts with 2
, Red thinks that it's an integer!
, tries to convert it and, wellmal-scalar
map
instead of a blockto-map
, that's not the issueparse-trace
¯\_(ツ)_/¯
>> to-integer "2]" == 2 >> to-integer "2}" *** Syntax Error: invalid integer! at "2}" *** Where: do *** Stack: to-integer
parser-trace
that it doesn't reset indentation between the calls parse-trace
are welcome.--> match: [some make bitset! #{000000000000FFC0}] input: "2}" --> ==> matched <-- <-- match: ["nil" keep ('nil) | "true" keep ('true) | "false" input: "}" --> *** Syntax Error: invalid integer! at "2}" *** Where: do *** Stack: parse-trace to-integer
input: "2)" --> match: [some make bitset! #{000000000000FFC0}] input: "2)" --> ==> matched <-- <-- match: ["nil" keep ('nil) | "true" keep ('true) | "false" input: ")" --> <-- match: [keep ('nil) | "true" keep ('true) | "false" keep input: ")" <--
2
as a number and continues2}
(to-integer tmp)
. You didn't post your mal-number
rule, but maybe just a small adjustment would do:| tmp: mal-number e: keep (to-integer copy/part tmp e)
e
is not leaking to global context).}
, as it means it would be in string!.>> to integer! "2)" == 2 >> to integer! "2]" == 2 >> to integer! "2}" *** Syntax Error: invalid integer! at "2}" *** Where: do *** Stack:
}
in this list?to
conversions are calling the lexer underneath, so they are bound by lexer's rules.}
in this list?{123}
is a string!, 123{}
is an integer!, followed by a string!. So, 123}
is obviously a syntax error.>> parse "121" [set x some ["0" | "1" | "2"]] == true >> x == #"1"
set
use the value of a whole match?copy
doesset
saves only the first value of the matched inputs: e: (change/part s e)
, can it be simplified to special keyword, say replace
?replace ()
change
keyword for that. It was added in later releases.set
use the value of a whole match?set
keyword in Parse. It will just extract a single value, while copy
will extract one or more, but in a series of same type as the input.foreach [k v] m []
to-block
helps, nvm :)switch
available to accept datatypes as match-conditions?switch
is good enough| ahead "{" [mal-map (take/last error-stack) | (take/last error-stack)]
mal-map
attemptmal-map
fails whole branch will nottry
try/all
catches too manySwitch
branches based on value matching. Always has. @maximvl, in your first example:switch 5 [number! [1]]
number!
in the block is a word, as Bolek pointed out. But you can check types as well:>> switch number! reduce [number! [1]] == 1
do-by-type
funcs for R2, using switch type?/word ...
.env STEP=step0_repl MAL_IMPL=js ../runtest.py --deferrable --optional ../tests/step0_repl.mal -- ../red/run Exception: IOError(5, 'Input/output error') Output before exception: ** Script Error: Invalid compressed data - problem: -3 ** Near: script: decapsulate if none? script
>env STEP=step0_repl MAL_IMPL=js ../runtest-old.py ../tests/step0_repl.mal -- ../red/run Did not get 'user> ' or 'mal-user> ' prompt Got : '** Script Error: Invalid compressed data - problem: -3\r\n** Near: script: decapsulate \r\nif none? script\r\n'
>> abc/cond-words == make hash! [even? 1 odd? 1 head? 1 tail? 1 equal? 1 not-equal? 1 strict-equal? 1 lesser? 1 greater? 1 lesser-or-equal? 1 greater-or-equal? 1 same? 1 complement? 1 negative? 1 p... >> find abc/cond-words 'even? == none >> first abc/cond-words == even? >> 'even? = first abc/cond-words == true >> find abc/cond-words 'even? == none >> select abc/cond-words 'even? == none
>> h: make hash! [even? 1] == make hash! [even? 1] >> h/even? == 1 >> select h 'even? == 1 >> find h 'even? == make hash! [even? 1]
abc
a context?>> abc/cond-words == make hash! [even? 1 odd? 1 head? 1 tail? 1 equal? 1 not-equal? 1... >> find abc/cond-words 'even? == make hash! [even? 1 odd? 1 head? 1 tail? 1 equal? 1 not-equal? 1... >> first abc/cond-words == even? >> 'even? = first abc/cond-words == true >> find abc/cond-words 'even? == make hash! [even? 1 odd? 1 head? 1 tail? 1 equal? 1 not-equal? 1... >> select abc/cond-words 'even? == 1
>> h: make hash! [] == make hash! [] >> put h 'a 3 == 3 >> put h 'b 5 == 5 >> h == make hash! [a 3 b 5] >> select h 'a == none >> select h 'b == none >> h == make hash! [a 3 b 5]
>> about Red for Windows version 0.6.3 built 17-Sep-2017/11:38:27+02:00 >> h: make hash! [] == make hash! [] >> put h 'a 1 == 1 >> select h 'a == none >> h == make hash! [a 1]
>> h: make hash! [] == make hash! [] >> put h 'a 1 == 1 >> select h 'a == none >> about Red for Linux version 0.6.3 built 17-Sep-2017/14:41:34+05:00
closure1: func [vars spec body][bind body-of spec: func spec body context vars :spec] some-func: closure1 [...][...][...]
context [ ;var declarations set 'some-func ... bind body-of :some-func self ]
closure2: func [vars spec body][func spec bind body context vars] some-func: closure2 [...][...][...] context [ ;var declarations set 'some-func ... ]
func
is overriding the binding made by bind
, and will rebind the body block to the function's context.context [var1: ... var2: ... set 'some-func <spec> <body>]
some-func
is declaring local vars in its spec
which are also set in its context. >> idx == 3 >> c/idx *** Script Error: word! type is not allowed here *** Where: catch *** Stack: >> c/3 == #"e"
pick
?>> c: "def" == "def" >> c/3 == #"f" >> idx: 3 == 3 >> pick c idx == #"f"
c/:idx
c/idx
is a syntactic sugar for select c 'idx
, selecting a word!
value on a string! series is not possible. What you want is c/:idx
which translates to pick c idx
.? call
helps? It's helpful if you can provide code of what you have done so far. Check also the rebol docs>> call/console "ping 8.8.8.8" PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=53 time=36.8 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=53 time=36.5 ms 64 bytes from 8.8.8.8: icmp_seq=3 ttl=53 time=36.5 ms
./ZeroMQ-Hello-server: error while loading shared libraries: libzmq.so.5.0.0: wrong ELF class: ELFCLASS64
macmini:native ralfwenske$ ./ZeroMQ-Hello-server dyld: Library not loaded: @loader_path/libzmq.5.dylib Referenced from: /Users/ralfwenske/Dropbox/os/mac/native/./ZeroMQ-Hello-server Reason: no suitable image found. Did find: /Users/ralfwenske/Dropbox/os/mac/native/libzmq.5.dylib: mach-o, but wrong architecture Abort trap: 6
>> set [a b c d e] [".bear" "b.ear" "be.ar" "bea.r" "bear."] == [".bear" "b.ear" "be.ar" "bea.r" "bear."] >> move-punctuation a == "bear." >> a == "bear." >> move-punctuation b == "ear." >> b == "bear." >> move-punctuation c == "ar." >> c == "bear." >> move-punctuation d == "r." >> d == "bear." >> move-punctuation e == "." >> e == "bear."
pigify
converts to PigLatin>> move-punctuation pigify "cat!" == "cay!" >> s: "" == "" >> move-punctuation s: pigify "cat!" == "cay!" >> s == "atcay!"
brew install zmq --universal
Warning: zeromq: this formula has no --universal option so it will be ignored!
64bit only
quite hard.sudo apt-get install libzmq1:i386
? On the macOS side, I am not surprised since almost nothing is 32bit compatible now and I am then really disappointed.next
sometimes unable to locate package
. Would you have an idea for a source (to add to /etc/apt /sources.list) or maybe where I can start searching for it?parse
?sudo apt-get install libzmq5:i386
installed libzmq properly. dpkg --add-architecture i386 apt-get update apt-get install libc6:i386 libcurl3:i386
:i386
to have the i386 version. libzmq.so.5
and it was installed into /usr/lib/i386-linux-gnu/
. a
in a series, or search for multiple, different values? Or both? There's not a standard feature for that, but not hard to roll your own.find-all: function [ "Returns all positions in a series that match a test." series [series!] test [any-function!] "Test (predicate) to perform on each value; must take one arg" ][ collect [ forall series [if test series/1 [keep/only series]] ] ] find-all [1 2 3 4 5 6] :odd? find-all [1 2 3 4 5 6] :even? find-all [1 2 q 3 #x 4 /c 5 6] :any-word?
find-all: function [ series [series!] value ][ collect [ case [ function? :value [ forall series [if value series/1 [keep/only series]] ] any [word? value block? value] [ ; Words are evaluated as sub-rules in Red's Parse dialect, only ; lit-words are matched (against words and lit-words). Sub-blocks ; have similar issues. So if we get a word or a block, we'll find ; it the old-fashioned way. forall series [if series/1 = value [keep/only series]] ] 'else [ keep parse series [ collect [any [thru value pos: (keep back pos)]] ] ] ] ] ] e.g. [ find-all "abcadaedgcax" #"a" find-all [a b c a b c a b c] 'a find-all [a b c [a] b c a b c] [a] find-all [a b c [a] b c a b c] func [v][v = 'a] ; TBD paren! map! ]
\n
however I don't get it inside Red:Exception: KeyboardInterrupt() Output before exception: user> abcABC123 Makefile:337: recipe for target 'test^red^step0' failed make: *** [test^red^step0] Interrupt
self.stdin.write(_to_bytes(str + "\n"))
all instances
. For example, sometimes folks get wild with punctuation: hello!!!
#"^/"
in redbol ?lf
is #"^/"
for us (#"^J" works as well).[ <3 zeroes>]
?[not quote 0 skip 3 quote 0]
not
! Thanks @maximvl [not quote 0 number! 3 quote 0]
remove/part
if you want to remove more than one item at a time.help at
for more details.compose
?text >> compose [(1 + 1) (nay don't touch me)] *** Script Error: nay has no value *** Where: compose *** Stack:
quote
did the trick some time ago, but now it's not>> compose [(1 + 1) ([(nay don't touch me)])] == [2 (nay don't touch me)]
to-number
? ins: func [ "Increment a numerical string" s [string!]][ to-string (1 + to-integer s) ]
>> ins "123" == "124" >> ins "123123123123" *** Script Error: Content too long *** Where: to *** Stack: ins to-string to-integer
load
.hash!
is just a block + hashtable for fast lookups.hash!
hashes all it's values?find
can find a "value" with the same valueset
for a quick check if it has some valuefind
"mpg", then you find/reverse path!
. So in practice, it's a O(1) + O(n), but with a n < 6, so no noticeable performance overhead).find/reverse
also benefit from hashing?path!
?find path!
in such case to find the end of the list directly.find 'mpg
hash
instance, but such a search would require position to be a part of hasing or something'mpg
which is before the position>> h: make hash! [a 1 b a c] == make hash! [a 1 b a c] >> find h 'a == make hash! [a 1 b a c] >> find find h 1 'a == make hash! [a c]
hash!
, but IIRC, in such case, it does a lookup on first value, then jumps to next same value (thanks to quadratic probing), and checks if it's before the required position or after. So, it becomes a linear search across all occurences of the key, each lookup being done in constant time.hash!
supports hashing functions too:>> foo: does [1] bar: does [2] == func [][2] >> h: make hash! reduce [:foo :bar] == make hash! [func [][1] func [][2]] >> find h :bar == make hash! [func [][2]]
try [t: type?/word v: get w/1] if 'a = w/1 [ probe ">>" probe value? t probe get w/1 ]
">>" true *** Script Error: a has no value *** Where: get *** Stack: probe
t
keeps the value from the last iterationerror?
and it works now :)even?
word meaning something completely different and it will be false-positive for my testuse load
?+
blow up there?value
or block of valuesimage
that displays draw
content?[image 10x10 100x100 draw [...]]
use
macro, any thoughts?#macro ['use block!] func [s e /local locals][ locals: s/2 reduce [ make function! [ [locals [object!] body [block!]] [do bind body locals] ] make object! collect [ forall locals [keep to set-word! locals/1] keep none ] ] ]
altern
one-of-*
, but I don't think I've done that in a long time, as it's kind of leaking implementation details. Sometimes that's OK, and even desired, but not always.to-altern
will dotext >> to-altern: func [blk][next collect [forall blk [keep reduce ['| blk/1]]]] == func [blk][next collect [forall blk [keep reduce ['| blk/1]... >> to-altern [a b c] == [a | b | c]
; This could also be done by adding a /SKIP refinement to INSERT. delimit: func [ ;[throw catch] "Insert a delimiter between series values." series [series!] "(modified)" delim "The delimiter to insert between items" /skip "Treat the series as fixed size records" ; Overrides system/words/skip size [integer!] ;"The number of items between delimiters (default is 1)" ][ ; By default, delimiters go between each item. ; MAX catches zero and negative sizes. size: max 1 any [size 1] ; If we aren't going to insert any delimiters, return the series. if size + 1 > length? series [return series] ; We don't want a delimiter at the beginning. incr/by series size ; Use size+n because we're inserting a delimiter on each pass, ; and need to skip over that as well. If we're inserting a ; series into a string, we have to skip the length of that ; series. i.e. the delimiter value is more than a single item ; we need to skip. incr/by size any [ all [any-string? series series? delim length? delim] all [any-string? series length? form delim] 1 ] forskip series size [ insert/only series either series? delim [copy delim] [delim] ] series ] ; >> make-csv: func [block] [rejoin delimit copy block #","] ; >> make-csv ['name 'rank 'serial-number] ; == "name,rank,serial-number" ; ; >> make-parse-OR: func [block] [delimit copy block '|] ; >> make-parse-OR [yes no maybe] ; == [yes | no | maybe]
forskip
.forall
a special case of forskip
. Forall
is native in Red, though, and it hasn't come up in a while to prioritize.[1 .. 100]
/part
and /skip
refinements, so that a specific range type would not add much. Moreover, you can also use a pair!
value to represent a range if needed. I think a range!
could still be interesting as an additional literal form for dialecting though.1
s to represent on and off by toggling from one to zero?b: append/dup make block! 100 1 100
. Though, in such case you might want to use a bitset!
instead.lisp >> bits: make bitset! [1 - 100] == make bitset! #{7FFFFFFFFFFFFFFFFFFFFFFFF8} >> bits/1 == true >> bits/1: off == false
lisp >> bits: make bitset! [1 - 100] == make bitset! #{7FFFFFFFFFFFFFFFFFFFFFFFF8} >> repeat i 100 [poke bits i off] == false >> bits == make bitset! #{00000000000000000000000000}
bounds
and range
funcs which are dialected. It uses a bit of a hack, so you can use tuple!
values such as 1..100
, along with other forms. The trick doesn't work in Red, at this time, because it lexes as an int, where Rebol allowed it, and just set the second segment of the tuple! to 0. We can hack around it even more, using issues, if we want, but better to write up a REP to consider all possibilities.serie
dialect that can make block of values from ranges http://box.lebeda.ws/~rebolek/rebol/swymir.html>> string-1: "Hello " == "Hello " >> string-2: "world!" == "world!" >> rejoin [string-1 string-2] == "Hello world!"
>> repeat i 10000000 [append [] i] *** Internal Error: not enough memory *** Where: append *** Stack:
range 1 100
or range #"a" #"z"
?op!
?lisp >> list: make block! 10'000'000 == [] >> repeat i 10'000'000 [append list i] == [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ...
1 .. 100
as an op is possible, of course, but in a block it's a dialect. Bounds/range
is a single arity concept, yes? i.e., a range is a *thing*. So 1..100
, [1 .. 100]
, and [one to one-hundred]
all describe the same thing. face/selected: none
base
face and your own button images, or live with the default native colors.unless none? face/selected [ ... ]
if face/selected [ ... ]
;)none
is falsynone
on macOS, but I am not able to unselect with setting to either none
or -1
.view [below t: text "some text" font-color red button [t/font/color: reverse t/font/color]]
push = append ; Add element to tail pop = take/last ; Remove last element and return it shift = take ; Remove first element and return it unshift = insert ; Add element to head
shift/unshift
sounds particularily confusing, as you shift the array both when inserting or removing. parse
print x: "100000" loop length? next x [ parse x [ while [ ahead ["1" ahead [change "0" "1"]] | change "1" "0" skip ;@ why? | skip ] ] print x ]
100000 010000 001000 000100 000010 000001
skip
in second altern?print x: "100000" loop length? next x [ parse x [ some [ m: ["1" change "0" "1"] n: fail | :m [change "1" "0"] :n | skip ] ] print x ]
parse-trace x
show you?10
. I skipped part there it matched second zero and replaced it with 1
, after that parsing resumes from the start of the series:10 --> ... <snip> match: [["1" ahead [change "0" "1"]] | change "1" "0" ski input: "11" <-- match: [[ahead ["1" ahead [change "0" "1"]] | change "1" input: "11" --> match: [ahead ["1" ahead [change "0" "1"]] | change "1" " input: "11" --> --> match: ["1" ahead [change "0" "1"]] input: "11" ==> matched match: [ahead [change "0" "1"]] input: "1" --> --> match: [change "0" "1"] input: "1" --> ==> not matched <-- <-- <-- <-- <-- match: [| change "1" "0" skip | skip] input: "11" --> ==> matched <-- match: [change "1" "0" skip | skip] input: "1" ==> matched match: ["1" "0" skip | skip] input: "" <-- <-- return: true 01
skip
10 --> ... <snip> match: [["1" ahead [change "0" "1"]] | change "1" "0" | s input: "11" <-- match: [[ahead ["1" ahead [change "0" "1"]] | change "1" input: "11" --> match: [ahead ["1" ahead [change "0" "1"]] | change "1" " input: "11" --> --> match: ["1" ahead [change "0" "1"]] input: "11" ==> matched match: [ahead [change "0" "1"]] input: "1" --> --> match: [change "0" "1"] input: "1" --> ==> not matched <-- <-- <-- <-- <-- match: [| change "1" "0" | skip] input: "11" --> ==> matched <-- match: [change "1" "0" | skip] input: "1" <-- match: [[ahead ["1" ahead [change "0" "1"]] | change "1" input: "1" --> match: [ahead ["1" ahead [change "0" "1"]] | change "1" " input: "1" --> --> match: ["1" ahead [change "0" "1"]] input: "1" ==> matched match: [ahead [change "0" "1"]] input: "" --> --> match: [change "0" "1"] input: "" --> ==> not matched <-- <-- <-- <-- <-- match: [| change "1" "0" | skip] input: "1" --> ==> matched <-- match: [change "1" "0" | skip] input: "" <-- <-- return: true 00
match: [| change "1" "0" skip | skip] input: "11" --> ==> matched <-- match: [change "1" "0" skip | skip] input: "1" ==> matched match: ["1" "0" skip | skip] input: "" <-- <-- return: true 01
match: [| change "1" "0" | skip] input: "11" --> ==> matched <-- match: [change "1" "0" | skip] input: "1" <-- match: [[ahead ["1" ahead [change "0" "1"]] | change "1" input: "1" --> match: [ahead ["1" ahead [change "0" "1"]] | change "1" " input: "1" --> --> match: ["1" ahead [change "0" "1"]] input: "1" ==> matched match: [ahead [change "0" "1"]] input: "" --> --> match: [change "0" "1"] input: "" --> ==> not matched <-- <-- <-- <-- <-- match: [| change "1" "0" | skip] input: "1" --> ==> matched <-- match: [change "1" "0" | skip] input: "" <-- <-- return: true 00
change "1" "0" skip
matches first 1
in 11
and replaces it with 0
, leaving us with 01
as expected, while change "1" "0"
... well, I don't know what's really happening herechange "1" "0"
for 11
matches first 1
, replaces it with 0
, then does the same for the second 1
text change "1" "0" v 11<end> ahead "1" ... nope, backtrack v 01<end> change "1" "0" v 01<end> v 00<end>
behind
parse
stack directlyprint x: "111000000" loop length? next x [ parse x [ while [ ahead ["1" ahead [change "0" "1" e:]] | change "1" "0" if (not unset? :e) :e | skip ] ] print x ]
parse
, can I access matched **rule** instead of matched **input**? Or is it possible only with parse/trace
?match: "abc"
with rule ["a" "b" "c"]
, now, inside paren expression I can alter matched input by reffering to match:
position, but what if I want alter the matched rule (i.e. block with 3 elements) instead? text >> parse "abc" ["a" "b" "c"] == true >> parse "abc" ["a" "bc" none] == true >> parse "abc" [none "abc" none] == true
"abc"
["a" "b" "c"]
a block with 3 elements?matches: [ ["a" "bc" none] | ["a" "b" "c"] | [none "abc" none] | ; etc etc etc | skip ] parse "123abc" [some matches (<somehow get my hands on, say, ["a" "bc" none]>)]
matches
in advance, but I want to know which altern block is matched current input and access it's elementsparse/trace
callback for that. Another way, is to JIT-rewrite the rules to add extra logging.matches
and append to each altern some paren which will log something?parse/trace
too, though, I can't wrap my head on how to, ehm, "sync" together parsing and tracing>> x: [1 2 3] == [1 2 3] >> change/part x "..." skip x 2 == [3] >> head x == ["..." 3]
successors: #("-" "O" "O" "-") match: [ ["O" "-" none] | [none "O" none] ] print string: "O--------" loop length? next string [ parse/trace string [ to match while [ start: ahead match ( change find start matched-rule/2 select successors matched-rule/2 ) :start ] ] func [ event [word!] match? [logic!] rule [block!] input [series!] stack [block!] ;/local ctx ][ ctx: [string! | quote none] also yes all [ match? parse rule [ctx string! ctx] set 'matched-rule rule ] ] print string ]
O-------- -O------- --O------ ---O----- ----O---- -----O--- ------O-- -------O- --------O
/local ctx
, thing breaks*** Script Error: matched-rule has no value *** Where: find *** Stack:
parse
inside all
starts to return false
, as if ctx
rule fails, but WHY it starts to fail all of a sudden if it's not in global context?/local ctx
issue. Parse is not setting the Red stack properly for local words when calling the user-provided function.
parse
:
with to
with thru
knowing only
?back
?back
keyword in parse
and I'm not sure if changing index position outside parsing is a good ideaoffset
?some [ahead | skip]
should doto
always advances position in this casehas: make op! func [ {Searches for a value in block! Returns true and the index of the value if found.} block [block!] "Block of values" value [any-type!] "Value to check for" /local match ][ match: find block value either none? match [false][reduce [true index? match]] ]
-o
path, any tips?*** Linker Error: locked or unreachable file
>> parse ["a" "c"]["a" then | "b" | "c"] == false
>> parse ["a" "b"]["a" then "b" | "c"] == true >> parse ["a" "b"]["b" then "a" | "c"] == false >> parse ["b" "a"]["b" then "a" | "c"] == true
| ... |
then
is not correctly implemented in Red, there's a old ticket about that. I haven't fixed it, because I'm not sure it is worth keeping it. In Rebol3, I haven't seen it used in any Parse code. I find it hard to wrap your mind around it, though [the idiom it is supposed to replace](https://github.com/gchiu/rebol.net/blob/master/wikipedia/Parse%20Project.wiki#THEN) is pretty common in my own code. Maybe the name or the syntax are just not good enough.then
|
:confused:
matched, then use
. You can see how subtle/confusing it can be.a
and b
are dropped and match resumes from a
but with the next (if any) altern?>> parse "abc" ["a" "b" 'poop | to end] == true
>> parse "abc" ["a" "b" 'poop | z: to end] == true >> z == "abc"
fail
- go to next altern, backtrack
- discard paritally matched input and return to previous position>> parse "abc" [["b" then "c" | x: "a"] "b" then "c" | :unacceptable!] == true >> x == "abc"
find
is different?first find [a b c] 'b
find
already return either "true" (block) or "false" ('none')do
to force interpreter.find/deep
existen in rebol land, but never materialised IIRC. Maybe using a nested loop or using a parse
?parse
text >> find-5: [some [ahead block! into find-5 | quote 5 | skip]] == [some [ahead block! into find-5 | quote 5 | skip]] >> parse [1 2 3 4 [5 6]] find-5 == true
block?
text >> find-5: [some [ahead block! into find-5 | quote 5 | skip]] == [some [ahead block! into find-5 | quote 5 | skip]] >> parse [no five here] find-5 == true
find list "a"
for find index number?attempt [index? find list element]
Compiling /home/abdllh/Belgeler/ceviri/app.red ... *** Compilation Error: undefined word ask *** in file: /home/abdllh/Belgeler/ceviri/app.red *** near: [ask ">>"
view
UI with text fields for input/output>> find-5: [to [quote 5 then | into find-5] to end] == [to [quote 5 then | into find-5] to end] >> parse [1 2 3] find-5 == false >> parse [1 2 3 4 5] find-5 == true >> parse [1 [2 [3 [4 5]]]] find-5 == true >> parse [1 [2 [3 [4]]]] find-5 == false
[|]
) matches? find-5: [to [quote 5 | ahead block! into find-5] to end]
should be more robustsplit "abc abc b" " "
give ["abc" "abc" "" "" "b"]
- and need ["abc" "abc" "b"]
split
to better handle such situations. Meanwhile you need to remove empty values manually:>> collect [foreach value split "abc abc bc cd" space [unless empty? value [keep value]]] == ["abc" "abc" "bc" "cd"]
>> whitespace: charset reduce [space tab] == make bitset! #{0040000080} >> split "abc abc cde^-asdf" whitespace == ["abc" "abc" "cde" "asdf"]
/lines => Removes all line breaks and extra spaces.
Same as in Rebol.help trim
anyway, I can not remember which refinement is the right one for that behavior. ;-)parse "abc 192.168.10.1 dfg 123" [to ipv4 to end]
== true
. It OK. How use ipv4
now, just print for example? parse "abc 192.168.10.1 dfg 123" [to ipv4 (print WHAT) to end]
split
we did for R3, or do you not want to go that direction? I know it's a low priority, just wondering.split
is to broaden its scope, to cover also composed datatypes (pair!
, tuple!
, time!
, date!
, url!
, ...). So, maybe split
should become an action (in such case, the dlm
argument would become optional). The R3 version has a refinement for "splitting into n pieces". I'm not sure what are the practical use cases for that option?>> split "pumpkin" #"k" == ["pump" "in"]
>> split "pumpkin" 5 == ["pump" "in"]
["pumpk" "in"]
if split at 5split "one,two,three" #","
, but they might be expecting all elements to be returned if they split at a positionipv4
try find it in log file (read strings) and print it. Input for parse - string, not block.parse "abc 192.168.10.1 dfg 123" [some [copy ip-found ipv4 (print ip-found) | skip]]
k
letter in the result.split-at
func I've historically used for that. I might have had a version of split
with an /at
refinement, but can't locate it right now."cat" = reverse "cat"
>> "cat" = reverse "cat" == false >> p: func [val] [val = reverse val] == func [val][val = reverse val] >> p "cat" == true
reverse COPY val
Red for Windows version 0.6.3 built 22-Sep-2017/10:24:08-06:00 >> trim/all/lines "Hello World!" == "HelloWorld!" >> trim/all/lines/with "Hello World!" "!" == "Hello World" >> trim/all/lines "Hello World!" == "HelloWorld" >> trim/all/lines "Hello World..." == "HelloWorld..." >> trim/all/lines/with "Hello World..." "..." == "Hello World" >> trim/all/lines "Hello World..." == "HelloWorld"
-t RPi
option.with
](https://doc.red-lang.org/en/vid.html#_with) keyword, please.text >> params: [color: red text: "some text"] == [color: red text: "some text"] >> view [text with params]
>> params: [color: red text: "some text"] == [color: red text: "some text"] >> view [text with params] *** Script Error: VID - invalid syntax at: [with params] *** Where: do *** Stack: view layout cause-error
view [do [self/menu: ["Whatever" menu]]]
foreach
that advances the index pointer?forall
Forall
break
when using it. e.g.>> blk == [1 2 3] >> forall blk [either 2 = index? blk [break][print blk]] 1 2 3 >> blk == [2 3]
forall [i j] [1 2 3 4 5 5...]
forskip
, but it's not decided if that will make it into official Red. foreach
, because you have to give it a reference to the series, not both iterator words and the series.forall
requires word bounded to seriesword = next word
?word/1 = word/2
comment { Split a character string based on change of character. For instance, the string: gHHH5YY++///\ should be split and show: g, HHH, 5, YY, ++, ///, \ } split-at-change: func [str [string!]][ "Split a character string based on change of character" str: copy str forall str [if not-equal? str/1 str/2 [str: insert next str ", "]] str ]
text >> parse "gHHH5YY++///\" [collect some [ahead [set x skip] keep some x]] == [#"g" "HHH" #"5" "YY" "++" "///" #"\"]
,
in the proper places except for the "5YY" sectiontext >> split-at-change "5YY" == "5, YY, " >> split-at-change "5YY!" == "5, YY, !" >> split-at-change "5YY!!" == "5, YY, !!, " >> split-at-change "!5YY!" == "!, 5YY, !"
also
also str: copy str forall str [...]
g, HHH,
etctext >> rejoin next parse "gHHH5YY++///\" [collect some [ahead [set x skip] keep (", ") keep some x]] == "g, HHH, 5, YY, ++, ///, \"
map!
by values?func some[txt][ foreach a txt [ while [...] [ if ... [break] ] ] ] *** Throw Error: no loop to break *** Where: break
otplib.red
by line 109 there is a break
throwing error if there is some character not present in the text, for example a comma when there is all lowercase raises the error.db: ["192.168.1.1" 100 "192.168.1.4" 50 192.168.1.2" 70]
. And how I can print this block sorted by value (100 50 70)?>> db: ["192.168.1.1" 70 "192.168.1.4" 100 "192.168.1.2" 50] == ["192.168.1.1" 70 "192.168.1.4" 100 "192.168.1.2" 50] >> sort/skip/compare db 2 2 == ["192.168.1.2" 50 "192.168.1.1" 70 "192.168.1.4" 100]
map!
and block!
- and same algorithm. With block!
worse ~2x times then map!
:(map
. Worse on read access? Try to convert block!
to map!
after sorting. Worse on write access? Use hash!
instead of block.text >> hash: make hash! ["192.168.1.1" 70 "192.168.1.4" 100 "192.168.1.2" 50] == make hash! ["192.168.1.1" 70 "192.168.1.4" 100 "192.168.1.2" 50] >> map: make map! ["192.168.1.1" 70 "192.168.1.4" 100 "192.168.1.2" 50] == #( "192.168.1.1" 70 "192.168.1.4" 100 "192.168.1.2" 50 )
hash!
is the way to go, as it both sortable and have fast read accessNewLine + Hole
defined, we can extract just that func to test it.split-at-change: func [ "Split a character string based on change of character" str [string!] ][ str: copy str forall str [ print [newline {We are at } str] print [newline {testing positions: } str/1 space str/2] if not-equal? str/1 str/2 [ print [newline {Inserting ", "} space next str] str: insert next str ", " ] ] str ] split-at-change "gHHH5YY++///\"
testing positions 5 Y
never happenseffect
support is missing in red.. still a nice example of what could be possible in the future..OtpText
contains only lowercase letters and ClrText
contains some character not present in ClrText
such a decimal point. CodeInd
reaches CodeMax
in while
loop and then break
raises the error.split-at-change: func [ "Split a character string based on change of character" str [string!] ][ str: copy str forall str [ if all [str/1 <> str/2 str/2 <> none][str: back insert next str ", "] ] str ]
text split-at-change: func [ "Split a character string based on change of character" str [string!] ][ also str: copy str forall str [ all [str/1 <> str/2 str/2 str: back insert next str ", "] ] ]
lisp split-at-change: func [ "Split a character string based on change of character" str [string!] ][ parse str [some [ahead [set x skip] some x [end | insert ", "]]] str ]
parse
to return the input series in general rules, when desired...parse-kido
sounds great. We should use those martial arts-ish titles for some docs ;-)react
](https://en.wikipedia.org/wiki/Bataireacht) is applicable here layout
](https://en.wikipedia.org/wiki/Silat_Melayu) and [voview
nam](https://en.wikipedia.org/wiki/Vovinam) :shipit: func
might be the cause - all of your words are exposed into global context>> first parse "gHHH5YY++///\" [collect keep some [ahead [set x skip] some x [end | insert ", "]]] == "g, HHH, 5, YY, ++, ///, \"
parse/return
? (for I really need to add a way for
parse to return the input series in general rules, when desired...
)>> regex/parse/g/replace "((.)*)" str: "gHHH5YY++///\" "\1, " head remove/part back back tail str 2 == "g, HHH, 5, YY, ++, ///, \"
Compiling to native code... *** Compilation Error: undefined symbol: red/vector/rs-head *** in file: %/home/spt/red/sum-bench.red *** in function: exec/do-count2 *** at line: 332 *** near: [vector/rs-head v1 p2: as pointer! [integer!] vector/rs-head v2 ]
*** Internal Error: routines require compilation, from OS shell: `red -c <script.red>`
time-it: func
almost what needed. Tnx.[| "a"]
) matches/behaves in parse
?ahead
keyword - match *forward* but don't change series index; to @dockimbel - what are your thoughts on behind
keyword, i.e. match *backward* but don't advance the input? For example ["b" ahead "c" behind "a"]
will match b
preceded with a
and with followed c
. I'm not sure if this is useful though, because ["a" "b" ahead "c"]
will have roughly the same effect. [x behind y]
is "match x
only if previously you've matched y
. Perhaps there's some existent parse
idiom for that?-r
now instead of -c
. I'm pushing a fix for it.Red [needs: 'view] txt: "43" upd1: func [][txt: "100"] view [ button "Update" [upd1] text react [face/text: txt] ]
txt
series to face/text
and then just update that same series. An example using the latter approach could be:txt: "43" upd1: func [][change txt "100"] view [ button "Update" [upd1] text txt ]
text txt
, and can't text blk/1
, where blk: block!
with valuescompose
the block dynamically or use the data
option as workaround: text data blk/1
.return
value unassigned in call to func, so strange!>> (1 + 3) = (2 + 2) = 4 == false
(1 + 3) = (2 + 2)
evaluates to true
and this is not equal to 4
, but how to evaluate this equation to get an intuitively true answer? str: "aeiouaeiou"
remove-each [first-ch] str [first-ch = #"a"]
remove-each [first-ch second-ch] str [first-ch = #"a" second-ch = #"i"]
> remove-each l "abcbdrbf" [l = #"b"] >> remove-each l str: "abcbdrbf" [l = #"b"] str == "acdrf"
parse str [some [to ["b" | "f"] mark: (remove mark)]]
view [ text-list data ["Monday" "Tuesday" "Wednesday"] on-change [remove at face/data face/selected] ]
on-change
in all cases, depending on the current selection. But with that basic idea, you can use on-down/on-up
and the selected
facets to experiment and post your results here.read
with the /lines
refinement, and write
as well. i.e., read/lines, remove the item in the block, write/lines.>> b: [1 * 2 1 + 1 2] == [1 * 2 1 + 1 2] >> forall b [print b] 2 2 2 *** Script Error: * operator is missing an argument *** Where: print *** Stack: >> b == [* 2 1 + 1 2]
probe
doesn't affect itforall b [print first b]
is fineprint
evaluates b
, you get 2 2 2
, then forall
moves position up to *
, and print
evaluates [* 2 1 + 1 2]
, chokes (because *
now is missing left argument), forall
breaks because of error and left series at current position (i.e. [* 2 1 + 1 2]
) without reseting back to head.text-list
widget to make such task simple. I'm having a look at it to see if it can be quickly implemented.>> b: [2 * 1 1 + 1 2] == [2 * 1 1 + 1 2] >> print b 2 2 2 >> b: next b == [* 1 1 + 1 2] >> print head b 2 2 2 >> print b *** Script Error: * operator is missing an argument
block!
?blk: ["23" "43"] upd1: func [][change blk ["100" "100"]] view [ button "Update" [upd1] text data blk/1 text data blk/2 ]
blk
is not a reactive sourcer: make deep-reactor! [blk: ["23" "34"]] upd: does [change r/blk ["100" "200"]] view [ button "update" [upd] t1: text react [t1/data: r/blk/1] t2: text react [t2/data: r/blk/2] ]
txt: "43" upd1: func [][change txt "100"] view [ button "Update" [upd1] text txt ]
txt
- reactive source, blk
- not reactive? This by disign?blk: ["23" "43"] upd1: does [ append clear blk ["100" "200"] tx1/data: blk/1 tx2/data: blk/2 ] view [ button "Update" [upd1] tx1: text data blk/1 tx2: text data blk/2 ]
txt
isn't reactive source either, text facet isview [ text-list data ["Monday" "Tuesday" "Wednesday"] on-down [remove at face/data event/picked] ]
event/picked
will accurately return the item index under the mouse cursor, regardless of its selection state.none
load
from http. What missing? Any windows dll?parse
will [just jump](https://github.com/red/red/blob/master/runtime/parse.reds#L1463) at the end of the current rule block.do %file
instead and %file
contains do
ing or load
ing of url!
output: make string! 1000 print-str: func third :print [ repend output [reform :value newline] ] The name of the argument used for print-str is obtained from the interface specification for print. You can examine that specification with: probe third :print [ "Outputs a value followed by a line break." value "The value to print" ]
*-of
reflectors.>> ? -of body-of function! Returns the body of a value that supports reflection. class-of function! Returns the class ID of an object. keys-of function! Returns the list of words of a value that supports reflection. spec-of function! Returns the spec of a value that supports reflection. values-of function! Returns the list of values of a value that supports reflection. words-of function! Returns the list of words of a value that supports reflection.
unless any
or if not any
?size: 50 if any [size < 10 size > 90] [ print "Size is out of range." ]
size
is less than 10 or bigger than 90 it is out of range.between?: func [low high num][and~ low <= num num <= high] >> between? 1 5 0 == false >> between? 1 5 5 == true >> between? #"a" #"d" #"c" == true >> between? #"a" #"d" #"e" == false
text *** Script Error: PARSE - COLLECT INTO/AFTER expects a series! argument *** Where: parse *** Stack:
after
, any tips?>> l: charset [#"a" - #"z"] == make bitset! #{0000000000000000000000007FFFFFE0} >> parse "abc" [some l] == true >> parse "ABC" [some l] == false
parse
is case-insensitive by default, second example would matchl: charset [#"a" - #"z" #"A" - #"Z"]
load
the file in the console. That is your first clue.split
ting, float numbers load
ing, summation and finding mean values. Red was *painfully* slow, and I don't know what might be the cause - no optimisations, my bad code, or both? What would you suggest?load
implementation is written using Parse and Red code. We need an alternative low-level R/S implementation for use-cases where high-performance is required.parse
, only using load
trim
and etc :D and yeah, in my experience load
slowed things down significantlyforall file [ line: split first file #";" time: load first line append select stages to-stage time mean next line print to percent! divide index? file to float! size ]
mean
itself heavily relies on load
sum: function [series][s: 0 forall series [s: s + series/1]] mean: function [band-powers][ n-of-waves: 05 n-of-channels: 14 collect [ repeat i n-of-waves [ channel: load form extract/index band-powers n-of-waves i keep/only (sum channel) / n-of-channels ] ] ]
split
in Red - near same result.Red [] digit: charset "1234567890" four: charset "01234" half: charset "012345" non-zero: charset "123456789" ws-cs: charset reduce [space tab cr lf] chars: charset reduce ['not space tab cr lf] ws: [some ws-cs] word: [some chars] num: [some digit] time-epoch: [10 digit] byte: ["25" half | "2" four digit | "1" digit digit | non-zero digit | digit] ipv4: [byte dot byte dot byte dot byte] time-line: resp-line: bytes-line: integer! ip-line: none file: read/lines %access.log ip-user: #() foreach line file [ parse line [time-epoch dot 3 digit ws num ws copy ip-line ipv4 ws word ws copy bytes-line num to end ] bytes-line: to-integer bytes-line either (find ip-user ip-line)[ ip-user/:ip-line: ip-user/:ip-line + bytes-line][ ip-user/:ip-line: bytes-line] ] probe ip-user
read/lines %access.log
and also read %access.log
?time-line: resp-line: bytes-line: integer!
bytes-line: to-integer bytes-line
parse
work on interpreter. In future it will be compiled in native? Or this architectural constraint?parse ... [change tab #";" | skip]
takes forever on my 355k pile, in Python it's 3-5 seconds :([some [change tab #";" | skip]]
, and "forever" as in "I already processed 14 such files in Python and Red didn't finished with the first one"[some [to tab change tab #";" | end]]
x: 3
happen first here?(x: 3) + 2
x: add 3 2
?x: add 3 2
is exactly x:
then add
is a function which is being called and it needs two arguments which are 2
and 3
3 + 2
?x: add
is not validx: 3
is3 + 2
is a valid expression, just like add 3 2
, it is evaluated and x
is set to the result of evaluationx: add 2 3
is parsed by tokens, x:
is set-word, then you need a value, add
is a function so you know that to get a value you need to execute it with 2 arguments, you read 2
, 3
and you are done+
and everything is freaked upop!
? :Dop!
follows your value, jeezparse
is there a way to match rule certain number of times but not set as a constant but Red expression?op!
and function!
(any-function!
?), and inserting parens as you gotext view/no-wait [b: box red on-time [b/color: random/only reduce [red blue green]] do [b/rate: 00:00:01]]
view/no-wait [b: box white on-time [colors: [red blue green cyan yellow magenta black] b/color: reduce take colors] do [b/rate: 00:00:01]]
b/color
manually on each program stageview/no-wait [b: box red ] do [b/rate: 00:00:0.1] b/color: blue read http://red-lang.org b/color: green
unview view/no-wait [b: box red ] do [b/rate: 00:00:0.1] b/color: blue set-focus b read http://red-lang.org b/color: green>
blue
and green
is milliseconds, box will instantly change its color to green so you won't notice bluerate
is helpful here thoughunview view/no-wait [b: box red ] do [b/rate: 00:00:0.1] b/color: blue repeat n 10 [read http://red-lang.org ] b/color: green
system/view/auto-sync?
word: if set to yes
, the realtime updating mode is on (default mode), if set to no
, View engine will defer all updates.system/view/auto-sync?: off
on a first line of your script and use show b
after each updatedo-events/no-wait
to make things like this work, the standard approach is to work inside the event loop, as @9214 showed.view [b: box red rate 0:0:1 on-time [b/color: random white]]
states: [ 1 red 2 blue 3 green ] state: 1 view [b: box red rate 0:0:1 on-time [ if state < 3 [ state: state + 1 b/color: get select states state] ] ]
delta-profile
?expr: [term copy op ["+" | "-"](print op) expr | term] term: [factor ["*" | "/"] term | factor] factor: [primary "**" factor | primary] primary: [copy number some digit (print number) | "(" expr ")"] digit: charset "0123456789" print parse "1+2" expr ;-- prints 1 1 1 1 + 2 2 2 2 2 2 2 2 true
lisp >> parse "a" ["b" (print "?") | "a"] == true
primary
rule (containing the number matching sub-rules) is called in both alternatives of factor
rule, which itself is pretty deeply nested in the rules hierarchy. The consequence is that the expanded expr
root rule will result in a tree of rules where primary
will be called in many places, resulting in many matching (but failing some ancestor rule). You can draw such tree manually on paper if you need to better visualize it.view
is written from scratchdraw
is just a language, if something is not possible you can always add a keyword or twodraw
to SVG compiler?C:/Users/davidan/scoop/shims/red.exe c:\Users\davidan\OneDrive\dev\red\hello.red
system/script
, but it's not really populated with anythingRed [ Title: "hello world" ] header: second load system/options/script print header/Title
lisp #!/usr/local/bin/red Red [ Title: "Hello World!" ] header: select/same load system/options/script 'Red
do
if you have a preamble visible?
facet instead["v" x y z]( x y z are float!) to a text file but haven't had much success. Is there any way to just 'print' into 'write' ?
reduce
block before writingrepeat x 4[ write/append %testfile.txt reduce a/:x write/append %testfile.txt " " ]but the result was
v 2 3 4
text >> x: 1.5 == 1.5 >> y: 2.7 == 2.7 >> z: 3.6 == 3.6 >> write %test form reduce ["v" x y z] >> read %test == "v 1.5 2.7 3.6"
save/load
:save %test reduce ["v" x y z] load %test
do
:Here is some text before the script. [ Red [ Title: "Embedded Example" Date: 8-Nov-1777 ] print "done" ] Here is some text after the script.
do
is used:*** Syntax Error: invalid value at "]Here is some text after the script." *** Where: do *** Stack: do-file expand-directives load
load
and what to skip?load
a preface script with commas - even though there is a preface script example in the guide with commasRebol
header and ignores everything before it.load find script "Rebol"
load
ed, though it should not** Syntax Error: Invalid word -- comments, ** Near: (line 2) by REBOL and can be used for comments, email headers,
load/header
is for that?do
on a text file with any file extension and it will run - as long as the proper Red []
header and Red code is in the filequote: ["^"" | "'"] string: [quote thru quote] probe parse {"string" 1 2 3 'another string'} [ collect some [keep string | skip] ]
[{"string"} "'another string'"]
>> parse {<html><div style="margin: 8pt;">Some 'plain or "not so plain"' text.</div></html>} [ collect any [ #"^"" keep to #"^"" skip | #"'" keep to #"'" skip | skip ] ] == ["margin: 8pt;" {plain or "not so plain"}]
text quote*: ["^"" | "'"] string: [set match quote* thru match] tags: {<html><div style="margin: 8pt;">Some 'plain or "not so plain"' text.</div></html>} probe parse tags [collect any [keep string | skip]]
[{"margin: 8pt;"} {'plain or "not so plain"'}]
tags: {<html><div style="margin: 8pt;">Some 'plain or "not so plain"' text.</div></html>} probe parse tags [ collect any [ [set match ["^"" | "'"] keep to match skip] | skip ] ]
["margin: 8pt;" {plain or "not so plain"}]
quote*: ["^"" | "'"] string: [set match quote* thru match] tags: {<html><div style="margin: 8pt;">Some 'plain or "not so plain"' text.</div></html>} >> compare-times/count [[parse tags [collect any [keep string | skip]]][parse tags [collect any [#"^"" keep to #"^"" skip | #"'" keep to #"'" skip | skip]]]] 100000 Time | Memory | Code 0:00:01.959 | 25571328 | [parse tags [collect any [#"^"" keep to #"^"" skip | #"'" keep to #"'" skip | skip]]] 0:00:04.107 | 33767424 | [parse tags [collect any [keep string | skip]]]
strings: copy [] parse text [ some [ {"} copy str to {"} skip (append strings str) | {'} copy str to {'} skip (append strings str) | skip ] ]
parse
only?parse
but also in general would be fine. collect
evaluates its body and, well, collects all of the values passed to keep
(or collected
) functionrepeat
and other loops to get the general ideastrings: copy [] parse text [ collect after strings some [ {"} keep to {"} skip | {'} keep to {'} skip | skip ] ] head strings
text probe parse "and he said: 'oh no, that\'s bad!'" [ collect any [ {"} keep to [not "\" skip {"}] | {'} keep to [not "\" skip {'}] | skip ] ]
["oh no, that\'s bad"]
tags: {<html><div style="margin: 8pt;">Some 'plain or "not so plain"' text, here's a common edge-case, 'ok'?</div></html>}
comma
first and lately replaced with quote
without checkingquote
is already defined, but because quote
is a parse
keywordcollect/into
- Red function or collect into
parse
keywords?text >> my-collected-numbers: next [>> <<] == [<<] >> parse [1 a 2 b 3 c 4 d][collect into my-collected-numbers some [keep integer! | skip]] == true >> head my-collected-numbers == [>> 1 2 3 4 <<]
>> obj1: make object! [a: 1] == make object! [ a: 1 ] >> obj2: make object! [b: 2] == make object! [ b: 2 ]
>> obj3 == make object! [ a: 1 b: 2 ]
>> obj2: make object! [a: 2 b: 3] == make object! [ a: 2 b: 3 ] >> obj3: make obj1 obj2 == make object! [ a: 2 b: 3 ] >> obj3: make obj2 obj1 == make object! [ a: 1 b: 3 ]
strings: copy [] parse text [ some [ {"} copy str to {"} skip (append strings str) | {'} copy str to {<} skip (append strings str) | {'} copy str to {'} skip (append strings str) | skip ] ]
text >> ? "reflect" body-of function! Returns the body of a value that supports r... keys-of function! Returns the list of words of a value that s... reflect action! Returns internal details about a value via ... spec-of function! Returns the spec of a value that supports r... values-of function! Returns the list of values of a value that ... words-of function! Returns the list of words of a value that s...
on-deep-change*
bind
? you just need to define itsystem/words
though{Some 'plain or "not so plain"' text, here's a common edge-case, 'ok'?}
with the same problem.strings: copy [] non-alpha: complement charset [#"a" - #"z" #"A" - #"Z"] parse text [ some [ non-alpha {"} copy str to {"} skip (append strings str) | non-alpha {'} copy str to {'} skip (append strings str) | skip ] ]
>> out: copy "" repeat i length? non-alpha [if non-alpha/:i [append out to-char i]] out == {^A^B^C^D^E^F^G^H^-^/^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^(1E)^_ !"#$%&'()*+,-./0123456789:;<=>?@[\]^^_`{|}~^~}
uppercase
and lowercase
either directly on bitsets or inside charset
dialect?collect/into [repeat i length? non-alpha [if non-alpha/:i [keep to-char i]]] copy "" rejoin collect [repeat i length? non-alpha [if non-alpha/:i [keep to-char i]]]
str: "abcdabcd"
>> replace skip find str "b" 1 "b" "xx" == "cdaxxcd" >> str == "abcdaxxcd"
change/part find/last str "b" "xx" 1
change/part at str 6 "xx" 1
Red [Needs: 'View] state: make reactor! [ text: "Helo" ] view [ panel react [ face/pane: layout/tight/only compose [text (state/text)] ] ]
*** Internal Error: stack overflow *** Where: layout *** Stack: view layout react layout react layout react layout react layout react layout >>
react
- it reacts on text
change, then reacts on reaction, then reacts on reaction... :boom: >> text: "my brand new, programmatically built text!" == "my brand new, programmatically built text!" >> view compose [panel (text)]
state: make reactor! [ today: now/date ] build-month: function [day [date!] /returns [block!]] [ month: [] ; ... calculate days of the month... while [day/isoweek <= last/isoweek] [ month: append month compose [button (to-string day/day)] day: day + 1 ] month ] view [ button ">" [ state/today: 2017-11-15 ] return ; fixed date for testing/prototyping panel 7 react [ face/pane: layout/only build-month state/today ] ; something 7 - to keep 7 in a row ]
text title-of: func [site [url!]][ first parse read site [collect [thru "<title>" keep to "</title>"]] ]
panel
requires a tree of faces, that's why you're using layout/only
, tried to re-create your example and got stack overflow tooxml "title" http://red-lang.org
>> page: read http://red-lang.org == {<!DOCTYPE html>^/<html class='v2' dir='ltr' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns: >> out: xml/decode page == [html [head [link none #( "href" {https://www.blogger.com/static/v1/widgets/3213516723-css_bundle_v2.css} "rel" "styleshe... >> out/html/head/title == [none "Red Programming Language" #()]
>> help poke USAGE: POKE series index value DESCRIPTION: Replaces the series value at a given index, and returns the new value. POKE is an action! value. ARGUMENTS: series [series! bitset!] index [scalar! any-string! any-word! block! logic!] value [any-type!] RETURNS: [series! bitset!]
>> blk: [a b c] == [a b c] >> poke blk 3 'test == test >> blk == [a b test] >> poke blk 3 #(a: 1 b: 2) == #( a: 1 b: 2 ) >> blk == [a b #( a: 1 b: 2 )]
any-type
any-type
means that poke
function can accept argument of any-type
, not that you can stick anything in anything>> poke "cat" 3 "!" *** Script Error: invalid argument: "!" *** Where: poke *** Stack:
g
in leetspeak anyway)add
on char values, but you can't add all of the types add
supports equally across datatypes.42
of courseadd
needs to support all types in its interface for any of its target datatypes. '!
to char!
but now without a blink of an eye use to-integer
casting..?seconds
, as with time?now/date + to-integer #"a"
poke
tried to poke some *exact* value of *exact* datatype into some *exact* series?poke
action from the series! type, which just throws the generic invalid arg
error. It could just throw a more specific error there. Maybe not practical. Not sure if it's worth adding to the standard error catalog.action!
type-mismatch
error that might be at least a little more informative.not-related
error is meant for that.newcomer-confusion
"true or false for bitset"
"only number! for vector"
"only integer! for binary"
poke
example, why would newbie be confused? Why you were confused in a first place?char!
values and that, as I already said, poke
does what it does precisely - inserts **value** that series support into this seriesDESCRIPTION: Replaces the series value at a given index, and returns the new value. POKE is an action! value.
series!
support another string as its value?aaaaaaaa
can contain only two values, aaaa
and aaaa
, or one value aaaaaaaa
, or million empty strings and aaaaaaaa
at the end, or maybe, just maybe, 4 aa
'spoke
ing some number of **values** in place of one **value**aaaaaaaa
what values are in there without additional information about indexes and elementsa
is first, aa
is second, aaa
is third,
is forth, aa
is fifth", then task is trivial["a" "aa" "aaa" "" "aa"]
?poke
whatever you want in this block, because there's no restrictions on values that it can support??
what you're looking for?>> x: 'this == this >> ?? x x: this >> ?? (in ctx 'x) x: that >> ?? ?? ??: func [ "Prints a word and the value it refers to (molded)" 'value [word! path!] ][ prin mold :value prin ": " print either value? :value [mold get/any :value] ["unset!"] ] >> ?? ctx/x ctx/x: that
data: [[1 2] [3 4] [4 5]]
foreach item data [ print item]
foreach
, unless you want to always skip in increments by using a block of words. In this case, you could print item 1, then use foreach item at data 3 [...]
. You could also use forall
, where you can check the index of the item for things to ignore.forall data [unless equal? (index? data) 2 [do stuff...]]
forall data [if odd? index? data [print first data]]
switch
?forall data [ switch index? data [ 1 [print add data/1/1 data/1/2] 2 [print "I could do nothing..."] 3 [print data] ] ]
copy
ied block before iteratingimage!
or some kind of animation in Red?pair!
works:>> parse [1x2] [pair!] == true
value
into which values are inserted according to instructions. When bot has 2 values it gives these over to either another bot or to output, again according to parsed instructions. Expected routs are following:data: [ bot 2 gives low to bot 1 and high to bot 0 bot 1 gives low to output 1 and high to bot 0 bot 0 gives low to output 2 and high to output 0 value 5 goes to bot 2 value 2 goes to bot 2 value 3 goes to bot 1 ] bot: make map! 3 output: make map! 3 initial: copy [] make-bot: func [nr recipient1 low recipient2 high][ bot/:nr: make deep-reactor! compose/deep [ myself: (nr) value: make block! 2 gives: is [ if 2 = length? value [ sort value probe reduce [myself 'has value] either 'bot = (to-lit-word recipient1) compose/deep [ print [(nr) " gives " first value " to " 'bot (low)] insert select select bot (low) 'value take value ] compose/deep [ print [(nr) " puts " first value " to " 'output (low)] put output (low) take value ] either 'bot = (to-lit-word recipient2) compose/deep [ print [(nr) " gives " first value " to " 'bot (high)] insert select select bot (high) 'value take value ] compose/deep [ print [(nr) " puts " first value " to " 'output (high)] put output (high) take value ] ] ] ] ] parse data [some [ 'bot set minion integer! 'gives 'low 'to set low-recipient ['bot | 'output] set low integer! 'and 'high 'to set high-recipient ['bot | 'output] set high integer! ( make-bot minion low-recipient low high-recipient high ) | 'value set value integer! 'goes 'to 'bot set minion integer! ( insert initial reduce [value minion] ) ]] foreach [value minion] initial [ insert bot/:minion/value value ]
[2 has [2 5]] 2 gives 2 to bot 1 2 gives 5 to bot 0 [1 has [2 3]] 1 puts 2 to output 1 1 gives 3 to bot 0 == []
>> probe bot #( 2 make object! [ myself: 2 value: [] gives: none ] 1 make object! [ myself: 1 value: [] gives: [5] ] 0 make object! [ myself: 0 value: [3 5] gives: none ] )
foreach
?foreach
is still running? (idk if this is possible though, I love to theorize :D)output
. I tried with longer data and program stops after first putting value to output
. But why doesn't bot who recieved two values react after that?put
commented out[2 has [2 5]] 2 gives 2 to bot 1 [1 has [2 3]] 1 puts 2 to output 1 1 gives 3 to bot 0 2 gives 5 to bot 0 [0 has [3 5]] 0 puts 3 to output 2 0 puts 5 to output 0
react? bot/0 'value
that reaction is registered. As I try react?
now, it responds with ==none
, but reaction works . Beats me. :astonished:dump-reactions
give any info :exclamation::question: But it works :yum: curry: function [f [any-function!] x][ function [y] reduce [:f x 'y] ]
where
function a bunch lately, but it only works with predicates that take a single argumentwhere: function [block pred][ collect [foreach i block [if pred i [keep/only i]]] ]
curry
is forwhere
func. Including this:keep-each: func [ "Keeps only values from a series where body block returns TRUE." 'word [get-word! word! block!] "Word or block of words to set each time (will be local)" data [series!] body [block!] "Block to evaluate; return TRUE to collect" ][ remove-each :word data compose [not do (body)] data ] e.g. [ filter: :keep-each filter x [1 2 3] [x = 2] filter x [1 2 3] [odd? x] filter res [1 2 3] [odd? res] filter [x y] [a 1 b 2 c 3] [all [odd? y 'c = x]] filter x [(1 2) (2 3) (3 4)] [x = first [(2 3)]] ]
filter
: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" ; Getting only the things that don't pass a test means applying NOT ; to the test and using /ONLY. Applying NOT means making a lambda. ; Not hard, for people who understand anonymous funcs. ;/pass "Return a single block of values that pass the test" ;/fail "Return a single block of values that fail the test" ][ ;TBD: Is it worth optimizing to avoid collecting values we won't need to return? result: reduce [copy [] copy []] foreach value series [ append/only pick result make logic! test :value :value ] either only [result/1][result] ]
has-bab?
takes an 'ip' string, and 'aba' string and returns a logic!
indicating whether it contains the 'bab' sequence in the correct spot, get-abas
finds all the 'aba' sequences)probe length? where inputs function [ip][ ip-has-bab?: curry :has-bab? ip positive? length? where get-abas ip :ip-has-bab? ]
text >> mylist: [[10 20][25 30]] == [[10 20] [25 30]] >> poke mylist/1 1 100 == 100 >> mylist == [[100 20] [25 30]] >> poke mylist/1 2 100 == 100 >> mylist == [[100 100] [25 30]]
>> mylist: [[10 20][25 30]] == [[10 20] [25 30]] >> mylist/1/1: 100 == 100 >> mylist == [[100 20] [25 30]] >> mylist/1/2: 100 == 100 >> mylist == [[100 100] [25 30]]
exclude
works on simple value comparisons in the datasets. It has no concept of geometry. intersect
to find the points where they intersect. Now, this is not foolproof for any 2 circles, as rendering and rounding may mean more than 2 values intersect. Still, this is an exercise in thinking. Now you have 2 points from each circle. Assuming your values are in order, you can find the subset (segment) of values in each circle, using those 2 points as start/end markers. Now you have a list of points from each circle, denoting the arc from each.save
?read rejoin [https://cex.io/eth- 'BTC]
'BTC = "BTC"
?<HTML> <TITLE>Simple Web Form</TITLE> <BODY> <b>Simple Web Form</b><p> <FORM ACTION="/cgi-bin/test2" method="post"> <INPUT TYPE="TEXT" NAME="Field" SIZE="25"><BR> <INPUT TYPE="SUBMIT" NAME="Submit" VALUE="Submit"> </FORM> </BODY> </HTML>
Red[] headers!: context [ server-software: none server-name: none gateway-interface: none server-protocol: none server-port: none request-method: none path-info: none path-translated: none script-name: none query-string: none remote-host: none remote-addr: none auth-type: none remote-user: none remote-ident: none content-type: none content-length: none user-agent: none other-headers: none ] parse-headers: func [query] [ headers: make headers! [] raw: make map! 50 key: value: none parse query [ some [ copy key to #"=" skip copy value to newline skip (raw/:key: value) ] ] foreach [cgi-key red-key] [ "HTTP_HOST" remote-host "HTTP_USER_AGENT" user-agent "SERVER_SOFTWARE" server-software "SERVER_NAME" server-name "SERVER_PORT" server-port "REMOTE_ADDR" remote-addr "SCRIPT_FILENAME" script-name "GATEWAY_INTERFACE" gateway-interface "SERVER_PROTOCOL" server-protocol "REQUEST_METHOD" request-method "QUERY_STRING" query-string "CONTENT_TYPE" Content-Type ] [ headers/:red-key: raw/:cgi-key raw/:cgi-key: none ] headers/other-headers: raw headers ] get-headers: func [/local o] [ call/wait/output "printenv" o: "" http-headers: parse-headers o ] get-headers print "Content-type: text/html^/" print rejoin ["Hello world from Red " system/version] print get-headers print "<BR><BR>Content-type: text/html^/" print rejoin ["Post data: " mold input]
*** Script Error: input has no value *** Where: mold *** Stack: rejoin empty?
copy
sets word to input that matched the rule, while set
sets word only to first element of the marched input.set
is [present](http://www.rebol.com/docs/core23/rebolcore-15.html#section-10.4) in Rebol's Parse.>> parse [a b c 1 2 3][some [set match some integer! | skip]] probe match 1 == 1 >> parse [a b c 1 2 3][some [copy match some integer! | skip]] probe match [1 2 3] == [1 2 3] >> parse ["foo"][set match string!] probe match "foo" == "foo" >> parse ["foo"][copy match string!] probe match ["foo"] == ["foo"]
set
in place of copy
for some reason) :older_man: *cough* *cough* my eyes fail me...["David" "White" "44 Shirley Ave." "Snellville" "NC" "56001" "352-993-7768" "webdragon@comcast.net"] ["Mia" "Taylor" "70 Bowman St." "Harlingen" "MA" "44133" "352-993-7768" "miyop@icloud.com"] ["John" "Wilson" "70 Bowman St." "Forest Hills" "NY" "11418" "212-546-9442" "firstpr@att.net"]
temp: read/lines %/Users/apple/Desktop/db2.txt a: temp/2 print a
["Mia" "Taylor" "70 Bowman St." "Harlingen" "MA" "44133" "352-993-7768" "miyop@icloud.com"]
pick a 2
== #"^""
a: ["Mia" "Taylor" "70 Bowman St." "Harlingen" "MA" "44133" "352-993-7768" "miyop@icloud.com"] pick a 2
== "Taylor"
>temp: load %/Users/apple/Desktop/db2.txt
pick-line: func [block index][line: at block index if string? first line [line/1: load line] first line]
temploaded: load temp
forall temp [temp/1: load temp/1]
load %file
. I would do the conversion on demand as described above.load %/Users/apple/Desktop/db2.txtor
forall temp [temp/1: load temp/1]it takes 20 seconds the first time
load
function is slower than reading from disk.load
is implemented in Red, I believe that it can be much faster when reimplemented in Red/System. But I may be wrong here.read
just copies file from disk to memory, read/lines
splits the file on newlines, but load
needs to check every value and convert them to Red. It must be slower.forall temp [temp/1: load temp/1]
is so slow compared for example to forall temp [temp/1: length? temp/1]
load
does the conversion from string to Red format, so it's understandable that it's slower than eg. length?
.>> profile/show [[load %db2.txt][load %db-n.txt]] Count: 1 Time | Time (Per) | Memory | Code 0:00:20.402 | 0:00:20.402 | 174456832 | [load %db-n.txt] 0:00:28.822 | 0:00:28.822 | 215150592 | [load %db2.txt]
load
is just a wrapper for transcode
, but that it's written in Red instead of Red/System is still the cause of low speed.parse
in R/S. t0: now/time/precise temp: read/lines %db2.txt forall temp [ temp/1: parse temp/1 [ collect some [thru {"} keep to {"} skip] ] ] print temp/1/1 probe now/time/precise - t0
>> profile/count/show [[load sl/1] [parse-it sl/1]] 1000 Count: 1000 Time | Time (Per) | Memory | Code 0:00:00.016 | 0:00:00 | 81920 | [parse-it sl/1] 0:00:00.333 | 0:00:00 | 2183168 | [load sl/1] >> profile/count/show [[load sl/1] [parse-it sl/1]] 100000 Count: 100000 Time | Time (Per) | Memory | Code 0:00:01.588 | 0:00:00 | 57700352 | [parse-it sl/1] 0:00:30.809 | 0:00:00 | 218316800 | [load sl/1]
split-at: func [ "Break a string into pieces using a token or index" series [any-string!] "The string to split" toi [integer! string! char!] "Token or index" /local index ][ index: either integer? toi [toi][index? find series toi] collect [keep copy/part series index keep skip series index] ]
>> split-at "Homerun" 4 == ["Home" "run"] >> split-at "Homerun" "e" == ["Home" "run"] >> split-at "Homerun" #"e" == ["Home" "run"] >> split-at "Homerun" #"x" *** Script Error: index? does not allow none! for its series argument *** Where: index? *** Stack: split-at
slice: func [ string [string!] range [block!] /local start end ][ start: either integer? first range [first range][index? find string first range] end: either integer? last range [last range][index? find string last range] string: skip string start copy/part string (end - start) ] comment { 1) Error if find returns none. Same problem that split-at has to defend against. 2) slice "Catnap and party" [t a] == "t" Should be "na". It sets end to the result of index? find, which is 2 here. The match before start should be ignored and either the index of the next match should be used, or the index of the last match should be used. }
transcode
just has to do a lot. I doubt there's a single bottleneck, but only profiling would really say.attempt
, but here's a gist:toi
is not a very good name. Next thought is to put "two" in the doc string for split-at
so it's clear it doesn't split at every occurrence. The func name does help there though.text carve: func [series index /at][ unless at [index: any [find/case string index return none]] reduce [copy/deep/part series index skip series index] ]
split-at: function [ "Split the series at a position or value, returning the two halves." series [series!] delim "Delimiting value, or index if an integer" /only "Treat value as single value if a series, and as a literal value, not index, if an integer" /tail "Split at delim's tail; implies value" /last "Split at the last occurrence of value, from the tail" ][...]
Split
is the much bigger, more general version.a: ["Sophie" "Wilson" "70 Bowman St." "Forest Hills" "NY" "11418" "212-546-9442" "firstpr@att.net"]
print a/2
b: 1 print a/b
none
a/:b
foreachor
forallto start with last record going backward instead from the first to the last
b: [o [o o [y o o]] o]
and a 'path' p: [2 3 1]
y
at b/2/3/1
? y
to n
?reverse
the series or write your own funcb
and p
to work with, i can't 'cheat' and type 2/3/1
>> get to path! compose [b (p)] == y >> set to path! compose [b (p)] 'n == n
get to path! compose [b (p)]
and any of get head insert make path! p 'b
or get make path! append copy [b] p
or reduce make path! append copy [b] p
?get
, they are all very much the same, with 100000 iterations in the order of 0:00:00.164000001 with little fluctuationsappend
'unwraps' its argument so that append [] 1
and append [] [1]
are equivalent and both give [1]
backb: [1]
than doing append [] reduce [b]
?next
(just like last
would be the converse of first
)most
, init
, ...?)exclude
:>> b: [1 2 3 4 5 6] == [1 2 3 4 5 6] >> exclude b reduce [last b] == [1 2 3 4 5]
next
) and i guess it doesn't and i would like to come up with a word that would 'fit' the functioninit
head
(first one) behead
(all but first one), tail
(last one) curtail
(all but last one)exclude
is tricky>> b: [1 2 3 4 5 6 6] == [1 2 3 4 5 6 6] >> exclude b reduce [last b] == [1 2 3 4 5]
exclude
is a set operation, so maybe not a good choice here. I've called this kind of func chop
in the past. Curtail
is longer, but a fun word. Behead
may be a bit violent, since we have remove
already.remove
or take
will be fast and efficient. The alternative is copy/part
which will require a new allocation, and which will hit you harder for larger blocks.b: [o [o o [y o o]] o] p: [2 3 1] n: 999 pick-deep: func [series indexes [block!] "All integers"][ while [not tail? indexes][ series: pick series first indexes indexes: next indexes ] series ] poke-deep: func [series indexes [block!] "All integers" value][ while [1 < length? indexes][ ; last value is the poke target series: pick series first indexes indexes: next indexes ] poke series first indexes value ] profile/show/count [ [get head insert make path! p 'b set head insert make path! p 'b n] [get to path! compose [b (p)] set to path! compose [b (p)] 'n] [pick-deep b p pick-deep b p n] ] 100'000
Count: 100000 Time | Time (Per) | Memory | Code 0:00:00.292 | 0:00:00 | 43663360 | [get head insert make path! p 'b set head insert make path! p 'b n] 0:00:00.317 | 0:00:00 | 47403008 | [get to path! compose [b (p)] set to path! compose [b (p)] 'n] 0:00:01.024 | 0:00:00 | 0 | [pick-deep b p poke-deep b p n]
runs-per: function [ "Return the number of times code can run in a given period" code [block! word! function!] "Code to evaluate" time [time!] ][ t: now/time/precise n: 0 until [ n: n + 1 do code now/time/precise - t >= time ] n ]
head/behead
and tail/curtail
is nicehead/tails
and tail/heads
head
is already used in Red with a different meaning, because head [1 2 3]
gives me back the whole block and not just 1
tail
behaves differently in Redfirst/next
and ???/last
get
and set
is faster although hungry in memorypick-deep
and poke-deep
!get
and set
per @rebolek snippets :-)butlast
? 😀all-but-last
?up-to-last
?penultimate
first back back tail series
. Just one item.penult
past
maybe?most
almost
Past
for "everything except the last item"? Doesn't sound right to me.first back back tail
most
seems the best to me so farmost
is betterbutlast
all-but-last
. all-but-last
verbose, butlast
would be better and both are inconsistent with next
before
, but mmm...Butlast
would have to at least be but-last
to be Red style conformant.front
?facade
..?ifirst inext
, i??? ilast
, ipick ipoke iappend
, to-iblock
(to make an immutable block) idrop
:^)idrop
makes the pair with itake
skip
just thought it sort of fit>> view [t: tab-panel 400x200 [] return button "add panel" [append t/data probe rejoin ["tab" 1 + length? t/data] append t/pane layout/only compose [text (rejoin ["panel" length? t/data])]]]
tab-panel
(it's been few months).detail-tab: first layout/only [panel [text "hello"]] toggle-detail: function [state [logic!]][ either state [ insert at tabs/data 2 "Detail" insert at tabs/pane 2 detail-tab ][ remove at tabs/data 2 remove at tabs/pane 2 ] ] view [ tabs: tab-panel [ "General" [check "Detail" [toggle-detail face/data]] "Tags" [] ] ]
view [ t: tab-panel 400x200 [] return button "add panel" [ append t/data probe rejoin ["tab" 1 + length? t/data] append t/pane first layout/only compose [at 40x40 text (rejoin ["panel" length? t/data])] ] ]
>> b: [1 2 3 c 5] == [1 2 3 c 5] >> b/4 == c >> b/c == 5
select
access can make them work like maps in many cases, just not as concisely, and not with exactly the same semantics.bind
able and do
able, that's a lot of expressive power that maps lacking, though they are more performance-wisepartition
function for grouping the elements of a block, like this:>> partition [1 2 3 4 5 6 7 8 9] 2 == [[1 2] [3 4] [5 6] [7 8] [9]]
partition: function [elems [block!] group [integer!]] [ unless zero? len: length? elems [b: make block! add divide len group 1 until [append/only b take/part elems group empty? elems] b]]
b
)>> time-it [i: 0 while [i < 100000] [append elems1: [] i: i + 1]] == 0:00:00.100000001 >> time-it [i: 0 while [i < 200000] [append elems2: [] i: i + 1]] == 0:00:00.179000001 >> time-it [i: 0 while [i < 300000] [append elems3: [] i: i + 1]] == 0:00:00.255000001 >> time-it [i: 0 while [i < 400000] [append elems4: [] i: i + 1]] == 0:00:00.343000001 ; but then >> group: 32 == 32 >> time-it [elems: partition elems1 group] ; for 100000 elems == 0:00:00.115000001 >> time-it [elems: partition elems2 group] ; for 200000 elems == 0:00:00.440000001 >> time-it [elems: partition elems3 group] ; for 300000 elems == 0:00:01.261 >> time-it [elems: partition elems4 group] ; for 400000 elems == 0:00:02.747
partition: func [elems [block!] group [integer!]][ parse elems [ collect some [keep group skip | collect keep thru end] ] ]
samples: 05 group: 32 repeat i samples [ set to word! rejoin ['elems i] collect [ repeat j i * 100000 [keep i] ] ] profile/show collect [ repeat i samples [ keep/only compose [ partition (to word! rejoin ['elems i]) group] ] ]
Count: 1 Time | Time (Per) | Memory | Code 0:00:00.009 | 0:00:00.009 | 2101248 | [partition elems1 group] 0:00:00.017 | 0:00:00.017 | 4284416 | [partition elems2 group] 0:00:00.026 | 0:00:00.026 | 6385664 | [partition elems3 group] 0:00:00.034 | 0:00:00.034 | 6385664 | [partition elems4 group] 0:00:00.042 | 0:00:00.042 | 8568832 | [partition elems5 group]
take
working against the head of a series. Obviously, take/part
has extra allocations for returning a block result, over plain take
. blk: [] i: 0 repeat i 100'000 [append blk i] take-from-head: func [blk][until [take blk empty? blk]] take-from-tail: func [blk][until [take/last blk empty? blk]] take-part-from-head: func [blk][until [take/part blk 1 empty? blk]] take-part-from-tail: func [blk][until [take/part/last blk 1 empty? blk]] take-part-from-head-32: func [blk][until [take/part blk 32 empty? blk]] take-part-from-tail-32: func [blk][until [take/part/last blk 32 empty? blk]] profile/show [ [take-from-head copy blk] [take-from-tail copy blk] [take-part-from-head copy blk] [take-part-from-tail copy blk] [take-part-from-head-32 copy blk] [take-part-from-tail-32 copy blk] ]
Count: 1 Time | Time (Per) | Memory | Code 0:00:00.004 | 0:00:00.004 | 4202496 | [take-part-from-tail-32 copy blk] 0:00:00.088 | 0:00:00.088 | 7122944 | [take-part-from-tail copy blk] 0:00:00.09 | 0:00:00.09 | 7122944 | [take-from-tail copy blk] 0:00:00.108 | 0:00:00.108 | 4284416 | [take-part-from-head-32 copy blk] 0:00:03.729 | 0:00:03.729 | 7122944 | [take-part-from-head copy blk] 0:00:03.935 | 0:00:03.935 | 7122944 | [take-from-head copy blk]
take
action like if "current index" = "head" then just move the head position, and free the memory from beginning
free
function call inside take
function in series.reds
file, does that mean take
moves the values but does't free up memory? Those kind of memory stuff will be added later?shrink-series
func that says it's not needed right now, and is commented out. alloc-tail
stuff in %common.reds checks to see if the series needs to be expanded, and so can re-use that memory perhaps. take
was the culprit and the parse
version looks actually better than linear time, it looks logaritmic... which is puzzling (how can that be?) but very welcome :-)Log
mei then :DTime 0:00:00.009 0:00:00.017 0:00:00.026 0:00:00.034 0:00:00.042
/offset
field) to allow optimizing such cases in the future (for the advanced GC in 0.9.x).img: image %/folder/img1.png array-img: [img img img img]
array-img/2/offset/x: 50
offset
is not image's property, it is property of View object. So you need to change the offset in window's pane, not in block of loaded images.img1: %/folder/img1.png img2: %/folder/img1.png img3: %/folder/img1.png array-img: [img1 img2 img3]
array-img/2
img2
>> img1: %/folder/img1.png == %/folder/img1.png >> img2: %/folder/img1.png == %/folder/img1.png >> img3: %/folder/img1.png == %/folder/img1.png >> >> img-block: reduce [img1 img2 img3] == [%/folder/img1.png %/folder/img1.png %/folder/img1.png] >> img-block/2 == %/folder/img1.png
>> img-block: [img1 img2 img3] == [img1 img2 img3] >> get img-block/2 == %/folder/img1.png
viewyou can you can define images, buttons, boxes, etc. and
on-timeblock you change their values, modify size, position of images etc.
on-timeand dinamically display it in
view? if you uncomment
do codeit will not work
code: [img5: image 50x80] code: reduce [code] x: 0 z: 0 view [ size 300x800 ; backdrop gray img1: image %test.png img2: image %test.png img3: image %test.png img4: image %test.png ;do code rate 10 on-time [ print z z: z + 3 if z > 250 [ z: 0] img1/offset/x: z img1/offset/y: 100 img2/offset/x: z img2/offset/y: 200 img3/offset/x: z img3/offset/y: 300 img4/offset/x: z img4/offset/y: 400 ] ]
do
inside view
, it escapes out to use regular Red code, not dialected VID code, so image
has no meaning.view
.pane
elements are, and how to safely manipulate the elements in the GUI tree.on-time
code will run continuously, so you don't really want to try to add faces there anyway.spec: copy [ size 300x800 backdrop gray ] repeat i 5 [ repend spec ['at to pair! i * 50 to set-word! append copy "img" i 'image %test.png] ] view spec
draw
and dynamically altering that block of commands.view
, you can build that block programmatically.partition
function, which can be seen when choosing any grouping greater than 2partition: func [elems [block!] group [integer!]] [ unless empty? elems [parse elems [collect some [keep group skip | collect keep thru end]]]] >> partition [a] 3 == [[a]] ; ok >> partition [a b] 3 == [[[a b]]] ; ERROR: there's extra brackets around [a b] >> partition [a b c] 3 == [[a b c]] ; ok >> partition [a b c d] 3 == [[a b c] [d]] ; ok >> partition [a b c d e] 3 == [[a b c] [[d e]]] ; ERROR: there's extra brackets around [d e] and so on...
collect
in partition
eliminates the bug while introducing a new one (lack of brackets for 'singletons')data: ["AB" [10 11 12] "BC" [5 -5 8] "CD" [105 1 0] "DE" [6 6] "EF" [15 20 15] "FG" [22 11 32] "GH" [20 20 20] ]
sort
), I know how sort by sum (using compare refinements of sort
as function), but how can we use these both ways simultaneously?sum: func [block [block!]] [ either empty? block [0] [add first block sum next block]] sort/skip/reverse/compare/all data 2 func [a b] [(sum second a) < sum second b]
partition
only work for evenly divisible blocks? Should single items (partition of 1) be blocks? In any case, we can work around the original @9214 version, I think, like this:partition: func [elems [block!] group [integer!] /local pos][ parse elems [ collect some [keep group skip | pos: keep (copy pos) thru end] ] ] partition [a] 3 partition [a b] 3 partition [a b c] 3 partition [a b c d] 3 partition [a b c d e] 3 partition [a b c d e f] 3
keep
and keep pick
behavior for clarity. I thought it was somewhere, but can't find it right now.all
refinement. :( I think, that solution will be a bit better ;) :sum: func [a][s1: 0 forall a [s1: s1 + a/1]] sort/skip/compare/all data 2 func[a b][greater? sum second a sum second b]
/reverse
by conveniently reversing the comparator function and you seem to prefer iteration over recursion in sum
:-)text partition: func [series group][ case [ any [empty? series not positive? group][series] group = 1 [ collect [forall series [keep/only to block! first series]] ] 'default parse series [ collect some [keep 2 group skip | collect keep thru end] ] ] ]
parse
instead?ones?: function [block [block!]] [either 1 = first block [ones? next block] [empty? block]] >> ones? [1 1 1] == true >> ones? [1 0 1] == false
ones?: function [block [block!]] [parse block [any 1]]
parse
rules1
?quote
in this case is because your literal value is an integer, and they have their own meaning in parse. That is, to match n
occurrences or m to n
occurrences.partition
is exactly right either. partition: func [series group][ case [ any [empty? series not positive? group][series] group = 1 [ collect [forall series [keep/only to block! first series]] ] 'default parse series [ collect some [keep 2 group skip | collect keep thru end] ] ] ] partition [a [b] c d] 1
to block!
in the skip size of 1 case, you lose nested blocks. It also returns the original series, not a copy, in the first case check. The other two cases return a new series.chunk: func [ "Collect chunks of a series into a new block" series [series!] length [integer!] "Chunk size; must be positive; last chunk may be shorter" /local val ][ if not positive? length [cause-error 'script 'invalid-arg reduce [length]] ; What was the 1 for? It's for leftovers, when the chunk ; length isn't evenly divisible into the series length. collect [ parse series [any [copy val 1 length skip (keep/only val)]] ] ] chunk [] 0 chunk [] 2 chunk [[a]] 3 chunk [a] 3 chunk [a b] 3 chunk [a b c] 3 chunk [a [b] c d] 3 chunk [a b c d e] 3 chunk first [(a b c d e f)] 3 chunk "abcdef" 1 chunk "abcdef" 2 chunk 'ab/cd/ef 1 chunk 'ab/cd/ef 2
split
func in Rebol, so this will likely be part of that for Red, if we can design it to our satisfaction.quote
for matching with numbers, got itpartition
which is slightly faster, or go with the more general chunk
, let's seeCount: 10 Time | Time (Per) | Memory | Code 0:00:00.017 | 0:00:00.002 | 2183168 | [partition blk 10] 0:00:00.019 | 0:00:00.002 | 2183168 | [chunk blk 10] 0:00:00.113 | 0:00:00.011 | 6303744 | [partition blk 1] 0:00:00.12 | 0:00:00.012 | 9224192 | [chunk blk 1]
Count: 10
Time | Time (Per) | Memory | Code
repeat i 100 [ image[i]: load img[i] ]
image[I]
repeat i 100 [ do rejoin [{img} i {: load %/Users/apple/Desktop/img} i {.png}] ]
n: 32 do rejoin [{img} n]
>> type? images == block!
t: 3 mainwindow: [ image (images/(t)) rate 4 on-time [ t: t + 1 print t] ] view compose mainwindow
>> type? images/23 == image!
z: images/23 mainwindow: [ image z ] view mainwindow
mainwindow: [ image images/23 ] view mainwindow
t: 3 mainwindow: [ image (images/(t)) rate 4 on-time [ t: t + 1 print t ] ] view compose mainwindow
mainwindow: [ image images/23 ] view mainwindow
path!
values are not evaluated by VID, but simple words *are*, which is why image z
works. A *few* places can use regular Red expressions, but they are the exception. Red
before the header. That must be proper case.ato point to
images/10but the image shown stays
images/3
a: images/3 mainwindow: [ image a rate 2 on-time [ a: images/10 ] ] view compose mainwindow
a
references doesn't affect the existing layout. What you can do is use a set-word!
before image
and alter the facets for that face.a: images/3 win: [ i: image a rate 2 on-time [ i/image: images/(random length? images) ] ] view win
i/image: first random images
is probably better.random
modifies the block, so the order is no more guaranteed. Every method has its advantages and trade-offs.array: [] temp-array: [] ;generate temp-array repeat num 100 [ append temp-array num ] ;randomize it repeat num 100 [ ran: random length? temp-array temp: temp-array/:ran append array temp remove at temp-array ran print array ]
random/only
source: [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19] ; etc... target: [] repeat i 10 [ n: random/only source unless find target n [append target n] ]
blk: random collect [repeat i 100 [keep i]]
unique
it that is.blk
afterward>> num-range 1% 50% 2% == [1% 3% 5% 7% 9.000000000000002% 11% 13% 15% 17% 19% 21% 23% 25% 27% 29% 31% 33% 35% 37% 39% 41% 43% 45% 47% 49%]
win: layout [ a1: base 200x200 gold loose on-down [print "bring it on top of every other face"] a2: base 200x200 brick loose on-down [print "bring it on top of every other face"] a2: base 200x200 loose on-down [print "bring it on top of every other face"] ] view win
move-to-top: func [face][move find face/parent/pane face tail face/parent/pane] win: layout [ a1: base 200x200 gold loose on-down [move-to-top face] pad -100x0 a2: base 200x200 brick loose on-down [move-to-top face] pad -50x0 a2: base 200x200 loose on-down [move-to-top face] ] view win
arr: array/initial 25 1
;?? Think about how to pass indices to generating funcs. Needs accumulator. array: function [ "Makes and initializes a block of of values (NONE by default)" size [integer! block!] "Size or block of sizes for each dimension" /initial "Specify an initial value for elements" value "For each item: called if a func, deep copied if a series" ][ if block? size [ if tail? more-sizes: next size [more-sizes: none] size: first size if not integer? size [ ; throw error, integer expected cause-error 'script 'expect-arg reduce ['array 'size type? get/any 'size] ] ] result: make block! size case [ block? more-sizes [ loop size [append/only result array/initial more-sizes :value] ] series? :value [ loop size [append/only result copy/deep value] ] any-function? :value [ loop size [append/only result value] ] 'else [ append/dup result value size ] ] result ] ;array 3 ;array [2 3] ;array [2 3 4] ;array/initial 3 0 ;array/initial 3 does ['x]
>> b: copy [] == [] >> insert/dup b 'some-value 5 == [] >> b == [some-value some-value some-value some-value some-value]
append/dup
alsostr: join "a" 1 "b" 2
rejoin ["a" 1 "b" 2]
RPi
) as target platform.Red [Title: "Simple hello world script"] print "Hello World!"
apple$ ./red.dms -c -t RPi test.red -=== Red Compiler 0.6.3 ===- Compiling /Users/apple/Desktop/test.red ... ...compilation time : 1073 ms Target: RPi Compiling to native code... ...compilation time : 32734 ms ...linking time : 260 ms ...output file size : 981432 bytes ...output file : /Users/apple/Desktop/test
./test: error while loading shared libraries: libcrypto.so.1.0.0: cannot open shared object file: No such file or directory
sudo apt-get install ia32-libs libc6-i386 libcurl3 pi@raspberrypi:~/Downloads $ sudo apt-get install ia32-libs libc6-i386 libcurl3 Reading package lists... Done Building dependency tree Reading state information... Done Package libc6-i386 is not available, but is referred to by another package. This may mean that the package is missing, has been obsoleted, or is only available from another source E: Unable to locate package ia32-libs E: Package 'libc6-i386' has no installation candidate
`else
case in what I posted.move-to-top: func [face][move find face/parent/pane face tail face/parent/pane] win: layout [ a1: base 200x200 gold loose on-down [move-to-top face print "what face number is this ?"] pad -100x0 a2: base 200x200 brick loose on-down [move-to-top face print "what face number is this ?"] pad -50x0 a3: base 200x200 loose on-down [move-to-top face print "what face number is this ?"] ] view win
extra
or get its index in the pane.view [ list: text-list data ["John" "Bob" "Alice"] button "Add" [append list/data "Sue"] button "Change" [lowercase pick list/data list/selected] ]
view [ list: text-list data ["John" "Bob" "Alice"] button "Add" [append list/data copy "Sue"] button "Change" [lowercase pick list/data list/selected] ]
move-to-top: func [face][move find face/parent/pane face tail face/parent/pane] who-am-i?: func [face][index? find face/parent/pane face] win: layout [ style mover: base loose 200x200 on-down [print who-am-i? face move-to-top face] a1: mover gold pad -100x0 a2: mover brick pad -50x0 a3: mover ] view win
pane
is just a block of faces, and we know how blocks work, then it's just a matter of knowing what funcs work on them and how. find
and round
. This makes help
open doors for deeper poking around.draw
inside view
? for example need draw 3 circle with radius 10, 20, 30 - loop inside draw
not work>> circles: collect [repeat i 3 [keep compose [circle 35x35 (10 * i)]]] == [circle 35x35 10 circle 35x35 20 circle 35x35 30] >> view [base draw circles]
>> view [base with [draw: collect [repeat i 3 [keep compose [circle 35x35 (10 * i)]]]]]
a: [1 2 4] remove back tail a insert tail a 3
z: copy [] a: copy [] repeat num 20 [ clear a copy insert/dup a 0 num change back tail a 1 append/only z copy a ]
text >> collect [repeat i 5 [keep/only collect [loop i - 1 [keep 0] keep 1]]] == [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]]
>> b: [1] repeat i 5 [append/only [] head copy insert b 0] == [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]]
>> repeat i 5 [a: copy [] append/only [] repeat j i [append a j / i]] == [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]]
>> collect [repeat i 5 [keep/only head insert/dup copy [1] 0 i - 1]] == [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]]
x: 20 _9214: [collect [repeat i x [keep/only collect [loop i - 1 [keep 0] keep 1]]]] _endo64: [b: [1] repeat i x [append/only [] head copy insert b 0]] _toomasv: [repeat i x [a: copy [] append/only [] repeat j i [append a j / i]]] _rebolek: [collect [repeat i x [keep/only head insert/dup copy [1] 0 i - 1]]] >> profile/show/count [_9214 _endo64 _toomasv _rebolek] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code -0:00:00.011 | 0:00:00 | 0 | _rebolek -0:00:00.009 | 0:00:00 | 0 | _endo64 -0:00:00.007 | 0:00:00 | 0 | _toomasv 0:00:00.002 | 0:00:00 | 0 | _9214
>> profile/show/count [_9214 _endo64 _toomasv _rebolek] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code -0:00:00.003 | 0:00:00 | 0 | _9214 -0:00:00.002 | 0:00:00 | 0 | _endo64 0:00:00.001 | 0:00:00 | 0 | _rebolek 0:00:00.003 | 0:00:00 | 0 | _toomasv
compare-times
):>> x: 10 >> compare-times/count [_9214 _endo64 _toomasv _rebolek] 100 Time | Memory | Code 0:00:00.004 | 2101248 | _toomasv 0:00:00.004 | 8486912 | _endo64 0:00:00.004 | 0 | _rebolek 0:00:00.015 | 0 | _9214 >> compare-times/count [_9214 _endo64 _toomasv _rebolek] 100 Time | Memory | Code 0:00:00.003 | 0 | _rebolek 0:00:00.005 | 0 | _toomasv 0:00:00.011 | 25214976 | _endo64 0:00:00.015 | 81920 | _9214 >> compare-times/count [_9214 _endo64 _toomasv _rebolek] 100 Time | Memory | Code 0:00:00.003 | 0 | _rebolek 0:00:00.004 | 0 | _toomasv 0:00:00.015 | 2183168 | _9214 0:00:00.018 | 39923712 | _endo64 >> compare-times/count [_9214 _endo64 _toomasv _rebolek] 100 Time | Memory | Code 0:00:00.003 | 0 | _toomasv 0:00:00.003 | 0 | _rebolek 0:00:00.012 | 2183168 | _9214 0:00:00.03 | 56733696 | _endo64 >> compare-times/count [_9214 _endo64 _toomasv _rebolek] 100 Time | Memory | Code 0:00:00.003 | 0 | _rebolek 0:00:00.004 | 0 | _toomasv 0:00:00.014 | 2183168 | _9214 0:00:00.032 | 73543680 | _endo64
>> compare-times/count [_rebolek _toomasv _endo64 _9214] 100 Time | Memory | Code 0:00:00.003 | 81920 | _rebolek 0:00:00.004 | 0 | _toomasv 0:00:00.016 | 81920 | _9214 0:00:00.082 | 212226048 | _endo64 >> compare-times/count [_rebolek _toomasv _endo64 _9214] 100 Time | Memory | Code 0:00:00.004 | 0 | _rebolek 0:00:00.004 | 0 | _toomasv 0:00:00.014 | 81920 | _9214 0:00:00.089 | 233238528 | _endo64 >> compare-times/count [_rebolek _toomasv _endo64 _9214] 100 Time | Memory | Code 0:00:00.003 | 0 | _rebolek 0:00:00.004 | 0 | _toomasv 0:00:00.014 | 81920 | _9214 0:00:00.096 | 247947264 | _endo64
compare-times
, to allow named programs to be compared:Red [Based-on: "https://gist.github.com/greggirwin/dd172d5dd1e3445b16052a89f000637f"] compare-times: func [ blocks "Block of code blocks to performance compare" /count ct /local t n baseline res blk stats1 memory time code template ][ ct: any [ct 1] t: now/time/precise loop ct [do []] baseline: now/time/precise - t res: collect [ foreach blk blocks [ t: now/time/precise stats1: stats loop ct [do either block? :blk [:blk][get blk]] n: now/time/precise - t - baseline keep reduce [n stats - stats1 either block? :blk [copy blk][:blk]] ] ] sort/skip res 3 insert res ["Time" "Memory" Code] template: [pad (time) 12 #"|" pad (memory) 11 #"|" (mold :code)] foreach [time memory code] res [ print compose template ] ]
b
was not cleared between the calls:x: 10 b: copy [] _9214: [collect [repeat i x [keep/only collect [loop i - 1 [keep 0] keep 1]]]] _endo64: [clear b b: [1] repeat i x [append/only [] head copy insert b 0]] _toomasv: [repeat i x [a: copy [] append/only [] repeat j i [append a j / i]]] _rebolek: [collect [repeat i x [keep/only head insert/dup copy [1] 0 i - 1]]] >> compare-times/count [_9214 _endo64 _toomasv _rebolek] 1000 Time | Memory | Code 0:00:00.012 | 81920 | _endo64 0:00:00.031 | 2265088 | _rebolek 0:00:00.04 | 4284416 | _toomasv 0:00:00.144 | 8978432 | _9214 >> compare-times/count [_9214 _endo64 _toomasv _rebolek] 1000 Time | Memory | Code 0:00:00.013 | 2183168 | _endo64 0:00:00.032 | 4284416 | _rebolek 0:00:00.036 | 2183168 | _toomasv 0:00:00.14 | 9060352 | _9214 >> compare-times/count [_9214 _endo64 _toomasv _rebolek] 1000 Time | Memory | Code 0:00:00.016 | 4284416 | _endo64 0:00:00.029 | 2265088 | _rebolek 0:00:00.04 | 6385664 | _toomasv 0:00:00.124 | 9060352 | _9214
a: copy [] b: copy [] _endo64: [clear a insert clear b 1 repeat i x [append/only a head copy insert b 0]] _toomasv: [clear b repeat i x [a: copy [] append/only b repeat j i [append a j / i]]]
delta-time
func that made profile
go wrong there?compare-times
._gregg: [ a: make block! x ; outer block b: append/dup make block! x 0 x ; inner block of zeros template poke b x 1 ; change last value to 1 repeat i x [append/only a copy at b x - i + 1] ]
a: make block! x ; outer block b: append/dup make block! x 0 x ; inner block of zeros template poke b x 1 ; change last value to 1 _gregg: [clear a repeat i x [append/only a copy at b x - i + 1]]
append
is about 3 times faster than insert
:b: copy [] a: copy [] compare-times/count [[i: 0 clear a loop 1000 [insert a 1]] [i: 0 clear b loop 1000 [append b 1]]] 1000 Time | Memory | Code 0:00:00.3 | 0 | [i: 0 clear a loop 1000 [append a 1]] 0:00:01.009 | 0 | [i: 0 clear b loop 1000 [insert b 1]]
insert/dup
is about 56 times faster than insert
with loop
a: copy [] b: copy [] compare-times/count [[clear a loop 1000 [insert a 1]][clear b insert/dup b 1 1000]] 1000 Time | Memory | Code 0:00:00.018 | 0 | [clear b insert/dup b 1 1000] 0:00:01.011 | 0 | [clear a loop 1000 [insert a 1]]
append/dup
is only about 17 times faster than append
with loop
a: copy [] b: copy [] compare-times/count [[clear a loop 1000 [append a 1]][clear b append/dup b 1 1000]] 1000 Time | Memory | Code 0:00:00.015 | 0 | [clear b append/dup b 1 1000] 0:00:00.279 | 0 | [clear a loop 1000 [append a 1]]
collect/into
is only slightly slower than append, but uses more memoryb: copy [] a: copy [] compare-times/count [[collect/into [loop 1000 [keep 1]] clear b] [clear a loop 1000 [append a 1]]] 1000 Time | Memory | Code 0:00:00.294 | 0 | [clear a loop 1000 [append a 1]] 0:00:00.36 | 2101248 | [collect/into [loop 1000 [keep 1]] clear b]
append
works at the tail, while insert
will have to move more things as it goes. Kind of like the take
performance that came up not long ago.>> compare-times/count [_9214 _endo64 _toomasv _rebolek _gregg] 1000 Time | Memory | Code 0:00:00.013 | 2265088 | _gregg 0:00:00.016 | 81920 | _endo64 0:00:00.031 | 2183168 | _rebolek 0:00:00.04 | 4284416 | _toomasv 0:00:00.131 | 6877184 | _9214 >> compare-times/count [_9214 _endo64 _toomasv _rebolek _gregg] 1000 Time | Memory | Code 0:00:00.014 | 2183168 | _endo64 0:00:00.014 | 2183168 | _gregg 0:00:00.033 | 2183168 | _rebolek 0:00:00.039 | 2183168 | _toomasv 0:00:00.142 | 6877184 | _9214
ag: make block! x ; outer block bg: append/dup make block! x 0 x ; inner block of zeros template poke bg x 1 ; change last value to 1 _gregg2: [clear ag repeat i x [append/only ag copy at bg x - i + 1]]
>> compare-times/count [_9214 _endo64 _toomasv _rebolek _gregg _gregg2] 1000 Time | Memory | Code 0:00:00.011 | 81920 | _gregg2 0:00:00.012 | 81920 | _endo64 0:00:00.013 | 2183168 | _gregg 0:00:00.028 | 4366336 | _rebolek 0:00:00.035 | 2183168 | _toomasv 0:00:00.146 | 6795264 | _9214 >> compare-times/count [_9214 _endo64 _toomasv _rebolek _gregg _gregg2] 1000 Time | Memory | Code 0:00:00.012 | 81920 | _gregg2 0:00:00.013 | 81920 | _endo64 0:00:00.013 | 2265088 | _gregg 0:00:00.033 | 2183168 | _rebolek 0:00:00.037 | 4284416 | _toomasv 0:00:00.143 | 6877184 | _9214 >> compare-times/count [_9214 _endo64 _toomasv _rebolek _gregg _gregg2] 1000 Time | Memory | Code 0:00:00.012 | 2183168 | _endo64 0:00:00.012 | 2183168 | _gregg2 0:00:00.013 | 2183168 | _gregg 0:00:00.03 | 2265088 | _rebolek 0:00:00.038 | 2183168 | _toomasv 0:00:00.144 | 6795264 | _9214
profile
as well. I set it up, and tested, with words that refer to funcs, expecting blocks to always be literals. I'll fix that up.repeat i 5 [append/only [] collect [keep pad/left/with 1 i #"0"]]
>> compare-times/count [_9214 _endo64 _toomasv _rebolek _gregg1 _gregg2 _gltewalt] 1000 Time | Memory | Code 0:00:00.012 | 2183168 | _gregg2 0:00:00.013 | 2183168 | _endo64 0:00:00.013 | 2183168 | _gregg1 0:00:00.031 | 2265088 | _rebolek 0:00:00.037 | 2183168 | _toomasv 0:00:00.054 | 4530176 | _gltewalt 0:00:00.148 | 6795264 | _9214
b: []
. It's just repeat i 5 [append/only [] collect [keep pad/left/with 1 i #"0"]]
[]
in your code. I fixed it as_gltewalt: [clear a repeat i x [append/only a collect [keep pad/left/with 1 i #"0"]]]
>> compare-times/count [_9214 _endo64 _toomasv _rebolek _gregg1 _gregg2 _gltewalt] 1000 Time | Memory | Code 0:00:00.011 | 2183168 | _gregg2 0:00:00.013 | 2265088 | _gregg1 0:00:00.016 | 2183168 | _endo64 0:00:00.031 | 2183168 | _toomasv 0:00:00.041 | 2183168 | _rebolek 0:00:00.097 | 9060352 | _gltewalt 0:00:00.132 | 6877184 | _9214 >> compare-times/count [_9214 _endo64 _toomasv _rebolek _gregg1 _gregg2 _gltewalt] 1000 Time | Memory | Code 0:00:00.011 | 2183168 | _gregg2 0:00:00.013 | 81920 | _gregg1 0:00:00.016 | 2183168 | _endo64 0:00:00.031 | 4366336 | _rebolek 0:00:00.044 | 2183168 | _toomasv 0:00:00.1 | 9060352 | _gltewalt 0:00:00.132 | 4694016 | _9214
[]
for profiling purposes:>> _gltewalt2: [repeat i 5 [append/only b: [] copy [1] insert/dup b/:i 0 i - 1 b]] == [repeat i 5 [append/only b: [] copy [1] insert/dup b/:i 0 i - 1 b]] >> loop 3 [probe do _gltewalt2] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] [[1] [0 0 1] [0 0 0 0 1] [0 0 0 0 0 0 1] [0 0 0 0 0 0 0 0 1] [1] [1] [1] [1] [1]] [[1] [0 0 0 1] [0 0 0 0 0 0 1] [0 0 0 0 0 0 0 0 0 1] [0 0 0 0 0 0 0 0 0 0 0 0 1] [1] [1] [1] [1] [1] [1] [1] [1] [1] [1]]
profile
:>> profile/show/count [_9214 _endo64 _toomasv _rebolek _gregg1 _gregg2 _gltewalt] 1000 Count: 1000 Time | Time (Per) | Memory | Code 0:00:00.011 | 0:00:00 | 2183168 | _gregg2 0:00:00.012 | 0:00:00 | 81920 | _gregg1 0:00:00.019 | 0:00:00 | 81920 | _endo64 0:00:00.03 | 0:00:00 | 4366336 | _rebolek 0:00:00.037 | 0:00:00 | 2183168 | _toomasv 0:00:00.103 | 0:00:00 | 9060352 | _gltewalt 0:00:00.131 | 0:00:00 | 6795264 | _9214
if find code 'gregg [time: fastest - 10%]
if find code 'gregg...
)._gltewalt2: [clear a repeat i x [append/only a copy [1] insert/dup a/:i 0 i - 1 a]]
x: 10 a: copy [] b: copy [] compare-times/count [_9214 _endo64 _toomasv _rebolek _gregg1 _gregg2 _gltewalt _gltewalt2] 1000 Time | Memory | Code 0:00:00.007 | 81920 | _gltewalt2 0:00:00.011 | 2183168 | _gregg2 0:00:00.012 | 81920 | _gregg1 0:00:00.014 | 81920 | _endo64 0:00:00.028 | 4284416 | _rebolek 0:00:00.036 | 2183168 | _toomasv 0:00:00.095 | 9060352 | _gltewalt 0:00:00.139 | 6877184 | _9214
>> step-range 1% 30% 5% == [1% 6% 11% 16% 21% 26%] >> range 1% 30% == [1% 101%]
copy [a]
so insert/dup
is faster?Insert/dup
is a win it seems. insert tail
vs one?x
is larger, so maybe the initial alloc of a block applies as well.5
to x
in _gltewalt2, but somehow 5 slipped back into code, while others were doing 10. So the right results are:>> compare-times/count [_9214 _endo64 _toomasv _rebolek _gregg1 _gregg2 _gltewalt _gltewalt2] 1000 Time | Memory | Code 0:00:00.013 | 2183168 | _gregg1 0:00:00.013 | 81920 | _gregg2 0:00:00.014 | 4284416 | _gltewalt2 0:00:00.015 | 81920 | _endo64 0:00:00.033 | 2265088 | _rebolek 0:00:00.042 | 4284416 | _toomasv 0:00:00.108 | 9060352 | _gltewalt 0:00:00.132 | 6795264 | _9214
text _9214: [ x: 10 also a: reduce [insert/dup copy [1] 0 x - 1] all [ loop x - 1 [append/only a a/1: back a/1] a/1: back tail a/1 ] ] profile/show/count [_9214] 1000
Count: 1000 Time | Time (Per) | Memory | Code 0:00:00.01 | 0:00:00 | 0 | _9214
profile
source?compare-times
text _9214: [ x: 10 also a: reduce [insert/dup copy [1] 0 x - 1] all [ loop x - 1 [append/only a a/1: back a/1] a/1: back tail a/1 ] ] compare-times/count [_9214] 1000
Time | Memory | Code 0:00:00.010119 | 0 | _9214
do
-like function. The *organize* part is the hardest one, I have everything else ready._9214: [ also a: reduce [insert/dup copy [1] 0 x - 1] all [ loop x - 1 [append/only a a/1: back a/1] a/1: back tail a/1 ] ]
>> x: 10 a: copy [] b: copy [] >> profile/show/count [_9214 _endo64 _toomasv _rebolek _gregg1 _gregg2 _gltewalt _gltewalt2] 10000 Count: 10000 Time | Time (Per) | Memory | Code 0:00:00.052 | 0:00:00 | 8568832 | _9214 0:00:00.097 | 0:00:00 | 11325440 | _gregg2 0:00:00.1 | 0:00:00 | 11325440 | _endo64 0:00:00.108 | 0:00:00 | 15691776 | _gregg1 0:00:00.118 | 0:00:00 | 21831680 | _gltewalt2 0:00:00.299 | 0:00:00 | 28626944 | _rebolek 0:00:00.355 | 0:00:00 | 30236672 | _toomasv 0:00:01.025 | 0:00:00 | 92704768 | _gltewalt >> compare-times/count [_9214 _endo64 _toomasv _rebolek _gregg1 _gregg2 _gltewalt _gltewalt2] 10000 Time | Memory | Code 0:00:00.089 | 8568832 | _9214 0:00:00.117 | 13426688 | _gregg2 0:00:00.122 | 11325440 | _endo64 0:00:00.133 | 13590528 | _gregg1 0:00:00.138 | 23932928 | _gltewalt2 0:00:00.311 | 30728192 | _rebolek 0:00:00.38 | 30236672 | _toomasv 0:00:01.046 | 90603520 | _gltewalt
compare-times
adds ~30ms to time?_9214: [ also a: reduce [insert/dup copy [1] 0 x - 1] loop x - 1 [append/only a back last a] ]
text x: 10 _9214-1: [ also a: reduce [insert/dup copy [1] 0 x - 1] loop x - 1 [append/only a back last a] ] _9214-2: [ also a: reduce [insert/dup copy [1] 0 x - 1] all [ loop x - 1 [append/only a a/1: back a/1] a/1: back tail a/1 ] ] profile/show/count [_9214-1 _9214-2] 10'000
Count: 10000 Time | Time (Per) | Memory | Code 0:00:00.093 | 0:00:00 | 6467584 | _9214-1 0:00:00.094 | 0:00:00 | 8568832 | _9214-2
load mold
after generation, but currently load
is costly operationback copy last a
instead, at a cost of doubled memory consumption and slower speed_githubnyn: [clear b repeat num x [a: copy [] insert/dup a 0 num change back tail a 1 append/only b copy a]]
compare-times/count [_githubnyn _9214 _endo64 _toomasv _rebolek _gregg1 _gregg2 _gltewalt _gltewalt2] 10000 Time | Memory | Code 0:00:00.092 | 8568832 | _9214 0:00:00.118 | 11325440 | _gregg2 0:00:00.131 | 11325440 | _endo64 0:00:00.14 | 23932928 | _gltewalt2 0:00:00.233 | 41562112 | _githubnyn 0:00:00.315 | 28626944 | _rebolek 0:00:00.382 | 30236672 | _toomasv
text _9214: [ also a: reduce [insert/dup copy [1] 0 x - 1] loop x - 1 [append/only a back last a] ]
>> compare-times/count [_githubnyn _9214 _endo64 _toomasv _rebolek _gregg2 _gltewalt2] 10000 Time | Memory | Code 0:00:00.09 | 8568832 | _9214 0:00:00.117 | 13426688 | _gregg2 0:00:00.123 | 11325440 | _endo64 0:00:00.144 | 21831680 | _gltewalt2 0:00:00.239 | 41562112 | _githubnyn 0:00:00.288 | 28626944 | _rebolek 0:00:00.381 | 30236672 | _toomasv
_9214: [also a: reduce [insert/dup copy [1] 0 x - 1] loop x - 1 [append/only a back last a]] _endo64: [clear a insert clear b 1 repeat i x [append/only a head copy insert b 0]] _toomasv: [clear b repeat i x [a: copy [] append/only b repeat j i [append a j / i]]] _rebolek: [collect/into [repeat i x [keep/only head insert/dup copy [1] 0 i - 1]] clear b] ag: make block! x ; outer block bg: append/dup make block! x 0 x ; inner block of zeros template poke bg x 1 ; change last value to 1 _gregg2: [clear ag repeat i x [append/only ag copy at bg x - i + 1]] _gltewalt: [clear a repeat i x [append/only a collect [keep pad/left/with 1 i #"0"]]] _githubnyn: [clear b repeat num x [a: copy [] insert/dup a 0 num change back tail a 1 append/only b copy a]]
x: 10 a: copy [] b: copy [] _9214: [also a: reduce [insert/dup copy [1] 0 x - 1] loop x - 1 [append/only a back last a]] _endo64: [clear a insert clear b 1 repeat i x [append/only a head copy insert b 0]] _toomasv: [clear b repeat i x [a: copy [] append/only b repeat j i [append a j / i]]] _rebolek: [collect/into [repeat i x [keep/only head insert/dup copy [1] 0 i - 1]] clear b] ag: make block! x ; outer block bg: append/dup make block! x 0 x ; inner block of zeros template poke bg x 1 ; change last value to 1 _gregg2: [clear ag repeat i x [append/only ag copy at bg x - i + 1]] _gltewalt: [clear a repeat i x [append/only a collect [keep pad/left/with 1 i #"0"]]] _githubnyn: [clear b repeat num x [a: copy [] insert/dup a 0 num change back tail a 1 append/only b copy a]] profile/show/count [_githubnyn _9214 _endo64 _toomasv _rebolek _gregg2 _gltewalt] 10'000
Count: 10000 Time | Time (Per) | Memory | Code 0:00:00.092 | 0:00:00 | 6467584 | _9214 0:00:00.118 | 0:00:00 | 11325440 | _gregg2 0:00:00.118 | 0:00:00 | 13426688 | _endo64 0:00:00.229 | 0:00:00 | 41562112 | _githubnyn 0:00:00.339 | 0:00:00 | 28626944 | _rebolek 0:00:00.393 | 0:00:00 | 30236672 | _toomasv 0:00:01.208 | 0:00:00 | 92704768 | _gltewalt
_gltewalt2: [clear a repeat i x [append/only a copy [1] insert/dup a/:i 0 i - 1 a]]
profile
function here (you can copy/paste it into your code): profile: function [ "Profile code, returning [time memory source] results" blocks [block!] "Block of code values (block, word, or function) to profile" /count ct "Eval code this many times, rather than once" /show "Display results, instead of returning them as a block" /kb /mb ][ ct: any [ct 1] ; set number of evaluations baseline: delta-time/count [] ct res: collect [ foreach blk blocks [ stats-1: stats ; get current stats before evaluation n: subtract delta-time/count :blk ct baseline keep/only reduce [ round/to n .001 round/to n / ct .001 stats - stats-1 either block? :blk [copy blk][:blk] ] ] ] if kb or mb [ forall res [ res/1/3: round/to either kb [res/1/3 / 1000.0][res/1/3 / 1000000.0] .01 ] ] sort res ; sort by time either show [ print ["Count:" ct] template: [pad (time) 12 #"|" pad (time-per) 12 #"|" pad/left (memory) 11 #"|" (mold/flat :code)] insert/only res compose/deep ["Time" "Time (Per)" (rejoin ["Memory" (case [kb [" (kb)"] mb [" (mb)"] true [""]])]) Code] ; last column is molded, so not a string here foreach blk res [ set [time time-per memory code] blk print compose template ] ][ insert/only res compose [count: (ct) fields: [Time Time-Per Memory Code]] new-line/all res on ; Return formatted results ] ]
>> profile/show/count/kb [_githubnyn _9214 _endo64 _toomasv _rebolek _gregg2 _gltewalt2] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.085 | 0:00:00 | 8568.83 | _9214 0:00:00.108 | 0:00:00 | 13426.69 | _gregg2 0:00:00.119 | 0:00:00 | 11325.44 | _endo64 0:00:00.136 | 0:00:00 | 21831.68 | _gltewalt2 0:00:00.224 | 0:00:00 | 41562.11 | _githubnyn 0:00:00.303 | 0:00:00 | 28626.94 | _rebolek 0:00:00.363 | 0:00:00 | 30236.67 | _toomasv >> profile/show/count/mb [_githubnyn _9214 _endo64 _toomasv _rebolek _gregg2 _gltewalt2] 10000 Count: 10000 Time | Time (Per) | Memory (mb) | Code 0:00:00.085 | 0:00:00 | 6.47 | _9214 0:00:00.112 | 0:00:00 | 11.33 | _gregg2 0:00:00.12 | 0:00:00 | 11.33 | _endo64 0:00:00.131 | 0:00:00 | 23.93 | _gltewalt2 0:00:00.236 | 0:00:00 | 43.66 | _githubnyn 0:00:00.317 | 0:00:00 | 30.73 | _rebolek 0:00:00.395 | 0:00:00 | 30.24 | _toomasv
_toomasv2: [ clear a insert/dup clear b 0 x change back tail b 1 insert/only/dup a b x forall a [a/1: at a/1 x + 1 - (index? a)] a ]
>> x: 5 loop 5 [probe do _toomasv2] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]]
x: 10 a: copy [] b: copy [] profile/show/kb/count [_githubnyn _9214 _endo64 _toomasv2 _rebolek _gregg2 _gltewalt2] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.083 | 0:00:00 | 8568.83 | _9214 0:00:00.106 | 0:00:00 | 0.0 | _toomasv2 0:00:00.109 | 0:00:00 | 11325.44 | _gregg2 0:00:00.115 | 0:00:00 | 11325.44 | _endo64 0:00:00.126 | 0:00:00 | 23932.93 | _gltewalt2 0:00:00.203 | 0:00:00 | 41562.11 | _githubnyn 0:00:00.304 | 0:00:00 | 28626.94 | _rebolek
profile
?clear b
in my code? collect/into
, I see.>> profile/show/kb/count [_rebolek _rebolek2] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.302 | 0:00:00 | 30810.11 | _rebolek2 0:00:00.306 | 0:00:00 | 30728.19 | _rebolek >> profile/show/kb/count [_rebolek _rebolek2] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.286 | 0:00:00 | 30728.19 | _rebolek 0:00:00.286 | 0:00:00 | 30810.11 | _rebolek2
_rebolek: [collect [repeat i x [keep/only head insert/dup copy [1] 0 i - 1]]] _rebolek2: [collect/into [repeat i x [keep/only head insert/dup copy [1] 0 i - 1]] clear b]
profile
enhancement. format-bytes
func in the format
work, but don't want dependencies from the profile
gist._toomasv3: [ also head insert/only/dup clear a change back insert/dup clear b 0 x 1 x repeat i x [a/:i: skip a/:i negate i] ]
>> profile/show/kb/count [_9214 _toomasv3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.05 | 0:00:00 | 0.0 | _toomasv3 0:00:00.065 | 0:00:00 | 8568.83 | _9214 >> profile/show/kb/count [_9214 _toomasv3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.079 | 0:00:00 | 0.0 | _toomasv3 0:00:00.084 | 0:00:00 | 6467.58 | _9214 >> profile/show/kb/count [_9214 _toomasv3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.084 | 0:00:00 | 8568.83 | _9214 0:00:00.094 | 0:00:00 | 0.0 | _toomasv3 >> profile/show/kb/count [_9214 _toomasv3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.076 | 0:00:00 | 6467.58 | _9214 0:00:00.088 | 0:00:00 | 0.0 | _toomasv3
_gregg-x2: [ a: make block! x ; outer block b: head insert/dup make block! x 0 x ; inner block of zeros template poke b x 1 ; change last value to 1 loop x [insert/only a b b: next b] ; add offsets into b a ]
a
and b
for a slight win. If all are reusing those, we need to prime them fairly, yes? Haven't been watching tests for that.>> profile/show/kb/count [_9214 _toomasv3 _gregg-x2] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.067 | 0:00:00 | 8568.83 | _9214 0:00:00.07 | 0:00:00 | 4366.34 | _gregg-x2 0:00:00.073 | 0:00:00 | 0.0 | _toomasv3 >> profile/show/kb/count [_9214 _toomasv3 _gregg-x2] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.077 | 0:00:00 | 6467.58 | _9214 0:00:00.084 | 0:00:00 | 4366.34 | _gregg-x2 0:00:00.096 | 0:00:00 | 0.0 | _toomasv3 >> profile/show/kb/count [_9214 _toomasv3 _gregg-x2] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.087 | 0:00:00 | 0.0 | _toomasv3 0:00:00.093 | 0:00:00 | 2265.09 | _gregg-x2 0:00:00.1 | 0:00:00 | 8568.83 | _9214
a
and b
into ag
and bg
_gregg-x3: [ clear a ; outer block b: head insert/dup clear b x 0 x ; inner block of zeros template poke b x 1 ; change last value to 1 loop x [insert/only a b b: next b] ; add offsets into b a ]
profile/show/kb/count [_9214 _toomasv3 _gregg-x3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.071 | 0:00:00 | 0.0 | _gregg-x3 0:00:00.073 | 0:00:00 | 6467.58 | _9214 0:00:00.081 | 0:00:00 | 0.0 | _toomasv3 >> profile/show/kb/count [_9214 _toomasv3 _gregg-x3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.078 | 0:00:00 | 8568.83 | _9214 0:00:00.079 | 0:00:00 | 0.0 | _gregg-x3 0:00:00.089 | 0:00:00 | 0.0 | _toomasv3 >> profile/show/kb/count [_9214 _toomasv3 _gregg-x3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.081 | 0:00:00 | 0.0 | _toomasv3 0:00:00.084 | 0:00:00 | 6467.58 | _9214 0:00:00.091 | 0:00:00 | 0.0 | _gregg-x3
load mold
if neededcopy
internally>> step-range 1% 50% 3% == [1% 4% 7% 10% 13% 16% 19% 22% 25% 28% 31% 34% 37% 40% 43% 46% 49%]
within?/between?
, or case
ranges are adjacent, etc._9214': [ a: reduce [append/dup make block! x 0 x] a/1/:x: 1 reverse loop x - 1 [append/only a next last a] ]
>> profile/show/kb/count [_9214' _toomasv3 _gregg-x3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.102 | 0:00:00 | 0.0 | _gregg-x3 0:00:00.115 | 0:00:00 | 0.0 | _toomasv3 0:00:00.118 | 0:00:00 | 4366.34 | _9214' >> profile/show/kb/count [_9214' _toomasv3 _gregg-x3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.071 | 0:00:00 | 6467.58 | _9214' 0:00:00.08 | 0:00:00 | 0.0 | _gregg-x3 0:00:00.096 | 0:00:00 | 0.0 | _toomasv3 >> profile/show/kb/count [_9214' _toomasv3 _gregg-x3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.102 | 0:00:00 | 0.0 | _gregg-x3 0:00:00.112 | 0:00:00 | 0.0 | _toomasv3 0:00:00.122 | 0:00:00 | 4366.34 | _9214'
profile
function different than @greggirwin 's gist?*** Script Error: reverse does not allow none! for its series argument
for _9214 and *** Script Error: value out of range: 1
for _gregg-x3._gregg-x3: [ clear a ; outer block b: head insert/dup clear b x 0 x ; inner block of zeros template poke b x 1 ; change last value to 1 loop x [insert/only a b b: next b] ; add offsets into b a ] a: copy [] b: copy [] x: 1 profile/show/count [ _gregg-x3] 1000
_gregg-x3: [ clear a ; outer block b: head insert/dup clear b 0 x ; inner block of zeros template poke b x 1 ; change last value to 1 loop x [insert/only a b b: next b] ; add offsets into b a ]
>> x: 5 a: copy [] b: copy [] loop 3 [probe do _gregg-x3'] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] [[1 0 0 0 0 0] [0 1 0 0 0 0 0] [0 0 1 0 0 0 0 0] [0 0 0 1 0 0 0 0 0] [0 0 0 0 1 0 0 0 0 0]] [[1 0 0 0 0 0] [0 1 0 0 0 0 0] [0 0 1 0 0 0 0 0] [0 0 0 1 0 0 0 0 0] [0 0 0 0 1 0 0 0 0 0]] == [[1 0 0 0 0 0] [0 1 0 0 0 0 0] [0 0 1 0 0 0 0 0] [0 0 0 1 0 0 0 0 0] [0 0 0 0 1 0 0 0 0 0]] >> probe _gregg-x3' [ clear a b: head insert/dup clear b 0 x poke b x 1 loop x [insert/only a b b: next b] a ]
a
and b
are shared, although cleared, the superfluous x
in _gregg-x3 went unnoticed. I checked other codes with the same loop as above and they seem to work._9214'': [ also append/only clear a insert/dup append clear b 1 0 x - 1 loop x - 1 [append/only a back last a] ]
>> profile/show/kb/count [_9214-3 _toomasv3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.068 | 0:00:00 | 0.0 | _9214-3 0:00:00.096 | 0:00:00 | 0.0 | _toomasv3 >> profile/show/kb/count [_9214-3 _toomasv3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.077 | 0:00:00 | 0.0 | _9214-3 0:00:00.088 | 0:00:00 | 0.0 | _toomasv3 >> profile/show/kb/count [_9214-3 _toomasv3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.078 | 0:00:00 | 0.0 | _toomasv3 0:00:00.085 | 0:00:00 | 0.0 | _9214-3 >> profile/show/kb/count [_9214-3 _toomasv3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) | Code 0:00:00.084 | 0:00:00 | 0.0 | _toomasv3 0:00:00.086 | 0:00:00 | 0.0 | _9214-3
also
thing!_9214''': [ either empty? a [ also append/only clear a insert/dup append clear b 1 0 x - 1 loop x - 1 [append/only a back last a] ][a] ]
profile/show/kb/count [_9214-3 _9214-4 _toomasv3] 10000 Count: 10000 Time | Time (Per) | Memory (kb) (kb) (kb) | Code -0:00:00.006 | 0:00:00 | 0.0 | _9214-4 0:00:00.067 | 0:00:00 | 0.0 | _toomasv3 0:00:00.072 | 0:00:00 | 0.0 | _9214-3
_9214''': [ either empty? a [ attempt [append _toomasv3 [loop 10 ** 3 [append [] 'ha]]] also append/only clear a insert/dup append clear b 1 0 x - 1 loop x - 1 [append/only a back last a] ][a] ]
map!
with x
key and generated block value[[1] [0 1] [0 0 1] ...]
copy/part stream x
[0 0 0 0 0 ... 1]
x: 10 a: make block! x b: make block! x m: make map! 1 _toomasv5: [ either m/1 [m/1][m/1: a also head insert/only/dup head a change back insert/dup clear b 0 x 1 x repeat i x [a/:i: skip a/:i negate i] ] ] >> profile/show/kb/count [_9214-4 _toomasv5] 1000000 Count: 1000000 Time | Time (Per) | Memory (kb) | Code 0:00:00.378 | 0:00:00 | 0.0 | _toomasv5 0:00:00.532 | 0:00:00 | 0.0 | _9214-4 >> profile/show/kb/count [_9214-4 _toomasv5] 1000000 Count: 1000000 Time | Time (Per) | Memory (kb) | Code 0:00:00.407 | 0:00:00 | 0.0 | _toomasv5 0:00:00.492 | 0:00:00 | 0.0 | _9214-4 >> profile/show/kb/count [_9214-4 _toomasv5] 1000000 Count: 1000000 Time | Time (Per) | Memory (kb) | Code 0:00:00.396 | 0:00:00 | 0.0 | _toomasv5 0:00:00.526 | 0:00:00 | 0.0 | _9214-4 >> profile/show/kb/count [_9214-4 _toomasv5] 1000000 Count: 1000000 Time | Time (Per) | Memory (kb) | Code 0:00:00.394 | 0:00:00 | 0.0 | _toomasv5 0:00:00.472 | 0:00:00 | 0.0 | _9214-4 >> profile/show/kb/count [_9214-4 _toomasv5] 1000000 Count: 1000000 Time | Time (Per) | Memory (kb) | Code 0:00:00.437 | 0:00:00 | 0.0 | _toomasv5 0:00:00.533 | 0:00:00 | 0.0 | _9214-4
>> probe _9214-4 [ either empty? a [ also append/only clear a insert/dup append clear b 1 0 x - 1 loop x - 1 [append/only a back last a] ] [a] ]
m/:x
I believenot m/1
?[m/1]
_9214: [ any [ m/:x m/:x: also append/only clear a insert/dup append clear b 1 0 x - 1 loop x - 1 [append/only a back last a] ] ]
clear
everything in between competitors ;)>> a: make block! x b: make block! x m: make map! x profile/show/count [_9214] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.292 | 0:00:00 | 0 | _9214 >> a: make block! x b: make block! x m: make map! x profile/show/count [_toomasv5] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.429 | 0:00:00 | 0 | _toomasv5 >> a: make block! x b: make block! x m: make map! x profile/show/count [_9214] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.277 | 0:00:00 | 0 | _9214 >> a: make block! x b: make block! x m: make map! x profile/show/count [_toomasv5] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.438 | 0:00:00 | 0 | _toomasv5
x
value on every iteration_gregg-x3: [ clear a ; outer block b: head insert/dup clear head b 0 x ; inner block of zeros template poke b x 1 ; change last value to 1 loop x [insert/only a b b: next b] ; add offsets into b a ]
_toomasv7: [ any [ a also head insert/only/dup head clear a change back insert/dup clear b 0 x 1 x repeat i x [a/:i: skip a/:i negate i] ] ] >> a: make block! x b: make block! x m: make map! x profile/show/count [_toomasv7] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.203 | 0:00:00 | 0 | _toomasv7 >> a: make block! x b: make block! x m: make map! x profile/show/count [_9214] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.285 | 0:00:00 | 0 | _9214 >> a: make block! x b: make block! x m: make map! x profile/show/count [_toomasv7] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.199 | 0:00:00 | 0 | _toomasv7 >> a: make block! x b: make block! x m: make map! x profile/show/count [_toomasv7] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.207 | 0:00:00 | 0 | _toomasv7 >> a: make block! x b: make block! x m: make map! x profile/show/count [_9214] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.291 | 0:00:00 | 0 | _9214 >> a: make block! x b: make block! x m: make map! x profile/show/count [_toomasv7] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.206 | 0:00:00 | 0 | _toomasv7 >> a: make block! x b: make block! x m: make map! x profile/show/count [_9214] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.299 | 0:00:00 | 0 | _9214
_9214: [ any [ a also append/only clear a insert/dup append clear b 1 0 x - 1 loop x - 1 [append/only a back last a] ] ]
>> a: make block! x b: make block! x m: make map! x profile/show/count [_9214] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.197 | 0:00:00 | 0 | _9214 >> a: make block! x b: make block! x m: make map! x profile/show/count [_toomasv7] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.207 | 0:00:00 | 0 | _toomasv7 >> a: make block! x b: make block! x m: make map! x profile/show/count [_9214] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.211 | 0:00:00 | 0 | _9214 >> a: make block! x b: make block! x m: make map! x profile/show/count [_toomasv7] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.187 | 0:00:00 | 0 | _toomasv7
a: make block! x b: make block! x profile/show/count [_9214 _toomasv6 _gregg-x3] 10000 Count: 10000 Time | Time (Per) | Memory | Code 0:00:00 | 0:00:00 | 0 | _9214 0:00:00 | 0:00:00 | 0 | _toomasv6 0:00:00.085 | 0:00:00 | 0 | _gregg-x3
map!
version then_9214: [ any [ m/:x m/:x: also append/only clear a insert/dup append clear b 1 0 x - 1 loop x - 1 [append/only a back last a] ] ]
_9214: [ any [a also append/only a: copy [] insert/dup append clear b 1 0 x - 1 loop x - 1 [append/only a back last a] ] ] _toomasv7: [ any [a also head insert/only/dup head a: copy [] change back insert/dup clear b 0 x 1 x repeat i x [a/:i: skip a/:i negate i] ] ]
/pre
in profile
:>> a: none b: make block! x profile/show/count [_9214] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.242 | 0:00:00 | 0 | _9214 >> a: none b: make block! x profile/show/count [_toomasv7] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.231 | 0:00:00 | 0 | _toomasv7
parse
can be (effectively) applied...>> x: 5 a: none loop 3 [probe do _9214] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] >> a: none loop 3 [probe do _toomasv7] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]]
cheater: context [ x: 10 a: make block! x a: head insert/dup a none x ; outer memoization block b: make block! x b: head insert/dup b 0 x ; inner block of zeros template poke b x 1 ; change last value to 1 make-item: func [i][skip tail b negate i] add-item: func [i][poke a i make-item i] pick-item: func [i][any [pick a i add-item i]] set '_cheating-gregg [] ] ; print mold cheater ; cheater/pick-item 1 ; cheater/pick-item 10 ; print mold cheater
b: make block! [[1][1][1][1][1]] repeat i 5 [loop i - 1 [insert b/:i 0] b]
>> loop 3 [probe repeat i 5 [unless 1 < length? b/:i [loop i - 1 [insert b/:i 0]] b]] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 1]]
_endo64: [ next reverse repeat i x [append/only b: [[1]] skip insert first b 0 x] ] >> profile/show/count [_endo64] 10000 Count: 1000 Time | Time (Per) | Memory | Code 0:00:003.47 | 0:00:00 | 0 | _endo64
>> x: 5 b: copy [] loop 3 [probe do _endo64] [[1] [0 1] [0 0 1] [0 0 0 1] [0 0 0 0 0 1]] [[0] [0 0] [0 0 0] [0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0] [0 0 0 1 0 0 0 0 0] [0 0 1 0 0 0 0 0] [0 1 0 0 0 0 0] [1 0 0 0 0 0] [0 0 0 0 0]] [[0] [0 0] [0 0 0] [0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0] [0 0 0 0 0 0] [0 0 0 0 0]]
.../count ... 10000
transform into "Count: 1000"?[1 123]
?print test:xthat doesn't work - so I can join the test to the 1 and use it as a variable
text >> test1: 1 == 1 >> test2: 2 == 2 >> test3: 3 == 3 >> repeat x 3 [probe to word! rejoin ['test x]] test1 test2 test3 == test3
>> repeat i 10 [set to-set-word load append form 'test i i] == 10 >> ?? test1 test1: 1 >> ?? test10 test10: 10
to-set-word
btwrepeat i 10 [set load append form 'test i i]
Thanks @9214 either all
..?a: [1 2 3 4 5 6 7 8] b: take/part tail a 3
Besides, how did .../count ... 10000 transform into "Count: 1000"?
sorry I think I made two tests and I mixed up them while copying.Red [] range: function [val1 val2 /step stp][ stp: any [stp either any [percent? val1 percent? va2] [1%][1]] rng: to-block either (number? stp) or (time? stp) [ pick reduce [val1 val2] stp+?: stp > 0 ][stp+?: true val1] comp: pick reduce [:<= :>=] (growing?: val1 < val2) xor stp+? inc: pick reduce [:+ :-] growing? addnext: pick reduce [:append :insert] stp+? changing: pick reduce [val1 val2] stp+? limit: pick reduce [val2 val1] stp+? while [limit comp changing: changing inc stp] [ head addnext rng changing ] rng ]
range/step 1-Jan-2018 5-Jan-2018 to-integer 11-9-1561/4:35:13 == [1-Jan-2018 2-Jan-2018 3-Jan-2018 4-Jan-2018 5-Jan-2018]
range/step 1-Jan-2018 5-Jan-2022 to-integer 11-9-1561/4:41:17 == [1-Jan-2018 1-Jan-2019 1-Jan-2020 31-Dec-2020 31-Dec-2021]
parse
is safer than Rebol's one I guess:parse [b] [some [any word!]]
returns true
on Red but endless loop on Rebol.:get-words
parse/trace
callbackmove-to-top: func [face][move find face/parent/pane face tail face/parent/pane] who-am-i?: func [face][index? find face/parent/pane face] win: layout [ style mover: base loose 200x200 on-down [print who-am-i? face move-to-top face] a1: mover gold pad -100x0 a2: mover brick pad -50x0 a3: mover ] view win
on-down
function face
word is already refers to the face you clicked on. So your example should work.view win: layout [ style mover: base loose 200x200 on-down [move find/same win/pane face tail win/pane] a1: mover gold pad -100x0 a2: mover brick pad -50x0 a3: mover ]
range: func [ "Returns a range of numbers or chars from lower to upper" lower [number! char! date!] upper [number! char! date!] /step "Increment range by step" num [number! char! date!] /rev "Returns range reversed" /local blk increment ][ blk: reduce [lower] increment: does [append blk lower: lower + num] check-bounds: func [val1 val2][ if val1 > val2 [cause-error 'script 'past-end []] ] either step [check-bounds num upper][check-bounds lower upper num: 1] while [lower < upper][increment] either rev [reverse blk][blk] if upper < last blk [remove back tail blk] blk ]
move-to-top: func [face][move find/same win/pane face tail win/pane] view win: layout [ style mover: base loose 200x200 on-down [move-to-top face] a1: mover gold pad -100x0 a2: mover brick pad -50x0 a3: mover button "Move" [move-to-top get random/only [a1 a2 a3]] ]
base
style currently. Some other styles may work but text and area styles do not AFAIK: base "Field 1:" 80x24 font-size 13 with [color: none]
probe
cuts down its output, are you sure about that?system/console/size
pairx
coordinateprobe
always prints its mold
ed argument fully before returning value, so you should inspect that printed version insteadwin: [ size 1000x700 offset 1000x500 at 300x300 i: base 100x100 rate 10 on-time [ z/offset/x: z/offset/x + 1 ] ] s: load %/1.png test: [] append test load rejoin ["at 10x10 z: image s" ] append win test view win
at 300x300 i: base 100x100the script doesn't work. I guess because it doesn't find anything to render, but I am adding an image to win with append
lit-word!
s?append win [at 10x10 z: image s]
should be enoughlayoutbut when I add layout, it doesn't work. I am just trying to position this window with offset
>> view win *** Script Error: VID - invalid syntax at: [offset 1000x500 size] *** Where: do *** Stack: view layout cause-error
offset 1000x500 size
in the code you've posted above>> append win code *** Script Error: append does not allow object! for its series argument *** Where: append *** Stack:
size
on the next line eitheroffset
keyword for container settingstext win: [ size 1000x700 at 300x300 i: base 100x100 rate 10 on-time [ z/offset/x: z/offset/x + 1 ] ] s: load %./1.png append win [at 10x10 z: image s] view/options win [offset: 1000x500]
win: [ size 1000x700 at 300x300 i: base 100x100 rate 10 on-time [ z/offset/x: z/offset/x + 1 ] ] append win [at 10x10 z: image with [image: load %./1.png]] view/options win [offset: 1000x500]
Red [] range: function [val1 val2 /step stp][ stp: any [stp either any [percent? val1 percent? va2] [1%][1]] rng: to-block either (number? stp) or (time? stp) [ pick reduce [val1 val2] stp+?: stp > 0 ][stp+?: true val1] comp: pick reduce [:<= :>=] (growing?: val1 < val2) xor stp+? inc: pick reduce [:+ :-] growing? addnext: pick reduce [:append :insert] stp+? changing: pick reduce [val1 val2] stp+? limit: pick reduce [val2 val1] stp+? while [limit comp changing: changing inc stp] [ head addnext rng changing ] rng ]
>> pick [a b] true == a >> pick [a b] false == b
none
does not work here in place of false
:>> pick [a b] none *** Script Error: pick does not allow none! for its index argument
>> a: 1 b: 2 >> pick reduce [a b] a < b == 1 >> pick reduce [a b] a > b == 2
range
" challenge! I'll have to revisit my old stuff and Reduce it.collect
as it uses my original custom version it seems.>> next-x: lazy-range/limit 10 10 [...] >> collect [ while [x: next-x][ next-y: lazy-range/step/limit 2 2 5 while [y: next-y][keep as-pair x y] ] ] == [10x2 10x4 10x6 10x8 10x10 11x2 11x4 11x6 11x8 11x10 12x2 12x4 12x6 12x8 12x10 13x2 13x4 13x6 13x8 13x10 14x2 14x4 14x6 14x8 14x10 15x2 15x4 1...
drop-down
is on-enter
, for drop-list
it's on-change
. view [ below t-1: text 80x20 "Waiting..." drop-down "D" data ["A" "B" "C"] [t-1/text: mold face/text] t-2: text 80x20 "Waiting..." drop-down "D" data ["A" "B" "C"] on-select [t-2/text: mold face/text] t-3: text 80x20 "Waiting..." drop-list select 2 data ["A" "B" "C"] [t-3/text: mold pick face/data face/selected] ]
?? system/view/vid/styles
>> view [style txt text font [name: "arial" size: 14 color: coal]] *** Script Error: VID - invalid syntax at: [txt text font] *** Where: do *** Stack: view layout cause-error
set-word!
.*** Script Error: copy does not allow set-word! for its value argument *** Where: copy *** Stack: view layout layout
view [ title "VID Example" size 800x600 origin 0x0 space 0x0 style my-style: text pewter font-name "arial" font-size 14 tab-panel 800x600 [ "Main " [ backdrop https://s-media-cache-ak0.pinimg.com/originals/87/ff/70/87ff70fec156246c5490c68eab6f3ce0.jpg below h4 "Enter some stuff:" field 600 my-style h4 "Other stuff:" area 600x300 my-style h4 "Final stuff:" area 600x100 my-style ] "Help " [backdrop red] ] ]
style fld: field 600
- if it's in the tab-panel
block it throws an errorview [ title "VID Example" size 800x600 origin 0x0 space 0x0 style fld: field 600 ; -- works tab-panel 800x600 [ ; style fld: field 600 ; -- error "Main " [ backdrop https://s-media-cache-ak0.pinimg.com/originals/87/ff/70/87ff70fec156246c5490c68eab6f3ce0.jpg below h4 "Enter some stuff:" fld h4 "Other stuff:" area 600x300 h4 "Final stuff:" area 600x100 ] "Help " [backdrop red] ] ]
select
on a hash!
, it returns the following element in constant time (while using a block! it woud be in linear time)hash!
?>> h: to-hash [a b c d e] == make hash! [a b c d e] >> select h 'd == e ; but i want to get the index of d (or of e, doesn't matter of course)
index? find h 'd
.../circle
refinement and examples to [lazy-range](https://gist.github.com/toomasv/1b1d8e859eeb1acfa230cc5357ca12fa)range!
type would still be very useful, IMO, but its utility comes back to having a literal form in some cases. Range
may not be too much to deal with, and even clearly says what you're doing.bounds
also useful themselves? Yes. e.g. case
can use them, assuming bounds are just endpoints and ranges produce filled or lazy series. That leads to the discussion of intervals open/closed ends./circle
, talk about fancy! ;^)[1 3 5 2 4 1 3 5...]
index? h/3
, what is that value?none
?Index?
throws an error. to-binary/base 255 2 -> 2#{11111111}
binary!
valuessystem/options/binary-base
might do it, but doesn't seem so. May be TBD.>> b: rejoin [2 "#{" enbase/base #{ABCD} 2 "}"] == "2#{1010101111001101}" >> load b == #{ABCD}
>> load rejoin [16 "#{" enbase/base #{ABCD} 2 "}"] == #{1010101111001101}
is
block>> x: make reactor! [ x: 5 y: is [x + 5]] == make object! [ x: 5 y: 10 ] >> x/x: 0 == 0 >> x/y == 5 >> z: make x [] == make object! [ x: 0 y: 5 ] >> z/x: 10 == 10 >> z/y == 5
z/y
to return 15/usr/bin/wine /home/max/red/red.exe --cli Z:/home/max/projects/redmap/redmap.red 2> /dev/null *** Runtime Error 1: access violation *** at: 00433D25h
is
blocks. >> r: make reactor! [x: 5 y: is [do has [z][z: 100 z + x + 5]]] == make object! [ x: 5 y: func [/local z][z: 100 z + x + 5] ] >> r/y == 110 >> r/x: 0 == 0 >> r/y == 105
fib: func [n [integer!]][ case [ n <= 2 [1] 'else [fib (n - 1) + fib (n - 2)] ] ]
fib: func [n [integer!]][ case [ n <= 2 [1] 'else [(fib n - 1) + fib n - 2] ] ]
n <= 2 [1]
should be n < 2 [n]
or you'll get 1
for fib 0
instead of 0
fib: func [n [integer!]][ case [ n <= 2 [1] 'else [(fib (n - 1)) + fib (n - 2)] ] ]
op!
s are "greedy", especially on left side.op!
s are "greedy", especially on left side.fib
is not evaluated before all the arithmetics following it is done.fib
, otherwise second fib
is consumed before first one, >> fib 5 + fib 4 + 1 == 55
fib (5 + (fib (4 + 1)))
fib n - 1 + fib n - 2
fib ((n - 1) + (fib (n - 2)))
or
as in Lisp or Java), it would be writtenfib: func [n][2 > n or add fib n - 1 fib n - 2]]
fib: func [n][any [all [n < 2 n] add fib n - 1 fib n - 2]] fib': func [n][do pick [n (add fib n - 1 fib n - 2)] n < 2] profile/show/count [[fib 15] [fib' 15]] 1'000
Count: 1000 Time | Time (Per) | Memory | Code 0:00:02.053 | 0:00:00.002 | 0 | [fib' 15] 0:00:02.067 | 0:00:00.002 | 0 | [fib 15]
numberjay: func [n [integer!]][ case [ n <= 2 [1] 'else [(fib n - 1) + fib n - 2] ] ] toomasv: func [n [integer!]][ case [ n <= 2 [1] 'else [(fib (n - 1)) + fib (n - 2)] ] ] peeps: [numberjay toomasv] foreach fellah peeps [ parse body-of get :fellah rule: [ any [ ahead any-block! into rule | to change 'fib fellah | skip ] ] ] x: 15 profile/show/count collect [ forall peeps [keep/only reduce [peeps/1 'x]] ] 1'000
Count: 1000 Time | Time (Per) | Memory | Code 0:00:00.969 | 0:00:00.001 | 0 | [numberjay x] 0:00:01.029 | 0:00:00.001 | 0 | [toomasv x]
fib': func [n][do pick [n (add fib n - 1 fib n - 2)] n < 2] >> fib' 2 == 2 >> fib' 3 == 2
|9214|: func [n [number!]] [ m: #() any [m/:n m/:n: any [all [n < 2 n] add fib n - 1 fib n - 2]]]
|9214|
in the body as well|9214|: func [n [number!]] [ m: #() any [m/:n m/:n: any [all [n < 2 n] add |9214| n - 1 |9214| n - 2]]]
foreach fellah peeps ...
doesn't ring a bell?peeps
because I'm a filthy cheater :feelsgood:, but before that parse
automatically replaced all occurrences of fib
in |9214|
with function's name (same for other functions)any/all
version is that slow :confused: toomasv: func [n][ unless value? 'sq5 [ sq5: square-root 5 a: 1 / sq5 b: (1 + sq5) / 2 k: #() ] any [k/:n k/:n: round b ** n * a] ]
Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.675 | 0:00:00 | 0 | [|9214| x] 0:00:00.935 | 0:00:00 | 0 | [toomasv x]
#(0 1)
3 => 2
should be correcttoomasv: func [z][ sq5: square-root 5 a: 1 / sq5 b: (1 + sq5) / 2 k: make map! z repeat n z [k/:n: round b ** n * a] ] toomasv 10 probe k #( 1 1.0 2 1.0 3 2.0 4 3.0 5 5.0 6 8.0 7 13.0 8 21.0 9 34.0 10 55.0 )
context [m: #() set 'fib func [n [number!]] [ any [m/:n m/:n: any [all [n < 2 n] add fib n - 1 fib n - 2]]]]
Red [Needs: 'View] myview: layout [ button {Click to "unview"} [unview] ] view/options/no-wait myview [offset: 30x100] wait 1 view/options myview [offset: 400x100]
text view/no-wait/options [text "this"][offset: 300x300] view/no-wait/options [text "that"][offset: 400x400]
layout
you'd better pass same VID block twicetext my-view: [button {click to "unview"} [unview]] view/options/no-wait my-view [offset: 30x100] view/options/no-wait my-view [offset: 400x100]
layout
even needed in Red? or is it there just for the sake of Rebol compatibility? view
, which can do the same thing automatically if you'd passed just a VID block to itview
constructs tree of faces from VID description **and** displays it as GUI, while layout
constructs tree of faces but doesn't display anything, that should be enough for a beginner- pos: change pos value + pos: insert remove pos value
change
and insert remove
have the same effect ?!? Or am I missing something?change
ing with empty string doesn't advance series! position, same for R2 & Red, see the below code:>> head change find "test" "e" "" == "test"
change
that we need to be careful about:>> head change find "test" "e" "xy" == "txyt" ; s also replaced >> head insert remove find "test" "e" "xy" == "txyst" ; s is not replaced
change
needs much more explanation.block!
s as well, if /only
is not used:>> head change find ["t" "e" "s" "t"] "e" ["x" "y"] == ["t" "x" "y" "t"] >> head change/only find ["t" "e" "s" "t"] "e" ["x" "y"] == ["t" ["x" "y"] "s" "t"]
>> head change/part find "test" "e" "xy" 1 == "txyst" >> head insert remove find "test" "e" "xy" == "txyst"
>> head change find "test" "e" "xy" == "txyt" >> head insert remove/part find "test" "e" 2 "xy" == "txyt"
change/part
with 1
. It also works a bit faster:>> profile/show/count [_change_ _insert_] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:01.832 | 0:00:00 | 43913216 | _change_ 0:00:02.094 | 0:00:00 | 46014464 | _insert_
>> head insert remove find "test" "est" "o" == "tost" >> head change find "test" "est" "o" == "tost" >> head insert remove/part find "test" "est" 3 "o" == "to" >> head change/part find "test" "est" "o" 3 == "to"
remove
removes by default just on item, or number of items determined by /part
.change
changes by default the length of replacement value, or the number of items determined by /part
.replace
instead:>> replace "test" "est" "o" == "to" >> replace "test" "e" "xy" == "txyst"
foreach b block [to-string b]
doesn't workhead remove back tail remove mold [1 2 3] == "1 2 3"
form [1 2 3] == "1 2 3"
blk: [1 2 3] head forall blk [change blk to-string blk/1] == ["1" "2" "3"]
map
func to help with this kind of thing in general.change-all: func [ "Change each value in the series by applying a function to it" series [series!] fn [any-function!] "Function that takes one arg" ][ forall series [change series fn first series] series ]
ch-dig-to-int: func [ch [char!]][to integer! ch - 48]
change-all
will do that.change-all
is generalisation of this.[
you think, Ah! I'm starting a block, and everything up to ]
will go in it. Next you see 1
. Ha! That's an integer, easy. Slot 1 of the block I'm collecting will refer to that. Next comes "abc"
. Oooh, now I need to handle a string, then maybe a word, path, or paren. Computer Science Logo Style
series is also great.Turtles, Termites, and Traffic James
by Mitch Resnick is also great.change-all
is vulnerable to functions that return a block with more than 1 elements. As discussed above, change
tries then to change as many elements as length of block returned from provided function... aaannd gets confused. Maybe change/part ... 1
helps? change/only
, yes?sum-f: func [blk][either tail? blk [0][blk/1 + sum-f next blk]] sum-i: function [blk][s: 0 forall blk [s: s + blk/1]]
sum-i
yields the desired result is not so obvious, though, and relies on the fact that the result of forall
is the last result computed in its body. Inserting s
before the last ]
would be helpful as documentation, so to speak.sum
as a first example as well @toomasv. Same brains it seems. :^)remove-each
, and note that it doesn't return a value.sum
should be a builtin.map
Red [needs: 'view] v1: view/options/no-wait [ backdrop blue button "unview blue"[unview v1] button "unview yellow" [unview v2] ] [offset: 30x100] ;options v2: view/options/no-wait [ backdrop yellow button "unview blue"[unview v1] button "unview yellow" [unview v2] ] [offset: 400x100] ;options
/only
option?unview
the result of view
, which probably is unset
][
on the same lineview1: layout/options [button {click to "unview"} [unview/only view1]][offset: 30x100] view2: layout/options [button {click to "unview"} [unview/only view2]][offset: 400x100] show reduce [view1 view2]
v1: layout/options [ backdrop blue button "Unview blue" [unview/only v1] button "Unview yellow" [unview/only v2] ][offset: 400x100] v2: layout/options [ backdrop yellow button "Unview blue" [unview/only v1] button "Unview yellow" [unview/only v2] ][offset: 30x100] show reduce [v1 v2]
[4 1 3 1 2 1]
, how to remove all of the 1
s?difference
, if you don't need to do that on the same block, or if you need a copy>> difference [4 1 3 1 2 1] [1] == [4 3 2]
only
refinement. It works fine now if run from notepadd++, but if I cut and paste to the console it shows only one window at a time. I don't know why.>> blk: [4 1 3 1 2 1] == [4 1 3 1 2 1] >> exclude blk [1] == [4 3 2] >> also blk parse blk [some [remove quote 1 | skip]] == [4 3 2] >> blk: [4 1 3 1 2 1] == [4 1 3 1 2 1] >> also blk remove-each item blk [item = 1] == [4 3 2]
exclude
. I've probably seen exclude
and difference
before but my memory is a hit or miss these days>> ? "data set" difference native! Returns the special difference of two data sets. exclude native! Returns the first data set less the second data set. intersect native! Returns the intersection of two data sets. union native! Returns the union of two data sets. unique native! Returns the data set with duplicates removed.
sum-f: func [blk][either tail? blk [0][blk/1 + sum-f next blk]] sum-i: function [blk][s: 0 forall blk [s: s + blk/1]]
forall
in this case would be fold
also known as accumulate
(longer to type) or reduce
(already taken in Red with totally different meaning)fold: function [f v b] [ either empty? b [v] [fold :f f v first b next b]]
sum-f: func [blk] [fold :add 0 blk] sum-i: function [blk][s: 0 forall blk [s: s + blk/1]]
text >> block: collect/into [repeat i 9 [keep reduce ['+ i]]][0] == [0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9] >> do block == 45
do
itmap
stands for? text >> ?? map map: func [series spec body][collect [foreach :spec series [keep do reduce compose [func spec body (:spec)]]]]
append
can't be functionalmeta-add: function [a b] [compose [(a) + (b)]] func [blk] [do fold :meta-add 0 blk]
text func [blk][do compose [(map blk [x][reduce [x '+]]) 0]]
forall
, foreach
, etc. would become fold
, map
etc. and the 'summing' function would generate code as data instead of executing itdo
of course)>> map: function [f b] [either empty? b [b] [append reduce [f first b] map :f next b]] == func [f b][either empty? b [b] [append reduce [f first b] map :f next b]] >> map :square-root [10 20 30] == [3.16227766016838 4.47213595499958 5.477225575051661]
map2
to use like thismap2 :add [1 2 3] [10 20 30]
[11 22 33]
)map
s for that[[1 2 3][10 20 30]]
map
a 1-ary function on a block, but there's no reason in principle why we should not map
an n-ary function on n blocks[11 22 33]
from [[1 2 3][10 20 30]]
nesting map
?map
to take a block of blocks and do the right thing[foo /local bar]
map [1 2 3 4][x y][x + y]
map
is interesting, probably should get its own namethis
or self
or recur
or recurse
and so on)map [[1 2 3] [10 20 30]] [x y] [either any [empty? x empty? y] [[]] [append reduce [(first x) + first y] recurse next x next y]]
[11 22 33]
text >> foo: func [x][unless x = 0 [probe x do reduce [context? 'x x - 1]]] == func [x][unless x = 0 [probe x do reduce [context? 'x x - 1]]] >> foo 5 5 4 3 2 1 == none
map
, and as a generalization of the usual map
, it would probably be useful in a language like Red (fixed arity) if map
would behave like>> map :add [1 2 3 4 5] == [3 5 7 9]
x
word is a function to which it is bound (foo
), that way you can call a function without mentioning its name>> map [[1 2 3] [10 20 30]] [x y] [either any [empty? x empty? y] [[]] [append reduce [(first x) + first y] do reduce [context? 'x next x next y]]] == [11 22 33]
*-each
style (like remove-each
). Almost certainly the series will be the first arg, rather than the function, as that's the Red standard approach. They open up a lot of detail questions (e.g., regarding unset!
results), and we can consider extended versions.; JS-like MAP. The order of args to the function is a bit odd, but is set ; up that way because we always want at least the value (if your func takes ; only one arg), the next most useful arg is the index, as you may display ; progress, and the series is there to give you complete control and match ; how JS does it. Now, should the series value be passed as the head of the ; series, or the current index, using AT? ; This is *sort of* like map-indexed in Clojure. map-js: func [ "Evaluates a function for all values in a series and returns the results." series [series!] fn [any-function!] "Function to perform on each value; called with value, index, series, [? and size ?] args" ;/only "Collect block types as single values" ;/skip "Treat the series as fixed size records" ; size [integer!] ][ collect [ repeat i length? series [ ; use FORSKIP if we want to support /SKIP. keep/only fn series/:i :i :series ;:size ] ] ] res: map-js [1 2 3 a b c #d #e #f] :form res: map-js [1 2 3 a b c #d #e #f] func [v i] [reduce [i v]] res: map-js [1 2 3 a b c #d #e #f] func [v i s] [reduce [i v s]] res: map-js "Hello World!" func [v i s] [pick s i] res: map-js "Hello World!" func [v] [either v = #"o" [1][0]] ; sum result = count res: map-js "Hello World!" func [v i] [if v = #"o" [i]] ; remove none! values to keep only index values res: map-js "Hello World!" func [v i s] [if v = #"o" [at s i]] ; remove none! values to keep only series offsets
Map-each
could basically look like this:map-each: function [ "Evaluates body for each value in a series, returning all results." 'word [word! block!] "Word, or words, to set on each iteration" data [series!] ; map! body [block!] ][ collect [ foreach :word data [ keep/only do body ] ] ] map-each v [1 2 3] [2 * v] map-each v "IBM" [v - 1] ;map-each [k v] #(a 1 b 2 c 3) [append form v k] map-each x [1 2 3 4 5] [either even? x [continue] [x]] map-each x [1 2 3 4 5] [either even? x [break] [x]]
keep
can't take unset!
vals, so need to change that or use a different approach.Fold/accumulate
opens similar questions. >> acc: make reactor! [total: 0 this: 0 total: is [total + this]] == make object! [ total: 0 this: 0 ] >> blk: [1 2 3 4 5 6 7 8 9] == [1 2 3 4 5 6 7 8 9] >> forall blk bind [this: first blk] acc == 9 >> acc/total == 45
total
twice?>> print mold/all acc make object! [ on-change*: func [word old new /local srs ][ if system/reactivity/debug? [ print [ "-- on-change event --" lf tab "word :" word lf tab "old :" type? :old lf tab "new :" type? :new ] ] all [ not empty? srs: system/reactivity/source srs/1 = self srs/2 = word set-quiet in self word old exit ] unless all [block? :old block? :new same? head :old head :new] [ if any [series? :old object? :old] [modify old 'owned none] if any [series? :new object? :new] [modify new 'owned reduce [self word]] ] system/reactivity/check/only self word ] total: 0 this: 0 ]
1:--- Source: object [total this] Field: total Action: [total + this] Target: total 2:--- Source: object [total this] Field: this Action: [total + this] Target: total
dump-reactions
in there somehow.sprintf(s, "%02d", x)
rejoin pick [["0" x] ["" x]] (x < 10)
pad/left/with 1 2 #"0"
printy: func [val length][pad/left/with length val #"0"]
tab-panel
described in block out of view
?panel01: [text "123"] view [ tab-panel 200x100 [ "pan1:" panel01 ] ]
compose/deep
to inject that value in the nested block.panel01: [text "123"] view compose/deep [ tab-panel 200x100 [ "pan1:" (panel01) ] ]
Script Error: VID - invalid syntax at: [["tab-panel2"]
error on my forms editor over line 245 using lasts builds. For now I am too busy to investigate, this weekend will try to fix.view [c: camera 100x100 button "show" [c/selected: 1]]
view [camera select 1]
>> l: layout [my-text: text "howdy"] == make object! [ type: 'window offset: none size: 100x44 text:... >> l/pane/1 == make object! [ type: 'text offset: 10x10 size: 80x24 text: "... >> to word! first back find body-of system/words l/pane/1 == my-text
what's-my-name?
issue as with any value, but there *is* value in knowing at least *one* name that refers to something, especially when doing things like data binding in UIs. 0.6.4
code branch?tab-panel 200x200 [ "TAB1" [...] "TAB2" [...] ]
There is only a little adjust to do.replace/all
with a parse pattern? Let's say you want to replace in a string either of . , ;
with an empty string (""
).replace/all "a.b,c;d" charset ".,;" ""
>> replace/all "this is a phrase, very very long phrase; period." [#"." | #"," | #";"] #"!" == "this is a phrase, very very long phrase; period."
replace
example with a parse rule pattern it would be interesting to see.parse
rule only with /deep
refinement, and turns out it doesn't really work on strings>> replace/deep [1 2 3][some integer!] 'poop == [poop]
cs: charset ".,;-!" replace/all mylongstring cs ""
replace/all mylongstring charset ".,;-!" ""
parse my-string [some [change [";" | "."] "!" | skip]]
add
subtract
etc. and as such they obey the left to right rule. Is that what you mean or infix have some property I'm not aware of?2
subtract 3 add 2 1
and therefore obey the left to right rule? I think my logic is right, I'm just not sure I conveyed the message clearly in the notebook note. add subtract 3 2 1
?subtract 3 2
is equivalent to 3 - 2
, hence subtract 3 2 + 1
is the same as 3 - 2 + 1
, which is wrongsubtract
is evaluated first, then add
, because it's a chained call, but in equivalent subtract 3 2 + 1
, +
operator takes the turn first, and only then subtract
is applied on two arguments, which doesn't strictly follow left-to-right ordersubtract 3 2 + 1
subtract
is a word, it is bounded to a system/words
context and have a value of a function that takes 2 arguments that follows it, so, I gonna take this two arguments...3
, it's an integer, and it's the first argument.2
, it's an integer too, and it must be the second argument...+
follows strict left-to-right order (which I think you meant), then at this step subtract
just should take 3
and 2
and give you 1
. But that's not the case, because +
butts in and says:2
, in turn, is the leftmost argument in 2 + 1
expression, and it should be evaluated first to 3
, and 3
then, indeed, is the second argument for subtract
.op!
evaluates before function!
, it's hard to say what's the result of subtract 3 2 + 1
.(subtract 3 2) + 1
or subtract 3 (2 + 1)
(which is the case simply because of design choice)?op!
subtract 3 2 + 1
is evaluated as (subtract 3 2) + 1
function!
vs op!
. Namely to take into account comparisons. Consider these:>> 1 + 2 = -1 + 4 *** Script Error: + does not allow logic! for its value1 argument *** Where: + *** Stack: >> 1 + 2 = (-1 + 4) == true
>> equal? 1 + 2 -1 + 4 == true
>> ((1 + 2) = -1) + 4 *** Script Error: + does not allow logic! for its value1 argument *** Where: + *** Stack:
op!
"jumps over" the leftmost value/parens and transforms into function, while following normal order of evaluation:1 + 2 = -1 + 4 + 1 2 = -1 + 4 3 = -1 + 4 = 3 -1 + 4 false + 4 + false 4 ; caboom
op!
ahead closer to it :sparkles: op!
isn't a syntactic sugar for dyadic functions, they have quite limited scope, in a sence that they don't allow refinements and quoted words in their specs/local
is allowed :smile_cat: [and or not is]
. Of course, we can make our own as well (https://github.com/red/red/wiki/Guru-Meditations#define-infix-operators). square-root 16 + square-root 16
is not 8. Actually I wrote that chapter exactly because I got this question in private.square-root
demands its rights on the rightmost 16
, but since +
has precedence, it beats square-root
and takes 16
, not seeing any value or parenthesis on the right side, it kindly asks rightmost square-root
to compute something, and square-root
yields 4
, which +
uses to do 16 + 4
, what's left is trivial
bit being the key. make-range: function [a [integer!] b [integer!]][ collect [i: a - 1 until [keep i: i + 1 i = b]] ] ->: make op! :make-range f7: does [7] 2 -> 7 2 -> f7 2 -> add 3 4
apply: function [a [integer!] f [function!]][ f a ] ->: make op! :apply mul-2: func [n][n * 2] 2 -> :mul-2 2 -> mul-2
mul-2
is evaluated (and fails) without triggering a type error in the op. i.e., no special op mechanics involved.op!
s "assymetry"?sine 90 + square-root 16
(sine 90) + (square-root 16)
?sine (90 + square-root 16)
op!
s are right-handed personslit-word!
args. Beyond beginner material, but something to note.>> apply: function [a [integer!] 'f][ [ print [f a] [ ] == func [a [integer!] 'f][print [f a]] >> ->: make op! :apply == make op! [[a [integer!] 'f]] >> >> mul-2: func [n][n * 2] == func [n][n * 2] >> 2 -> :mul-2 4 >> 2 -> mul-2 *** Script Error: mul-2 is missing its n argument *** Where: mul-2 *** Stack: mul-2 >> apply 2 mul-2 mul-2 2 >> 2 -> 'mul-2 mul-2 2
/local
refinements are restrictedsine 90
and not see a single thing to be evaluated.+
, which implies that it should have processed and "postponed" sin 90
, then if +
takes sin 90
, shouldn't it evaluation be postponed again, and again..?op!
s don't have precedence, which is falsesquare-root 2 + 2 + square-root 3 * 3 * square-root 1 + 4 * 5
square-root 4 + square-root 9 * square-root 5 * 5
square-root 7 * square-root 25
square-root 35 ;wrong answer
>> square-root 2 + 2 + square-root 3 * 3 * square-root 1 + 4 * 5 == 3.272339214155429 >> square-root ((2 + 2) + (square-root ((3 * 3) * (square-root ((1 + 4) * 5))))) == 3.272339214155429
square-root (2 + 2) + ; + needs a value here, so evaluates square-root (3 * 3) * ; * needs a value here, so evaluates square-root (1 + 4 * 5)
square-root 4 + square-root 9 * ...
as being equal to square-root 7 * square-root n
, *
has not finished evaluating yet.find/tail
and use that as the starting point for another find
call, or you could use parse
.sort
.sort/stable
, but still, if they're equal it doesn't matter.2 4 1 2
is encountered, exit loopappend/only
but it isn't working outbanks: [0 2 7 0] bucket: index: cycles: 0 find-largest-bank: func [b][last sort copy b] state-table: [] until [ wait 2 index: index? find banks find-largest-bank banks banks: skip banks index - 1 bucket: bucket + banks/1 banks/1: 0 repeat i bucket [ banks: next banks if tail? banks [banks: head banks] banks/1: banks/1 + 1 bucket: bucket - 1 ] banks: head banks print ["banks" banks] cycles: cycles + 1 find/only state-table banks;- Not sure how to test for duplicate ]
append/only state-table banks
line so that it runssub: find/tail/only state-table banks ; first match if find/only sub banks [break] ; second match
banks: [0 5 10 0 11 14 13 4 11 8 8 7 1 4 12 11] bucket: index: cycles: 0 find-largest-bank: func [b][last sort copy b] state-table: [] forever [ index: index? find banks find-largest-bank banks banks: skip banks index - 1 bucket: bucket + banks/1 banks/1: 0 repeat i bucket [ banks: next banks if tail? banks [banks: head banks] banks/1: banks/1 + 1 bucket: bucket - 1 ] banks: head banks repend/only state-table banks cycles: cycles + 1 sub: find/tail/only state-table banks ; first match if find/only sub banks [break] ; second match ]
square-root 4 + square-root 9 * square-root 5 * 5
square-root 7 * square-root 25
square-root 4 + square-root 9 * square-root 5 * 5 square-root 4 + square-root 9 * square-root 25 square-root 4 + square-root 9 * 5 square-root 4 + square-root 45 square-root 4 + 6.7 square-root 10.7 3.27
Red [] a: make deep-reactor! [z: [x: ""]] ;reactor object - triggers changes b: object [w: is [a/z/x]] ;second object - changes when 'a' changes forever[ a/z/x: ask "?" ;here we input a value for a part of a print a/z/x ;here we print a to make sure it is changed print b ;b should change, but it doesn't! ]
0.6.3
versionon-change*
function of a face object?>> print mold/all deep-reactor! make object! [ on-change*: func [word old new /local srs ][ if system/reactivity/debug? [ print [ "-- on-change event --" lf tab "word :" word lf tab "old :" type? :old lf tab "new :" type? :new ] ] all [ not empty? srs: system/reactivity/source srs/1 = self srs/2 = word set-quiet in self word old exit ] unless all [block? :old block? :new same? head :old head :new] [ if any [series? :old object? :old] [modify old 'owned none] if any [series? :new object? :new] [modify new 'owned reduce [self word]] ] system/reactivity/check/only self word ] on-deep-change*: func [owner word target action new index part][ system/reactivity/check/only owner word ] ]
on-change*
isn't used for face objects. Is there another way to monitor all chages made to a face?on-change*
isn't used for face objects>> print mold/all face!
system/reactivity/debug?
flagsystem/view/screens/1/pane/-1
is the GUI console window, so you can set its size and offset via that path. Just tried here and it works.square-root (2 + 2) + ; + needs a value here, so evaluates square-root (3 * 3) * ; * needs a value here, so evaluates square-root (1 + 4 * 5)
>> x: {Räksmörgås, Räksmörgås. Räksmörgås;} == "Räksmörgås, Räksmörgås. Räksmörgås;" >> cs: charset ",.;" == make bitset! #{00000000000A0010} >> replace/all x cs "" == "Rksmrgås Rksmrgås Rksmrgås"
>> x: "Räksmörgås, Räksmörgås. Räksmörgås;" == "Räksmörgås, Räksmörgås. Räksmörgås;" >> cs: charset ",.;" == make bitset! #{00000000000A0010} >> replace/all x cs "" == "Rksmrgs Rksmrgs Rksmrgs"
>> x: {Rksmörgs, Rksmörgs. Rksmörgs;} ;<--- I actually pasted: x: {Räksmörgås, Räksmörgås. Räksmörgås;} == "Rksmörgs, Rksmörgs. Rksmörgs;"
>> x: {Räksmörgås, Räksmörgås. Räksmörgås;} == "Räksmörgås, Räksmörgås. Räksmörgås;" >> replace/all x charset ",.;" "" == "Räksmörgås Räksmörgås Räksmörgås"
>> x: {Räksmörgås, Räksmörgås. Räksmörgås;} == "Räksmörgås, Räksmörgås. Räksmörgås;" >> cs: charset ",.;" == make bitset! #{00000000000A0010} >> replace/all x cs "" == "Rksmrgs Rksmrgs Rksmrgs"
>> x: {Räksmörgås, Räksmörgås. Räksmörgås;} == "Räksmörgås, Räksmörgås. Räksmörgås;" >> xs: charset ",.;" == make bitset! #{ 0000000000500008000000000000000000000000000000000000000000000000 } >> replace/all copy x xs "" == "Räksmörgås Räksmörgås Räksmörgås"
>>
as a prompt...text >> x: {Räksmörgås, Räksmörgås. Räksmörgås;} == "Räksmörgås, Räksmörgås. Räksmörgås;" >> xs: charset ",.;" == make bitset! #{00000000000A0010} >> parse x [some [to change xs "" | thru end]] == true >> x == "Räksmörgås Räksmörgås Räksmörgås"
replace
version should work too./deep
which relies on parse
>> x: {Räksmörgås, Räksmörgås. Räksmörgås;} == "Räksmörgås, Räksmörgås. Räksmörgås;" >> xs: charset ",.;" == make bitset! #{00000000000A0010} >> replace/deep/all x xs "" == "Rksmörgs Rksmörgs Rksmörgs" >> x: {Räksmörgås, Räksmörgås. Räksmörgås;} == "Räksmörgås, Räksmörgås. Räksmörgås;" >> replace/deep/all x charset ",.;" "" == "Räksmörgås Räksmörgås Räksmörgås"
>> do/args %red.r "-r %environment/console/gui-console.red"
-t Windows
-t MSDOS
)-r
automatically picks a platform there compilation is runningsystem/script/arguments
.Red [] print system/script/args
$ ./test hello command line arguments hello command line arguments
db: ["123" "456" "789"] view [ lst: text-list 200x100 data db on-select [print lst/selected] ]
select
occurs when an entry in the list is selected. selected
facet refers to **old** selected entry index.-t windows
? If so, you shouldn't get that console window.text >> x: {Räksmörgås, Räksmörgås. Räksmörgås;} == "Räksmörgås, Räksmörgås. Räksmörgås;" >> xs: charset ",.;" == make bitset! #{00000000000A0010} >> replace/all x xs "" == "Rksmörgås Rksmörgås Rksmörgås" >> about Red for Windows version 0.6.3 built 12-Dec-2017/16:15:28+05:00
>> x: {Räksmörgås, Räksmörgås. Räksmörgås;} == "Räksmörgås, Räksmörgås. Räksmörgås;" >> replace/all x charset ",.;" "" == "Räksmörgås Räksmörgås Räksmörgås"
gen
functions.gen1
and gen2
:context [value: none inner: does [value: value + 1] set 'gen1 func [val][value: val :inner]] gen2: function [val][context [value: val return does [value: value + 1]]]
>> f1: gen1 0 == func [][value: value + 1] >> g1: gen1 0 == func [][value: value + 1] >> f1 == 1 >> f1 == 2 >> g1 == 3 >> f1 == 4
>> f2: gen2 0 == func [][value: value + 1] >> g2: gen2 0 == func [][value: value + 1] >> f2 == 1 >> f2 == 2 >> f2 == 3 >> g2 == 1 >> g2 == 2 >> g2 == 3
closure: func [vars spec body][ ; Don't have to reuse 'spec name; just saves a word. bind (body-of spec: func spec body) (context vars) :spec ] gen3: closure [var: 0] [] [var: var + 1]
closure
func. @JacobGood1 did one as well, which we pared down to func spec bind body context vars
, but then there was the tiny detail related to binding, that led Doc to produce the above. vars
block. I'd like to try revisiting the generator stuff using that, as it looks way stronger than what I was doing.yield
merge: func ["Merge block" b [block!] /with c /quot /local s v][c: any [c ","] if quot [c: rejoin ["'" c "'"]] s: copy "" s: head clear skip foreach v b [insert tail s rejoin [form v c]] negate length? c if quot [ s: rejoin ["'" s "'"] ] s ] >> merge/with [1 2 3] ".." == "1..2..3" >> merge/quot [1 2 3] == "'1,'2','3'"
modified?
function?/with
refinement to rejoin
. I have a general delimit
func that works on any series, so you can then rejoin
the result if you want a string. I have some other, old *-dlm-str
funcs, which is another way we can look at it. >> f3: closure [var: 0] [] [var: var + 1] == func [][var: var + 1] >> g3: closure [var: 0] [] [var: var + 1] == func [][var: var + 1] >> f3 == 1 >> f3 == 2 >> f3 == 3 >> g3 == 1 >> g3 == 2 >> f3 == 4
context [var: 0 return func [][var: var + 1]]
gen
*per se*, but a more general question about reusage of contexts. Consider for example these two versions of ring
: [ring.red](https://gist.github.com/toomasv/6a530ebc8cbb48a273d1cc449d8f204d) and [ring2.red](https://gist.github.com/toomasv/c3bc1a1a9fbb484f31b04ca771ba9578). gen3
shouldn't be making the function each time. But let's see if there's a visible difference. I added gen4
closure which takes an arg like yours, to compare as well.>> profile/count/show [[gen1 1] [gen2 2] [gen3] [gen4 4]] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.234 | 0:00:00 | 0 | [gen1 1] 0:00:00.288 | 0:00:00 | 0 | [gen3] 0:00:00.318 | 0:00:00 | 0 | [gen4 4] 0:00:02.103 | 0:00:00 | 639045632 | [gen2 2]
gen4
?gen4: closure [var: 0] [n] [var: var + 1]
gen3
?!>> ? :gen2 func [val /local value][context [value: val return does [value: value + 1]]] >> ? :gen3 func [][var: var + 1]
>> profile/count/show [[gen1 1] [gen2 2] [g2] [gen3] [gen4 4]] 1000000 Count: 1000000 Time | Time (Per) | Memory | Code 0:00:00.323 | 0:00:00 | 0 | [gen1 1] 0:00:00.381 | 0:00:00 | 0 | [g2] 0:00:00.42 | 0:00:00 | 0 | [gen4 4] 0:00:00.451 | 0:00:00 | 0 | [gen3] 0:00:02.242 | 0:00:00 | 638963712 | [gen2 2]
ring
stuff in a bit.gen2
uses a lot of memory.copy/part s 10
closure
with "boiled down" version of it and here is what I found:closure: func [vars spec body][ bind (body-of spec: func spec body) (context vars) :spec ] gen3: [closure [var: 0] [] [var: var + 1]] ctx: [context [var: 0 return func [][var: var + 1]]]
f-gen3: do gen3 g-gen3: do gen3 >> f-gen3 == 1 >> f-gen3 == 2 >> g-gen3 == 1 f-ctx: do ctx g-ctx: do ctx >> f-ctx == 1 >> f-ctx == 2 >> g-ctx == 1
>> profile/count/show [[do gen3][do ctx]] 100000 Count: 100000 Time | Time (Per) | Memory | Code 0:00:00.179 | 0:00:00 | 59084800 | [do ctx] 0:00:00.249 | 0:00:00 | 64106496 | [do gen3] >> profile/count/show [[do gen3][do ctx]] 100000 Count: 100000 Time | Time (Per) | Memory | Code 0:00:00.184 | 0:00:00 | 59084800 | [do ctx] 0:00:00.261 | 0:00:00 | 64106496 | [do gen3] >> profile/count/show [[do gen3][do ctx]] 100000 Count: 100000 Time | Time (Per) | Memory | Code 0:00:00.193 | 0:00:00 | 59084800 | [do ctx] 0:00:00.268 | 0:00:00 | 64106496 | [do gen3]
actors
facetactors
facet I see handlers what used in script. In documentation only one handler for area
- on-change
.on-enter
.system/view/evt-names
text >> probe extract system/view/evt-names 2 make hash! [ detect time drawing scroll down up mid-down mid-up alt-down alt-up aux-down aux-up wheel drag-start drag drop click dbl-click over key key-down key-up ime focus unfocus select change enter menu close move resize moving resizing zoom pan rotate two-tap press-tap create created ]
ime
is not a typoif event/key = #"x"
and for enter? #"^/" don't work.map!
by (highest) number then string?x: #("aa" 3 "ab" 3 "cc" 9 "dd" 5 "de" 4)
parse/all
is the same as Red parse
, but Red version is more powerful than R2, it's closer to R3hash!
>> blk: ["aa" 3 "ab" 3 "cc" 9 "dd" 5 "de" 4] == ["aa" 3 "ab" 3 "cc" 9 "dd" 5 "de" 4] >> sort/skip/compare blk 2 2 == ["aa" 3 "ab" 3 "de" 4 "dd" 5 "cc" 9]
>> sort/skip/reverse/compare sort/skip/reverse to-block x 2 2 2 == ["cc" 9 "dd" 5 "de" 4 "ab" 3 "aa" 3] >> sort/skip/reverse/compare sort/skip to-block x 2 2 2 == ["cc" 9 "dd" 5 "de" 4 "aa" 3 "ab" 3]
>> sort/skip/compare/all to-block x 2 func [a b][either a/2 = b/2 [a/1 < b/1][a/2 > b/2]] == ["cc" 9 "dd" 5 "de" 4 "aa" 3 "ab" 3] >> sort/skip/compare/all to-block x 2 func [a b][either a/2 = b/2 [a/1 > b/1][a/2 > b/2]] == ["cc" 9 "dd" 5 "de" 4 "ab" 3 "aa" 3]
x: #("aa" 3 "ab" 3 "cc" 9 "dd" 5 "de" 4) y: [] foreach i keys-of x [ append y reduce [(select x i) i] ] sort/skip/reverse y 2
map!
preserves the order of the arguments, so you may end up with the same map!
view [area on-key [print mold event/key]]
That will show you the value the enter key generates in the handler. Then if you do ? char!
in the console, you'll see that you were checking for LF, not CR.sort/skip/compare/all to-block x 2 func [a b][either a/2 = b/2 [a/1 < b/1][a/2 > b/2]]
dir-Resources: normalize-dir rejoin [ system/options/path first split-path to-file system/options/boot %../Resources ]
closure
is generalized? That is, sub/compose in args, rather than hard-coding, yes?close-ctx: func [vars spec body][ context [ (vars) return func (spec) (body) ] ]
call "notepad.exe"
nothing happenscall/show "notepad.exe"
notepad openscall "red-063.exe"
Red's console openscall/shell "notepad.exe"
seems to also open notepadcall
just kind of "type" my text to the shell?call
normally runs a process in the background, so if you need to show it you need /show
.notepad.exe
IS a Windows application, but red-063.exe
is a MSDOS application (well, not a real MSDOS of course, but it is not a GUI application)-t Windows
, otherwise you need to fiddle with Windows API to hide that window or change its parameters["a" "b" "c" "d" "e"]
.x: { a? b , c . d; e } replace/all x charset ",.;?" "" trim/lines x x: split x " "
form
x before splitting, it cleans that up.write
that one unless you want the machine to shutdown without askingx
function, but print
returns unset!
write
write %x.txt :x
write/append
. I guess it depends on what you are going to do with it later. There is also save
, though I don't really know how it differs from just write
, but I think it does some additional things...save
as the opposite of load
, though save
and write
may work almost the same in some cases, they have different refinements that go along with their primary purpose.write
should work the way it does. If it didn't, how would you write anything except literal values?Red [title: "Simple Menu" needs: 'view] window: layout [ ] window/menu: [ "File" [ "Test" test ] ] window/actors: make object! [ on-menu: func [face [object!] event [event!]][ if event/picked = 'test [print "Test"] ] ] view window
text view/options [on-menu [if event/picked = 'test [print "Test"]]][menu: ["File" ["Test" test]]]
write
ing out a Red program or script{ }
it works outmold
it: write %file.txt mold :f
or simply write %file :f
but not write %file f
which executes f
.func [val][val + 1]
to filewrite %a.txt {add1: func [val][val + 1]}
willdefinition of a function
, means the body of the function. Second example, you are writing simply a string to a file.write
might suppress evaluation, so that I could write write %test.txt add1
write
might suppress evaluation, so that I could write write %test.txt add1
write %test.txt add1
writes the result of add1
write
to file, it has to be wrapped in a block or a string. lf
with parse. (Using a leftover text file from code challenge)input: load %my-file.txt
>> parse input [some [thru '-> copy word to end]] == true >> word == [rjzvwv noybkx dvkug (90) -> tbjbz gxnvl meeiw (95) iaibv (52) ckddz ...
to newline
text input: next { pbga (66) xhth (57) ebii (61) havc (66) ktlj (57) fwft (72) -> ktlj, cntj, xhth qoyq (66) padx (45) -> pbga, havc, qoyq tknk (41) -> ugml, padx, fwft jptl (61) ugml (68) -> gyxo, ebii, jptl gyxo (61) cntj (57) } probe parse input [ collect [ some [ thru [ ["->" space] keep to newline | end ] ] ] ]
load
ing your file and all the strings become word!
s, but in @9214 's example he parses a string directly without loading it.read
the file not load
it.word!
?load
there is no newline
characters anymore, it becomes a block! of word!s and value!s (like integers etc.)parse
keywordto newline
in you parse block.load
every string, it should be meaningful for Red. Should be loadable:>> load { ' } *** Syntax Error: invalid value at "'" *** Where: do *** Stack: load >> type? load { 'Hi } == lit-word! ;not a string >> load { 3*5 } *** Syntax Error: invalid integer! at "3*5" *** Where: do *** Stack: load >> load { 3 * 5 } == [3 * 5]
collect
into two blocks simultaneously?parse
thoughcopy
and keep
where neededword!
collect set
in order to collect into two blocks?parse [1 2] [some [set x integer! (probe x)]]
>> parse b: [1 2] [some [p: integer! (change p form first p)]] b ; == ["1" "2"]
parse b: ["1" "2"] [some [p: string! (change p load first p)]]
:mark
not necessary in this example?str: "at this time, I'd like to see the time change" parse str [ some [to "time" mark: (remove/part mark 4 mark: insert mark now/time) :mark ] ] print str
text >> str: "at this time, I'd like to see the time change" == "at this time, I'd like to see the time change" >> also str parse str [to change "time" (now/time) thru end] == "at this 13:21:53, I'd like to see the time change"
parse
looking at R2 examples is not a good idea IMOtext >> also str parse str [some [to change "time" (now/time)] thru end] == {at this 13:23:43, I'd like to see the 13:23:43 change}
copy/part str 10
. Not more clear if they stand right after command? As this: copy/part 10 str
? Because if str
big evaluated block - hard to understand what variable for what command.copy
and copy/part
require series!
as their first argument/part
requires second argument which should come right after the main one>> f: func [arg1 /ref arg2][print ["Args:" arg1 arg2]] == func [arg1 /ref arg2][print ["Args:" arg1 arg2]] >> f 1 Args: 1 none >> f/ref 1 2 Args: 1 2
>> f: func [arg1 /ref arg2 /local t][if ref [t: arg1 arg1: arg2 arg2: t] print ["Args:" arg1 arg2]] == func [arg1 /ref arg2 /local t][if ref [t: arg1 arg1: arg2 arg2: t] print ["Args:" arg1 arg2]] >> f 1 Args: 1 none >> f/ref 1 2 Args: 2 1
f: func [/ref arg2 /local t arg1]
?arg1
as local wordreplace/all copy/part skip db/:i 21 10 "^/" " "
replace/all "^/" " " copy/part 10 skip 21 db/:i
[a,b,c].include?(a)
in red?find
found?
function in Rebol:found?: func [ "Returns TRUE if value is not NONE." value ][ not none? :value ] >> found? find "abcdef" "cd" == true
collect
into two blocks simultaneously?save
(/all
not required generally). If you're generating other code, you'll probably use write
or save
with a string you've constructed.>> make-dir %test-dir == %test-dir/ >> write %test-dir/file1.txt "Some text" >> td: %test-dir == %test-dir >> write td/file2.txt "Some more text" >> read td/file1.txt == "Some text" >> read %test-dir/file2.txt == "Some more text" >> delete %test-dir/file2.txt == true >> delete td/file1.txt == true >> delete td == true
help tuple!
x: collect/into [ foreach s split fetch-help tuple! {^/} [ keep (trim s) ] ] copy []
. What remains here is to remove the spaces and split the string into two in between inside the keep call.fetch-help
is an old name, which will likely go away. The new name is help-string
.>> same? :fetch-help :help-string == true
Help
is an interactive function, and does not produce loadable output in all cases. In the case of datatype help you are in luck, as *that* output is loadable.>> b: load help-string tuple! == [Red 255.0.0 white 255.255.255 transparent 0.0.0.255 black 0.0.0 gray 128.128.128 aqua 40...
a: charset [#"a" - #"z" #"A" - #"Z"] c: charset "0123456789." x: to-map collect/into [ foreach s split fetch-help tuple! {^/} [ keep parse (trim s) [ collect [ keep some a some space keep some c ] ] ] ] copy []
to-map collect/into [ foreach w words-of system/words [ if tuple? get/any :w [ keep reduce [:w get w]] ] ] copy []
a: charset [#"a" - #"z" #"A" - #"Z"] c: charset "0123456789." word: [some a] tuple: [some c] s: fetch-help tuple! m: to-map parse s [collect some [[copy v [word | tuple] keep (load v) | skip]]]
useful: charset [not #" " #"^/"] to-map parse fetch-help tuple! [ collect [ some [keep some useful | skip] ] ]
useful: complement charset " ^/"
"
?^
is the escaping character in Redview/no-wait
and or disabling it manually:view [f: field b: button "test" react [b/enabled?: all [string? f/text not empty? f/text]]]
do
command is not evaluating the reaction?view [f: field b: button "test" react [b/enabled?: all [string? f/text not empty? f/text]] do [f/text: none]]
disabled
keyworddisabled
hoping they will do what I wantdisabled
keywordview/no-wait
, setting the field's value (something what I was expecting to be able use with the do
command in the VID and finally running do-events
command.Red [ Needs: View ] colors: extract load help-string tuple! 2 view/tight collect [ until [ foreach color take/part colors 3 [ tuple: get color keep reduce [ 'text 'middle 'center form color tuple pick [white black] tuple < gray ] ] also empty? colors keep 'return ] ]
>> view [f: field b: button "test" disabled react later [b/enabled?: not empty? f/text]]
later
is the right key word.colors: sort extract load help-string tuple! 2 colors: sort/compare extract load help-string tuple! 2 func [x y][greater? get x get y]
base
with 70x40
size instead of text
for nicer look, although layout is slightly off for some reasontext
the colors glass
, tuple
and transparent
is black, i.e. not the same as with base
.base
case aboveRed [ Needs: View ] colors: exclude sort extract load help-string tuple! 2 [transparent glass] view/tight collect [ until [ foreach color take/part colors 5 [ hue: get color keep reduce [ 'base 70x40 form color hue pick [white black] hue < gray ] ] also empty? colors keep 'return ] ]
view
"?tuple!
values (hue
word for example)collect
?gui-console
from source - I can type in it, but no code is evaluated.do/args %red.r "-r %environment/console/gui-console.red”
-t Windows
when compiling the GUI console on Windows > XP. That option will redirect the DOS shell I/O to the console face.a -> b, b -> c, c -> d
but if I try to search for b
in hash I will find b
as a resultmap/b
is of course enoughmap!
disadvantage is sorting :(>> dt [loop len [select m 'w-12345]] == 0:00:00.111223 >> dt [loop len [find h 'w-12345]] == 0:00:00.108337
>> dt [loop len [find h to word! rejoin ['w random 100000]]] == 0:00:29.39861 >> dt [loop len [select m to word! rejoin ['w random 100000]]] == 0:00:27.498863
make-x
?skip
refinement with select
or find
on hash values>> h: make hash! [a b b c c d] == make hash! [a b b c c d] >> select/skip h 'b 2 == c >> find/skip/tail h 'b 2 == make hash! [c c d] >> first find/skip/tail h 'b 2 == c
do/args %red.r "-r -t Windows %environment/console/gui-console.red"
/skip 2
, but start from index 1 to search for *left* values and from index 2 for *right* values. Would that fit your data structure model?a => b, b => c, c => b, d => b
>> h: make hash! [ a b b c c b d b ] == make hash! [a b b c c b d b] >> second find/skip h 'c 2 == b
skip
works differently heren
value after a match>> x: object [m: make map! []] == make object! [ m: #() ] >> y: make x [] == make object! [ m: #() ] >> put x/m 'a 5 == 5 >> y == make object! [ m: #( a: 5 ) ]
>> x: object [l: copy []] == make object! [ l: [] ] >> y: make x [] == make object! [ l: [] ] >> append x/l 5 == [5] >> y == make object! [ l: [] ]
map!
or object!
are not. It is a trade-off between convenience and performance/resources.copy/types
and copy/deep/types
.errors
and throws
and how are they supposed to work and be used?cause-error
arguments right.catch
?if err: catch [ attempt [ parse line parse-rule ] false ] [ print ["<<" err ":" line ":" n ] ]
throw
takes an argument that is returned by catch
. cause-error
is hairycause-error
is just a constructor for errors, nothing else.make-error "This is my error"
would be great.clone: function [ "Deep make an object" object [object!] /with spec [block!] "Extra spec to apply" ][ cloners!: union series! make typeset! [object! map! bitset!] new: make object any [spec clear []] foreach word words-of new [ val: get in new word if find cloners! type? :val [ new/:word: either object? val [ clone val ][ copy/deep val ] ] ] new ]
>> str: "house" == "house" ; ok so far >> str: insert str "my " == "house" ;str should be "my house" >> str: insert at str 1 "my " == "house" ;str should be "my my house"... >> str == "house" ; ... but it's not!
insert
returns series AFTER the insertion. Red is full of these quirks! :worried: insert
function specification carefullyinsert
operations, or help calculate the length of the inserted part.>> do %run-all.r ** Script Error: Feature not available in this REBOL ** Where: context ** Near: SECURITY_ATTRIBUTES: make struct! [ nLength [integer!] lpSecurityDescriptor [integer!] bInheritHandle [int... >> about REBOL/Core 2.7.8.3.1 1-Jan-2011 Copyright 2000-2011 REBOL Technologies. All rights reserved. REBOL is a trademark of REBOL Technologies. WWW.REBOL.COM
struct!
is the custom call
implementation, what about switching to native call
instead in the testing framework when struct!
is not available? (So that just Rebol/Core would be needed for running the tests).call
.panel
:pan: [field area] view compose/deep [below drop-list data ["a" "b"] panel [(pan)]]
>> c: [x: 1 y: 2 x + y] compose [a b (c)] == [a b x: 1 y: 2 x + y] >> c: [(x: 1 y: 2 x + y)] compose [a b (c)] == [a b (x: 1 y: 2 x + y)] >> c: [(x: 1 y: 2 x + y)] compose compose [a b (c)] == [a b 3] >> c: [(x: 1 y: 2 x + y)] compose [a b (compose c)] == [a b 3] >> compose [a b (x: 1 y: 2 x + y)] == [a b 3] >> compose [a b [(x: 1 y: 2 x + y)]] == [a b [(x: 1 y: 2 x + y)]] >> compose/deep [a b [(x: 1 y: 2 x + y)]] == [a b [3]] ; But, in clean console >> compose/deep [a b [x: 1 y: 2 (x + y)]] *** Script Error: x has no value *** Where: + *** Stack:
build
(which I'm renaming), that Ladislav Mecir wrote, which is a keyword based alternative to compose
.on-change*
function for the face but it doesn't really work and I am wondering if this is the correct way to go?red clear
in that directory-r
compile option.-r
option, the exe will contain the runtime and does not require libRedRT.dll to run.--no-runtime
only applies to Red/System programs when compiling for minimalist environments (Those without a fully-fledged operating system.) It was introduced during some early experiments with Arduino.-u
option though I haven't used it myself. -r
.-c -u
. It worked for me though I run the compiler source and on a Mac. (Don't mix the -u and -r options).$ rebol -wqs red.r -u ../../Code/Red/test.red -=== Red Compiler 0.6.3 ===- Compiling .... /test.red ... ...compilation time : 812 ms Target: Darwin Compiling to native code... libRedRT-extras.r file generated, recompiling... Compiling ..../test.red ... ...using libRedRT built on 12-Nov-2017/6:49:14+8:00 ...compilation time : 24 ms Target: Darwin Compiling to native code... ...compilation time : 1104 ms ...linking time : 68 ms ...output file size : 77824 bytes ...output file :..../test $ ./test 133 $ rebol -wqs red.r ../../Code/Red/test.red -=== Red Compiler 0.6.3 ===- Compiling .../Code/Red/test.red ... ...using libRedRT built on 12-Nov-2017/6:49:14+8:00 ...compilation time : 24 ms Target: Darwin Compiling to native code... ...compilation time : 1085 ms ...linking time : 53 ms ...output file size : 77824 bytes ...output file : .../Red/red/test $ ./test 133
rate
less than 1?view
)text "something" rate 0.1
I got an errorview [text "hello" rate 10 on-time [print "ok"]]
rate 10
says run 10 times in a second. You are saying "run half times in a second" by giving 0.5
time!
works just as I wantview [text "hello" rate 0:0:3 on-time [print "ok"]]
time!
sets like a timeout#/bin/sh /usr/local/bin/red-063 /home/red/script.red
** Script Error: Invalid compressed data - problem: -3 ** Near: script: decapsulate if none? script
>> parse "a-b+c" [collect any [keep skip thru ["-" | "+"]]] == [#"a" #"b" #"c"] >> parse "a-b+c" [collect any [keep skip thru ["-" keep "-" | "+" keep "+"]]] == [#"a"]
keep
:>> parse "a-b+c" [collect any [keep [skip thru ["-" | "+"]]]] == ["a-" "b+"]
>> parse "ax-bx+c" [collect any [keep to copy c ["-" | "+" | end] keep c]] == ["ax" #"-" "bx" #"+" #"c"]
/size
refinementacc: 0 image-name: does [ load rejoin [mold '% 'temp acc: acc + 1 '.jpg] ] view [ cam: camera 800x600 select 1 button "Save picture" [save image-name to-image cam] ]
save/as
, but 'jpg doesn't save any files. No error though.acc: 0 image-name: does [ load rejoin [mold '% 'temp acc: acc + 1 '.png] ] view [ cam: camera 800x600 select 1 button "Save picture" [save/as image-name to-image cam 'png] ]
save image-name to-image cam
write
?write
it says the file is corrupted or too largeIt is possible to capture the content of a camera face using to-image on the face.
image
though I think it's weird to have to use image path on an image.view [ i: image 200x200 button "save" [save/as %test.png i/image 'png] ]
save/as blah blah 'jpg
does nothing. No error either.acc: 0 image-name: does [ load rejoin [mold '% 'temp acc: acc + 1 '.jpeg] ] view [ cam: camera 800x600 select 1 button "Save picture" [save/as image-name to-image cam 'jpeg] ]
jpg
is not recognized.rejoin
in Red?join
?red-by-example
then?source
commandrejoin
in it either :(what
in the Red console.what
comprehensive?npm
for redcontext
to create namespaces though.--cli
?do
files to include them at runtime. They won't be compiled in that way though.red --cli
on windows--cli
.help
, what
, and use source
to peek inside things. You can also do help help
and help what
, the latter being much more...helpful. red --cli
from inside babun behaves weirdly?help
and pressing enter, nothing happens, but when I ctrl+c
it prints everything it should before and then exitshelp
. It's actualy Windows' help foo: func ['a [any-type!] 'b [any-type!]][probe :a probe :b]
text >> x: 1 == 1 >> foo: func ['arg][probe arg] == func ['arg][probe arg] >> foo x x == x >> foo: func [arg][probe arg] == func [arg][probe arg] >> foo x 1 == 1
quote
quote
does?text >> foo: func [x][x + 1] == func [x][x + 1] >> foo *** Script Error: foo is missing its x argument *** Where: foo *** Stack: foo >> :foo == func [x][x + 1]
Programmers who have mastered REBOL suggest that the best approach is to forget what you already know about other languages.
is CRUCIAL and should be like telegraphed in every Red/REBOL tutorialparse
? :D-c -u
. It worked for me though I run the compiler source and on a Mac. (Don't mix the -u and -r options).$ rebol -wqs red.r -u ../../Code/Red/test.red -=== Red Compiler 0.6.3 ===- Compiling .... /test.red ... ...compilation time : 812 ms
-uswitch is used.
*** Internal Error: contains Red/System code which requires compilation
-uon Windows to double-check my result?
#system [ ;-- Red/System code inc: func [n [integer!] return: [integer!]][n + 1] ] red-inc: routine [i [integer!] return: [integer!]][inc i] probe red-inc 132
red -u code.red
and the snipped that you pasted?-uis supposed to create a small exe file using the libRedRT.dll.
-cthis should compile fine and link the dll into a big exe file.
routine
in the blog. It's an example given by @dockimbel in the comment section of that articleconsole.red
-u
switch on that specific code a couple of days ago on Mac and it compiles fine, see his log a bit higher in a post on this channel. The point is that the link step takes a long time and can be avoided.#system
:(text Red [] inc: func [n [integer!]][n + 1] #system [ #call [inc 123] int: as red-integer! stack/arguments print int/value ;-- will print 124 ]
-c -u
?-c -u
it workslibRedRt.dll libRedRt-include.red libRedRt-defs.r libRedRt-extras.r
-c -u
-u
the switches are mutually exclusive-u
it throws the error-u
throws an error-c -u
it compiles with few files-c
and look for differences-u
is not workingsplit-at: func [ "Break a string into two pieces using a delimiter or index" series [any-string!] "The string to split" delim [integer! string! char!] /local index ][ attempt [ index: either integer? delim [delim][index? find/case series delim] reduce [copy/part series index skip series index] ] ]
split
, but @gltewalt has you covered for now, and I have similar things I can post if you want.view [b: button "Press" [?? b]]
echo
a lot, so my apps dump a lot of data both to the console and a file. do/next
we should be able to step trace, to some extent anyway. We can also instrument code ourselves, much more easily than in other langs, but I think those of us who want to do that kind of thing are holding off, as it makes more sense to help the core team add it when Red becomes self hosted. Think DTrace on steroids.semver
string and getting a block of 3 integers as a result?-c -u
. It worked for me though I run the compiler source and on a Mac. (Don't mix the -u and -r options). $ rebol -wqs red.r -u ../../Code/Red/test.red -=== Red Compiler 0.6.3 ===- Compiling .... /test.red ... ...compilation time : 812 ms Target: Darwin Compiling to native code... libRedRT-extras.r file generated, recompiling... Compiling ..../test.red ... ...using libRedRT built on 12-Nov-2017/6:49:14+8:00 ...compilation time : 24 ms Target: Darwin Compiling to native code... ...compilation time : 1104 ms ...linking time : 68 ms ...output file size : 77824 bytes ...output file :..../test $ ./test 133 $ rebol -wqs red.r ../../Code/Red/test.red -=== Red Compiler 0.6.3 ===- Compiling .../Code/Red/test.red ... ...using libRedRT built on 12-Nov-2017/6:49:14+8:00 ...compilation time : 24 ms Target: Darwin Compiling to native code... ...compilation time : 1085 ms ...linking time : 53 ms ...output file size : 77824 bytes ...output file : .../Red/red/test $ ./test 133
x.y.z
type of thingparse version [ collect [ keep some integers #"." keep some integers #"." keep some integers ] ]
1.41.2
?a.b.c
1.41.2
would work the same.load
does here?parse-semver: function [ version ] [ integers: charset [#"0" - #"9"] either parse version [ some integers #"." some integers #"." some integers ] [ to-tuple utils/map parse version [ collect [ keep some integers #"." keep some integers #"." keep some integers ] ] utils/compose :to-integer :to-string ] [ none ] ]
1.2.3-alpha
in the future as well[1 2 3 alpha]
some integers 2 [#"." some integers]
mold
does formatting on mapsformat-block: function [ b ] [ replace/all replace/all replace/all mold b " " "^/ " "[" "[^/ " "]" "^/]" ]
print format-block [ 2 15 2 3 ]
v: "0.0.1-beta.2" delim: charset ".-" ?? v probe parse v [collect some [keep copy result to [delim | end ] skip] ]
format-block: function [ input /iden n ] [ deepness: either iden [ 4 * n ] [ 4 ] bracketPad: copy "" insert/dup bracketPad " " (deepness - 4) result: rejoin [ bracketPad (copy "[^/") ] foreach element input [ padding: copy "" insert/dup padding " " deepness either block? element [ append result format-block/iden element either iden [ n + 1 ] [ 2 ] ] [ append result rejoin [ padding (mold element) "^/" ] ] ] append result rejoin [ bracketPad (copy "]^/") ] return result ]
print format-block [ 1 2 3 [4 5 6] 7 8 9 ]
it prints:format-block: func [ b [block!] /local bl ] [ bl: b while [bl: find bl block!] [ format-block bl/1 bl: next bl ] new-line/all b on ]
do/args
into a block?insert at block (n + 1) /args
insert at block n [do/args]
just worksinsert at block n 'do/args
?insert/only
maybe?Red/System [] #import [ "kernel32.dll" stdcall [ beep: "Beep" [ frequ [integer!] dur [integer!] return: [integer!] ] ] ] beep 800 1000 beep 800 500
Red [] ; --- lib imports ----- #system [ #import [ "kernel32.dll" stdcall [ beep: "Beep" [ frequ [integer!] dur [integer!] return: [integer!] ] ] ] ] redbeep: routine [ f [integer!] d [integer!] return: [integer!] /local ret] [ ret: beep f d ret ] redbeep 1000 500
compose
compose
load
text in clipboard?/binary
on a clipboard scheme, which would let us do that.?
, Luke!wat!
find collection /part 3 'x /skip 2
#macro apply: function [f args] [ values: copy [] ref-values: copy [] refinements: copy [] append refinements f forall args [ case [ refinement? args/1 [ append refinements to-word args/1 ] refinement? args/-1 [ append ref-values args/1 ] true [ append values args/1 ] ] ] append append reduce [to-path refinements] values ref-values ] b: [a b d b c d c f] probe apply find [b /part 4 'c /skip 2] ; => none probe apply find [b /part 6 'c /skip 2] ; => [c d c f]
all-word!
, though there was discussion of changing those typeset names at one point. 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. 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 any-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]
all-word!
. 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] ]
;!! 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]
to-path
needs load form
and simple to path!
produces a//b
I guess we could agree it's bad design.compose
issue, where quote
is still not always how you want to do it. It's based on Ladislav's old build
func. I'll try to get a gist up before too long, for comment. Remind me if it's not up in a couple days.read-clipboard
messages made me try this: make a file containing onlyRed [] do read-clipboard
red.exe --cli do_clipboard.red
and see the magic ! I think I will make a shortcut for it in my text editor...do-clip
and load-clip
. I also have cc
which molds and writes a value to the clipboard. So handy.