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/argsexcept 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-digitnon-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 valuesource 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/onlyfilter: 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 specializespecialize 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
getting 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 red1199.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.helpspace: #" "
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 tabmeans testing for the lit-word'tabspspacetext: [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 contextfunctionfunction 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, useas 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 tabs (it appends tab-num * tab-with) and append-space-indent would append tab-num * tab-with spaces (it appendstab-num tabs).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-savetab-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-savevar 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: 10in 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 trapmac [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 contextloadsystem/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-downget/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-iRed []
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/iuse 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 ; 1Red []
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!"]
]
iuse 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.funclisp 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]
]listwith 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!: unsethelp system/wordscaps-lock unset! unset
num-lock unset! unset
cat unset! unsetcontext? #issue though :confused: equal? source context source objectname-space: :contextcontext 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/headeris 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 formatspec blocks, parse them, save in a file, something like thatspecs ?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
ffc> 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
== 2word 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?" inned?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 words thoughin?](https://stackoverflow.com/questions/21059228/how-to-use-in-with-a-block-instead-of-an-object/39812409#comment66916104_39812409)bind is from inred>> 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
== 2red>> b == 2 red>> get 'b == 2 red>> get 'a *** Script Error: a has no value *** Where: get red>> get in o 'a == 1
words 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?Wordes and Doctor Bindson, or "Zen and The Art of Scope Maintenance: An Inquiry into Contexts" :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
== 1a 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> ; --> 13371337.red file, then:h4x0r: load %1337.red h4x0r/9: h4x0r/4 do h4x0r
h4x0r: load load/headerc> 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.redRed [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
2context? in c 'acontext? ... 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 words 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: dosum-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
== 3755672sum-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 codecode 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"
callcould 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-iostack 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 RedRed [] 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.redsparse "ab cd cdefg" [any [to "cd"] to end]. Infinite loop? The first to should be thru to make it work.forever.someparseless 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 parseparse 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.redprin 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 :wordinhelp 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 funczinteger!>> 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
== truecontext? currently tells anything usefulcontext-ofreflector, which we don't have. We would have two options here - 1) context-of my-wordreturning the context, where my-wordis bound 2) context-of 'my-word (or using /any) returning block of context, where my-wordis 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-ofroute 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 *-ofreflectors 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-
== truehelp'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 reflectioncontext? 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! specmake x specxmake 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-ofwould 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: callcall/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" bfrextract-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/ageperson: 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/ageto-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: callcall output? I know that I could use call/shellfor 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 ...lsworks 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.comurl!, 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:freturns *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.pngfalse 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: pimold 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 reducetext-box! anyway. So, lot of work ;)cto 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 clearrebol --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.collects 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/collecttags 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". collection 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 'keynone if they key doesn't exist.has? func.none look the same.none ~= falsenone 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 ftest: {
<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 ftest: {
<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]
]collects 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 fkeep 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?routines 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"
== 981100010 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 - 004185E0hred -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.rednull 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 bodya 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 bitem 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.ratevalue: view [b: base 300x300 rate 10 on-time [b/color: random 255.255.255.0]] view [box 300x300 [print "test"]]boxis transparent by default, and hence the event fall on the underlying face? If I change boxto base, it works ...[print "test"]?on-downbox?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-downseems 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/barRed []
#macro generateApi: function[][
[
context [
foo: function[][print "foo"]
bar: function[][print "bar"]
]
]
]
api: generateApi
api/foo
api/barexpand 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 atcomposeultra-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 argumentbitset! 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-blahcompose 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 bdo, have to use system/words/doz)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.743286test.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 b50 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/:idpreprocessor/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]
== truegroup-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/3length? 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 editorview [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 editorarea of the first window.a set to? Now you run it again. What is a set to? Same question for editor. doing 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-pathargs 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
]>asdoes 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! | bluefalse 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"]
== falseahead, but length of jump is not known in advance. to or thru would do the trick, but they would not fail on non-alpha2to 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]
== truels 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?removeface/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 itfaceto 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/allhelp 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.redcontains 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+mshows 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 /allrefinement for mold and save).Compiling to native code... *** libRedRT Error: definition not found for red/OS-image/ctx-to-cgimage
environment/console/console.redconsole. 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 <> dtestred >> 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 makenative!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 filterC:\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/thatvalue? 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 guessgets 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
== 13824000s: 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 sword 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-wordvalue? bflmpsvbflmpsvz gets evaluated and the result of the evaluation is passed to value?false and then quit?catchcatch ?>> 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 >>
foreachunset '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 200base 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.forkable 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 orderjoin 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.5wat 4.0round 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-boxavailable 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 ANDnot 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: loadREBOL/View 2.7.6.3.1 14-Mar-2008Windows 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 : objectred.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 -rquit 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.exemusic: 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:i386gtk 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 msdosPS 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-timeblink: 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 anywill 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 breaktag: [t: open-tag (print ["in-tag" t]) any [ahead [not "<"] text | tag] close-tag]
anyRed [] 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 createdconstructinstead 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 #includes %file1.redand 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 expanddo %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[], loading 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.pngfile 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/scripti 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/scriptload 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.callfacility 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/varon-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 fieldsview/no-waitred 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.foris 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 kindpick 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
2with 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.#includes 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 tailappend/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-clipboardhelp 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 :Ddodialect 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-eachthat 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!
== truesome [ ... | 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-charmake 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-charcs: [- - - - - - - - - - - - - - - - - - - - - - - - - - - -] ;-- 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.438collect 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.526flatten-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.473flatten-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.224flatten: 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/stylesreverse 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.parapara! 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
== truebreak 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 ;)views"?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.composed 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
]]savesort 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
nones?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). writeis 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
]composeself 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]
composeclosure1: 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: loadnewline, 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 vsomething 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 expandtext-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:Usersand 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-scalarmap 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-integerinput: "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 nottrytry/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/:idxc/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: ELFCLASS64macmini: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 --universalWarning: 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
]
]
]alternone-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.1s 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
== falselisp
>> 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/rangeis 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. parseprint 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
01skip10
-->
... <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
00match: [| 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
01match: [| 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
00change "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 1text
change "1" "0"
v
11<end>
ahead "1" ... nope, backtrack
v
01<end>
change "1" "0"
v
01<end>
v
00<end>behindparse 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/tracecallback 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] 'bfind already return either "true" (block) or "false" ('none')do to force interpreter.find/deepexisten in rebol land, but never materialised IIRC. Maybe using a nested loop or using a parse?parsetext >> 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 valRed 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?forallForallbreak 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/2comment {
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, !"
alsoalso 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: breakotplib.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 CodeMaxin whileloop and then breakraises 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 [voviewnam](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.noneload 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 doing or loading 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]
== falseparse 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.splitting, float numbers loading, 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 loadsum: 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-userread/lines %access.log and also read %access.log?time-line: resp-line: bytes-line: integer!
bytes-line: to-integer bytes-lineparse 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) + 2x: 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 33 + 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 truelisp >> 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.redsystem/script, but it's not really populated with anythingRed [
Title: "hello world"
]
header: second load system/options/script
print header/Titlelisp
#!/usr/local/bin/red
Red [
Title: "Hello World!"
]
header: select/same load system/options/script 'Reddo 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"loaded, 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 stringstext
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-typeany-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'spokeing 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: thatdata: [[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]
]
]copyied 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/:bforeachor
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 functioninithead (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/headshead is already used in Red with a different meaning, because head [1 2 3] gives me back the whole block and not just 1tail 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?penultimatefirst back back tail series. Just one item.penultpast maybe?mostalmostPast for "everything except the last item"? Doesn't sound right to me.first back back tailmost seems the best to me so farmost is betterbutlastall-but-last. all-but-last verbose, butlastwould be better and both are inconsistent with nextbefore, 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 itakeskip 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.bindable and doable, 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 beginningfree 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 :-)Logmei 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] 3keep 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] 1to 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 2split 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 | Coderepeat 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 mainwindowmainwindow: [
image images/23
]
view mainwindowpath! 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 wini/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/onlysource: [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 winmove-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 winarr: 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 winextra 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 winpane 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 loopa: 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 loopa: 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-timestext _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'000Count: 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-wordsparse/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 winon-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 molded 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
== 5z/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
== 105fib: 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 0fib: 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.fibis 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'000Count: 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?changeing 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-allis 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 ... 1helps? 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.mapRed [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 1s?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])maps 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
== 45total 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-textwhat'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?2subtract 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) + 1function! 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 4apply: function [a [integer!] f [function!]][
f a
]
->: make op! :apply
mul-2: func [n][n * 2]
2 -> :mul-2
2 -> mul-2mul-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 * 5square-root 4 + square-root 9 * square-root 5 * 5square-root 7 * square-root 25square-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 matchbanks: [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.yieldmerge: 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 10closure 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-namestext
>> 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 2map! 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!writewrite %x.txt :xwrite/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 windowtext view/options [on-menu [if event/picked = 'test [print "Test"]]][menu: ["File" ["Test" test]]]
writeing out a Red program or script{ } it works outmold it: write %file.txt mold :f or simply write %file :f but not write %file fwhich 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 add1write might suppress evaluation, so that I could write write %test.txt add1write %test.txt add1 writes the result of add1write 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 newlinetext
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
]
]
]
]loading 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 strtext >> 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?findfound? function in Rebol:found?: func [
"Returns TRUE if value is not NONE."
value
][
not none? :value
]
>> found? find "abcdef" "cd"
== truecollect 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.COMstruct! 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.5time! 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 camwrite?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
quotequote 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.c1.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-alphain 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) /argsinsert 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 500Red []
; --- 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 500composecomposeload 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.