i: make image! 100x100
points: [40x40 50x50 60x60]
foreach point points [
draw i [circle point 1]
]reduce or compose to get the point value.i: make image! 100x100
points: [40x40 50x50 60x60]
foreach point points [
draw i compose [circle (point) 1]
]
? ia: [a block] a: 22
a entry in the system context word-value table is updated linking it to the block structure. This link is done at runtime and not at program loading.a: is encountered, what does happen ?a value in the context word-value table be changed? Or will the context word entry be linked to the element just after the a: word ?sel-code: [s: select s path-item] fin-code: [s: first at s path-item] do sel-code do fin-code
s: are in the same context, the first one will link s to the result of the SELECT, then the same word will be linked to the result of FIRST operation.y: s what will this do internally ? If s is an integer, will be created a copy in memory and then linked to y entries in y definition context ?reddo "print {Directory listing:} foreach x read %. [print [sp x]]"reddo "view [button {click cluck} focus [unview]]"
*** Script Error: View has no value needs: 'view now it works*** Script Error: expand-directives does not allow word! for its code argument
Script Error: dir has no value now cos is the C-like version, concise and accepting radians, convenient for (complex) math expression. cosine is the human-friendly version, accepting degrees and not having a mangled name.cos is the C-like version, concise and accepting radians, convenient for (complex) math expression. cosine is the human-friendly version, accepting degrees and not having a mangled name.cosine seems to accept radians as well, with /radians refinement and is of native! type, which, in my limited understanding should provide some performance benefits - is that correct? Unless I am missing something else here, I am unsure what additional cases would justify for me using cos instead of cosine, aside of somewhat lesser verbosity.%, //, mod, modulo, remainder also confuse me a little bit in terms of choice. Aside of being used in either infix or prefix scenarios, how should one proceed with deciding on what should be the most appropriate for their case? Help description states that modulo "handles errors like REMAINER", but no further details are given, so this seems to be quite abstract for me as a newcomer still.:arg, which is the difference from 'arg' when passing an integer or other arguments which are not functions? Is it equivalent or it is different in some way ?f: func [:a] [probe a] f myword ; R2 == ** Script Error: f is missing its a argument ; R3 & Red == myword
>> a: "aaa" == "aaa" >> b: a == "aaa"
>> a: "aaa" == "aaa" >> b: :a ; colon before a == "aaa"
a evaluates, while :a does not, but string evaluates to itself, so it's same. But there are types where it makes difference.f: func [:arg][type? :arg] probe f print
Gives the same result as: f: func [arg] [type? :arg] probe f :print
native!result, while for Red print is just a *word* in the first situation. >> f: func [:arg] [type? :arg] >> probe f print native! == native! >> f: func [arg] [type? :arg] >> probe f :print native! == native! >>
>> f: func [:arg] [type? :arg] == func [:arg][type? :arg] >> probe f print word! == word! >> f: func [arg] [type? :arg] == func [arg][type? :arg] >> probe f :print native! == native! >>
f by assigning body-of to b, but can't change a by using b in last few line:>> f: func[] [v: [] append v "aa"] == func [][v: [] append v "aa"] >> f == ["aa"] >> f == ["aa" "aa"] >> f == ["aa" "aa" "aa"] >> >> b: body-of :f == [v: ["aa" "aa" "aa"] append v "aa"] >> >> b/2/1 == "aa" >> b/2/1: "cc" == "cc" >> >> f == ["cc" "aa" "aa" "aa"] >> >> >> a: "aaa" == "aaa" >> b: a == "aaa" >> >> b: "bbb" == "bbb" >> a ; a still aaa == "aaa" >>
b points to. If you need to change a from b, you need to change the block directly, not just reassign b:>> a: "aaa" == "aaa" >> b: a == "aaa" >> change b "bbb" == "" >> a == "bbb"
v inside the function as a local, so once you call the f function, the value v will be global! Check this in fresh console:>> f: func[] [v: [] append v "aa"] == func [][v: [] append v "aa"] >> v *** Script Error: v has no value *** Where: catch *** Stack: >> f == ["aa"] >> v == ["aa"]
body-of does not copy the function body like Rebol does so you can mess with it like @bubnenkoff does.f2 to take the context of f and associate to it's a in place of system/words ? Has the context of a in f2 been set at function definition or at runtime ?a: 22 f: func [/local a] [a: 33 f2: func [] [print ["A value: " a]] f2 ] f ;f2
A value: 33
f2 if removed prints "a value: 33" in R2 and "Context for a is not available" in Red for reasons already explained from Vladimir months ago.)a: "hello word!"f: func [arg1 arg2] [block: [arg1 arg2] f1 block] f1: func [arg3] [append/only arg3 arg3 probe arg3] f 10 20
[arg1 arg2 [...]]
halt than you have no error it has been called with less arguments than needed. I supposed it is wanted too.f halt and see no error being returned.... indicates that there's a cycle.>> do :print [2 + 2] 4
>> do :print [2 + 2] == [2 + 2]
>> p: :print p [2 + 2] 4
... cycle issue, you can see the similar output for objects: o: object [x: self]to or make (or at least object into map, as ordered into orderless collection)?>> make map! object [a: 1] *** Script Error: cannot MAKE/TO map! from: make object! [a: 1] *** Where: make *** Stack: >> object #(a: 1) *** Script Error: object does not allow map! for its spec argument *** Where: object *** Stack: object
y axis increasing from top to bottom of the display for draw dialect? I have a gut feeling that this might have something to do with the way images are represented in Red (as a 1D space by taking first row of pixels from left to right, then second row, and so on - according to the documentation), but this is just a guess.f1versions: reduce [ 'v1 func [arg1] [print ["arg1 is: " arg1]] 'v2 func [arg1 arg2] [print ["arg1 is: " arg1 " arg2 is: " arg2]] 'v3 func [arg1 arg2 arg3 /additional arg4] [print ["arg1 is: " arg1 " arg2 is: " arg2 " arg3 is: " arg3]] ] f1: func [version] [select f1versions version] do f1 'v1 14 do f1 'v2 15 25 do f1 'v3 16 26 36
arg1 is: 14 arg1 is: 15 arg2 is: 25 arg1 is: 16 arg2 is: 26 arg3 is: 36
f1versions: reduce [ 'v1 func [arg1] [print ["arg1 is: " arg1]] 'v2 func [arg1 arg2] [print ["arg1 is: " arg1 " arg2 is: " arg2]] 'v3 func [arg1 arg2 arg3 /additional arg4] [print ["arg1 is: " arg1 " arg2 is: " arg2 " arg3 is: " arg3]] ] f1: func [version] [select f1versions version] do reduce compose [(:f1) 'v1 14] do reduce compose [(:f1) 'v2 15 25] do reduce compose [(:f1) 'v3 16 26 36]
arg1 is: 14 arg1 is: 15 arg2 is: 25 arg1 is: 16 arg2 is: 26 arg3 is: 36
/additional refinement using your current pattern.f1: context [ v1: func [arg1] [print ["arg1 is: " arg1]] v2: func [arg1 arg2] [print ["arg1 is: " arg1 " arg2 is: " arg2]] v3: func [arg1 arg2 arg3 /additional arg4] [print ["arg1 is: " arg1 " arg2 is: " arg2 " arg3 is: " arg3]] ] f1/v1 14 f1/v2 15 25 f1/v3 16 26 36
map-to-object: function [map [map!]] [
body: body-of map
words: clear []
values: clear []
foreach [word value] body [
append words word
append/only values :value
]
obj: construct words
set obj values
obj
]map-to-object can misbehave for maps with non-word keys:>> map-to-object probe #(a: 1 "b" 2 'c 3 :d 4 0 5)
#(
a: 1
"b" 2
c: 3
d: 4
0 5
)
== make object! [
a: 1
c: 2
d: 3
]clearinstead of a copyin @giesse's example? Haven't seen it yet used like that :-)apply a lot tooapply is another design/implementation pitfall (reduced block vs non-reduced, named args vs providing all the args+refinements,...). Propositions are welcome (in HOF group) as I don't have the spare time to work on that.find, add your shiny epic refinement to it. E.g. /epic message. You write find/epic ... "my message" so it will do just print "my message", then call native find and return it's result. Try to implement this ;)apply :find [series value /epic "my message"] ?apply that makes this task a one-linercopying, it can be a gotcha, but something people can learn, and there are many use cases where it will work just fine. e.g., just as JSON allows keys with spaces, the vast majority of key names are word compatible. applywas part of R3 implementation - http://www.rebol.com/r3/docs/functions/apply.htmlmyapply: func [
{Given an extended function (with more arguments and refinements), applies
and run the funcion being exteded providing only the parameters and refinement
present in both specs and used in the extetend function}
func-word [word!]
"A function name which is an extension of another one"
func-to-patch [word!]
"The original function which has been extended"
ctx [word!]
"an argument of the function with extended parameters"
/only
/local
line-to-run
found-refinement
ref-word
item
specs
specs-func-to-patch
refs
] [
line-to-run: copy []
refs: to-path func-to-patch
specs: spec-of get func-word
specs-func-to-patch: spec-of get func-to-patch
bind specs 'ctx
found-refinement: false
ref-word: false
forall specs [
item: first specs
either refinement? item [
if (get in bound? ctx item) [
if found? find specs-func-to-patch item [append/only refs to-word in bound? ctx item]
found-refinement = true
ref-word: true
]
]
[
if word? item [
if (get in bound? ctx item) [
if found? find specs-func-to-patch item [
either only
[append/only line-to-run reduce in bound? ctx item]
[append/only line-to-run in bound? ctx item]
]
]
]
]
]
do head insert/only head line-to-run refs
]newfind: func append spec-of :find /epic [ if epic [print "--- !!!!! This is epic !!!!! ---"] probe myapply 'newfind 'find 'series ]
newfind [a b c] 'b newfind/epic [a b c] 'b newfind/epic/tail [a b c] 'b newfind/tail/epic [a b c] 'b
[b c] --- !!!!! This is epic !!!!! --- [b c] --- !!!!! This is epic !!!!! --- [c] --- !!!!! This is epic !!!!! --- [c]
newfind: func append spec-of :find /epic [
newfind: func append copy/deep spec-of :find /epic [
>> newfind reduce ['a off 'b] no none == none >> f: does [print "CALLED"] newfind reduce ['a :f 'b] :f CALLED none == none
found-refinement and ref-word play. And then what if I wish to rename some refinements, or add those not provided to my newfind? Or if I wrote the spec of newfind by hand, but spec of find changes in the new release? Details, details...>> f: list-dir to-path get-current-dir *** Access Error: cannot open: %/D/code/2020/redparse/D:\code\2020\redparse\/
f: read %./path! type is not file path, do not confuse them!dirdir is fine for printing, but you can't assign its output to a word.help?>> help list-dir
USAGE:
LIST-DIR dir
DESCRIPTION:
Displays a list of files and directories from given folder or current one.
LIST-DIR is a function! value.
ARGUMENTS:
dir [any-type!] "Folder to list."
REFINEMENTS:
/col => Forces the display in a given number of columns.
n [integer!] "Number of columns."
>> list-dir %./
make-csv.red gui-conso... CODE_OF_C... usr/ BSL-Licen... cleaned.red libRedRT-... boot.red red-063
compiler.r crush.dylib version.r stylize.exe red.r quick-test/ runtime/ tests/ .gitignor...
pp.red utils/ docs/ .appveyor... bridges/ .editorco... README.md system/ user.red
CONTRIBUT... csv-test/ .github/ rebol.exe rebol environment/ gui-console build/ custom.red
libRed/ .git/ rebuild modules/ lexer.r run-all.r .travis.yml BSD-3-Lic... usage.txt
console>> f: list-dir %./ app.red backup.txt r1.r r2.r r3.r *** Script Error: f: needs a value *** Where: f
displays being the most important word here.>> foreach file read %./ [if find file ".r" print file] app.red *** Script Error: if does not allow unset! for its then-blk argument
if needs block! -> if find file %.r [print file] (I also changed your suffix to file! from string!. Not necessary, but IMO it’s better to use appropriate datatype).suffix? function, that may be useful for this kind of checks, e.g.: equal? %.red suffix? file>> if find %bad.robot.jpg ".r" [print "found"] found
foreach f files [if find f ".r" [print f]]
.r files but end exclude all other like .readme?remove-eachfunction, though it needs to reverse to condition naturally:>> remove-each file data: read %./ [not find file ".r"] >> data == [%boot.red %compiler.r %lexer.r %libRedRT-extras.r %particles.red %red.r %run-all.r %version.r]
keep-eachfunction, so that you don't have to reverse the condition, especially if there is multiple conditions there ....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)]] ]
%.r = suffix? f is so nice and clear. If you're really printing, that may hide any speed gains from parse, but let's see...using 10'000 random files, of which 223 have a %.r suffix:Time | Time (Per) | Memory | Code 0:00:00.012 | 0:00:00.012 | 440284 | [n: 0 foreach f files [if %.r = suffix? f [n: n + 1]]] 0:00:00.014 | 0:00:00.014 | 284 | [n: 0 foreach f files [if parse f [thru %.r end] [n: n + 1]]] 0:00:00.244 | 0:00:00.244 | 33288 | [foreach f files [if parse f [thru %.r end] [print f]]] 0:00:00.287 | 0:00:00.287 | 473444 | [foreach f files [if %.r = suffix? f [print f]]]
suffix? isn't consistent, due to a single run. Here's another:Time | Time (Per) | Memory | Code 0:00:00.014 | 0:00:00.014 | -1637792 | suffix'n 0:00:00.014 | 0:00:00.014 | 284 | parse'n 0:00:00.226 | 0:00:00.226 | 33288 | parse' 0:00:00.262 | 0:00:00.262 | 537468 | suffix'
>> m: #() == #() >> m/(#x): 1 *** Script Error: issue! type is not allowed here *** Where: set-path *** Stack:
put [] #x 1 *** Script Error: put does not allow issue! for its key argument *** Where: put *** Stack:
Form, (mold actually), which is still lossy, and is something users can do themselves.issue! as key makes a lot of sense to me.sources: get-files/filter dir ends-with extensions
crashdump..red, but I is there any cases when .r is using?.r file:>> list-of-rules: foreach f files [if equal? suffix? f ".r" [f]] == %r3.r >> >> foreach f files [if equal? suffix? f ".r" [print f]] r1.r r2.r r3.r
>> files == [%app.red %backup.txt %r1.r %r2.r %r3.r] >> >> >> foreach f files [if equal? suffix? f ".r" [append list-of-rules f]] == [%r1.r %r2.r %"" %r1.r %r2.r %r3.r]
>> files: [%app.red %backup.txt %r1.r %r2.r %r3.r] == [%app.red %backup.txt %r1.r %r2.r %r3.r] >> list-of-rules: [] == [] >> foreach f files [if equal? suffix? f ".r" [append list-of-rules f]] == [%r1.r %r2.r %r3.r]
foreach return values instead of appending them? Or what best practice for writing such functions? collect/keep.l: foreach f files [if equal? suffix? f ".r" [collect keep f]]
>> ? keep No matching values were found in the global context.
collect.parse at allf/:cond xyzdo?apply it gets better.copy, collect, and keep so they align with standard Red functions, but they may behave differently. It may seem strange at first, but it becomes natural before too long for most people.parse. But we wouldn't be as effective without it, and our code would be more complicated.asset. The military's meaning of asset would be different than the financial analyst's meaning of asset.` apt`git clone https://github.com/anonymouXnashdo/next and check the mode again (switch if needed)exit that sets the position and breaks out of parse, then after a break (in do-mode again), continue from that position+ is an operator, but at some point it may change into a value or a function and you need to be up to date with this change. The only way to be up to date is to evaluate ;)system/lexer/pre-load thing abuses thatdo on the resultimg1: make image! 100x100 img2: make image! 10x10 ; copy image img2 into img1 xy: 10x10 change at img1 xy img2
*** Script Error: change does not allow image! for its series argument
>> i1: make image! 2x2
>> i2: make image! [1x4 255.0.0]
== make image! [1x4 #{FF0000FF0000FF0000FF0000}]
>> head change i1 i2
== make image! [2x2 #{FF0000FF0000FF0000FF0000}]make image! [2x2 #{FF0000FFFFFFFF0000FFFFFF}]>> i1: make image! 2x2
== make image! [2x2 #{FFFFFFFFFFFFFFFFFFFFFFFF}]
>> change i1 #{112233FF}
== make image! [2x2 #{112233FFFFFFFFFFFFFFFFFF}]to-binary on an image is a VERY slow operation ☻as binary! should work with image!? (Don't have a /View build handy to check)image! is sometimes indeed treated as a kind of 2D series! may be additionally confusing: https://doc.red-lang.org/en/datatypes/image.html#_manipulationx was not declaredunset 'x>> make binary! [98]
== #{62}
>> to binary! 98
== #{00000062}>> make binary! [98]
== #{62}
>> to binary! [98]
== #{62}
>> to binary! 98
== #{00000062}
>> make binary! 98
== #{}tocommandto binary!. What are different semantic meanings in these two cases? (with and without [])>> to binary! [98 99 #"d" "ef" [103 104]]
== #{62636465666768}binary! datatype, wouldn't you agree? I suspect I wasn't the first and wouldn't be the last one to ask this question.xml-files: read %/C/current_month/notice/notification_Moskva_2019020200_2019020300_001.xml/ list-of-files-for-processing: collect [foreach f xml-files [if equal? suffix? f ".xml" [keep f]]]
== [%fcsNotificationEA44_0373200101018000262_19160099.xml %fcsNotificationEA44_0373200101018000263_19160346.xml]
xml-folder: %/C/current_month/notice/notification_Moskva_2019020200_2019020300_001.xml/ xml-files: read xml-folder list-of-files-for-processing: collect [foreach f xml-files [if equal? suffix? f ".xml" [keep rejoin [xml-folder f] ]]]
foreach _file list-of-files-for-processing [
file: read _file
; ...
]
foreach file list-of-files-for-processing [
file: read file
; ...
]
foreach _ list-of-files-for-processing [
file: read _
; ...
]foreach file files [file: read file]. If I need to keep the filename, I change it to foreach file files [data: read file]list-of-files-for-processing is too long for my tastefile-listwould be ok too ....remove-each f xml-files [%.xml <> suffix? f]foreach file files [
data: read file
; ...
]f: func[s][
foreach [a b] s [
prin rejoin [a t: any[b ""] t]
]
]
f "abcde"
print ""
f "abcdef"
abbcdde
abbcddeff
>>>> f: func[s][
[ foreach [a b] s [
[ prin rejoin [a t: any[b ""] t]
[ ]
[ ]
== func [s][foreach [a b] s [
prin rejoin [a t: any [b ""] t]
]]
>> f "abcde"
abbcdde
>> f "abcdef"
abbcddeff1 with an overline as one symbol. This doesn't work for me:>> print rejoin [#"^(0031)" #"^(0305)"]. Any ideas?
/extra field is yours to abuseforeach-face is your friend I guessextra too, or walking words to look for those that refer to an object (in this case), which is very brute force, but can work fine. It's not hard to do yourself, but it *is* harder to generalize, because more than one word can refer to the same value. The "harder" part is not every user has the same needs./extras: [myname ] could be a good place.a-button: button on-something [] a-button: is in the global context ?>> view/no-wait [aword: button on-click [unview]] probe aword
make object! [
type: 'button
offset: 10x9
size: 78x27b: make object! [aword: none] view/no-wait [b/aword: button on-click [unview]] probe b/aword *** Script Error: VID - invalid syntax at: [b/aword: button on-click] *** Where: do *** Stack: view layout cause-error
words-of would do (part of) the magic for my starting question.set-word? valueis checked (line 646) and where it's set (line 727) won't be hard to change. z: [a "hello" b "world"] view [aword: button z/a on-click [unview]] *** Script Error: VID - invalid syntax at: [z/a on-click [unview]] *** Where: do *** Stack: view layout cause-error
datarow/column, and similar, which are used often.planets: [ #(Name: "Mercury" Mass: 0.055 Orbit: 0.4) #(Name: "Venus" Mass: 0.815 Orbit: 0.7) #(Name: "Earth" Mass: 1.0 Orbit: 1.0) #(Name: "Mars" Mass: 0.107 Orbit: 1.5) ] >> view layout [button planets/1/name on-click [probe face/text unview]] *** Script Error: VID - invalid syntax at: [planets/1/name on-click [probe face/text unview]] *** Where: do *** Stack: view layout cause-error
BUTTON ? The data element ? get-word! and get-path! datatypes should be supported, so the code would be:view layout [button :planets/1/name on-click [probe face/text unview]]
flip-exe-flag you can also add config: [sub-system: 'GUI] to the script header-t Windows might even produce a smaller exefacet.checksumstyle piece:edge you should removestyle piece: base coal 60x60 on-down [... style works for meedge, I'm assuming because it's using
baseinstead of
button
Base is just an empty box, basically, so doesn't look like anything. :^)Red [ ] Do [Mycode my-code] Switch code [ A [Mycode mycode] B [othercode other-code] ]
do ?A or B, is the code floowing those words preprocessed before execution ? Which are the avaluation/execution steps if any ?profile it to see ;)profile? Never read about this function. I'll try and report!DO and SWITCH perform extra operations on the code block that adds overhead or it is immediately executed.>> round 99 / 50.0 == 2.0/ on ints coerce, while // will be the new integer divide op. win: make face! [ type: 'window text: "Red View" size: 320x240 ] win/pane: reduce [ hello-btn: make face! [ type: 'button text: "Hello" offset: 10x10 size: 75x35 actors: object [ on-click: func [ face [object!] event [event!] ][ print "Hello!" ] ] ] ] view win
The Red Language Server server crashed 5 times in the last 3 minutes. The server will not be restarted. msg on VSCode extension:[Trace - 17:11:18] Sending request 'textDocument/hover - (3)'. [Trace - 17:11:20] Received notification 'textDocument/publishDiagnostics'. [Info - 17:11:20] Connection to server got closed. Server will restart. [Error - 17:11:20] Request textDocument/hover failed. Error: Connection got disposed. at Object.dispose (c:\Users\endo\.vscode\extensions\red-auto.red-0.3.6\node_modules\vscode-jsonrpc\lib\main.js:876:25) at Object.dispose (c:\Users\endo\.vscode\extensions\red-auto.red-0.3.6\node_modules\vscode-languageclient\lib\client.js:71:35) at LanguageClient.handleConnectionClosed (c:\Users\endo\.vscode\extensions\red-auto.red-0.3.6\node_modules\vscode-languageclient\lib\client.js:2153:42) at LanguageClient.handleConnectionClosed (c:\Users\endo\.vscode\extensions\red-auto.red-0.3.6\node_modules\vscode-languageclient\lib\main.js:151:15) at closeHandler (c:\Users\endo\.vscode\extensions\red-auto.red-0.3.6\node_modules\vscode-languageclient\lib\client.js:2140:18) at CallbackList.invoke (c:\Users\endo\.vscode\extensions\red-auto.red-0.3.6\node_modules\vscode-jsonrpc\lib\events.js:62:39) at Emitter.fire (c:\Users\endo\.vscode\extensions\red-auto.red-0.3.6\node_modules\vscode-jsonrpc\lib\events.js:120:36) at closeHandler (c:\Users\endo\.vscode\extensions\red-auto.red-0.3.6\node_modules\vscode-jsonrpc\lib\main.js:226:26) at CallbackList.invoke (c:\Users\endo\.vscode\extensions\red-auto.red-0.3.6\node_modules\vscode-jsonrpc\lib\events.js:62:39) at Emitter.fire (c:\Users\endo\.vscode\extensions\red-auto.red-0.3.6\node_modules\vscode-jsonrpc\lib\events.js:120:36) at StreamMessageReader.fireClose (c:\Users\endo\.vscode\extensions\red-auto.red-0.3.6\node_modules\vscode-jsonrpc\lib\messageReader.js:111:27) at Socket.<anonymous> (c:\Users\endo\.vscode\extensions\red-auto.red-0.3.6\node_modules\vscode-jsonrpc\lib\messageReader.js:151:46) at Socket.emit (events.js:205:15) at Pipe.<anonymous> (net.js:586:12)
>> ~: make op! :as-pair >> clock/times [as-pair 1 2] 1000000 241 ms [as-pair 1 2] == 1x2 >> clock/times [1 ~ 2] 1000000 143 ms [1 ~ 2] == 1x2
append are binary in their common formto-float will convert string to float, so you will lose your padding zeroes:>> pad/with find/tail form round/to 1 .01 dot 2 #"0" == "1.00"
form function? ;-)Red [
needs: 'view
file: insults.red
Author: "manuelcaeiro"
]
col1: ["Away, you" "Come, you" "Thou" "You poor"]
col2: [" peevish" " grizzled" " greasy" " jaded" " waggish" " purpled" " rank"
" saucy" " vacant" " yeasty"]
col3: [" clay-brained" " dog-hearted" " evil-eyed" " lily-livered" " mad-bred"
" onion-eyed" " paper-faced" " rump-fed" " shag-eared" " white-livered"]
col4: [" three-inch fool" " canker blossom" " clot pole" " hedge-pig" " dogfish"
" egg-shell" " nut-hook" " pantaloon" " rabbit-sucker" " snipe younker"]
ins: [random/only col1 random/only col2 "," random/only col3 "," random/only col4 "!"]
view [
size 750x100
title "Shakespearean insult generator for kids"
below center button "Insult me!" [phrase/text: form rejoin ins] phrase: text 725x35 font-size 20 center
]map! to none removes the value. Is it possible in Red?>> m: make map! [a: 1 b: 2]
== make map! [
a: 1
b: 2
]
>> m/a: none
== none
>> m
== make map! [
b: 2
]ports?random ?gensym func. gensym: func [/with 'word /reset /local count] [ count: [0] count/1: add 1 either reset [0] [count/1] to word! append to string! any [word "g"] count/1 ] loop 3 [print gensym] loop 3 [print gensym] gensym/reset loop 3 [print gensym] loop 3 [print gensym/with 'xx]
gensym example! So this is how to implement a generator in Red - very nice!Red [ Needs: 'View ]
b: make face! [
type: 'button
text: "ok"
enabled?: yes
visible?: yes
]
w: make face! [
type: 'window
text: "My Window"
pane: [b]
offset: 50x50
size: 300x300
enabled?: yes
visible?: yes
]
view wRed [ Needs: 'View ]
b: make face! [
type: 'button
text: "ok"
offset: 0x0
size: 80x25
]
w: make face! [
type: 'window
text: "My Window"
pane: reduce [b]
offset: 50x50
size: 300x300
]
view wtext: {ok start this is a test string stop test testing startokstring2stop test start wordstring3 stop ok}
a: parse text [collect any [thru "start" | keep to ["stop" | end]]]
print a|:>> a: parse text [collect any [thru "start" keep to ["stop" | end]]] == [" this is a test string " "okstring2" " wordstring3 "]
load %file. How to check if it have function foo inside? I tried set-word? but it's seems that it's not for thisfindfind code [foo: func] in case you're not using something more interesting to create your functions :-)function? do not work?>> ? function?
USAGE:
FUNCTION? value
DESCRIPTION:
Returns true if the value is this type.
FUNCTION? is a function! value.
ARGUMENTS:
value [any-type!]
>> func function function! function?
>> foo: func[] [print "hello"]
== func [][print "hello"]
>>
>>
>> function? foo
hello
== falsefunction? :fooload returns *data*do load %file ?:foo to get valuefunction? :foofoo from every file if it exists in it. foreach _rule list-of-rules [
rule: load _rule
do do-parsing file ; do-parsing can exist of not in files
]unset after every function call ir I can simply go to next filefile?list-of-files-for-processing: collect [foreach f xml-files [if equal? suffix? f ".xml" [keep rejoin [xml-folder f] ]]]
foreach _file list-of-files-for-processing [
file: read _file
foreach _rule list-of-rules [
rule: load _rule
do do-parsing file
]
]do-parsing after each callrule: load _rule:dp: find/tail rule 'do-parsing
if dp [
dp: do copy/part dp 3
dp file
]do rule to execute the code inside rule. And all other code from rule will run as well.>> rule: load %.\rules\r1.red
== [Red []
"aabbccdd"
x: "hello"
foo: func [] [print "hello world from foo"]
]
>>
>>
>> do rule/foo
*** Script Error: func is missing its spec argumenttype? rule/foorule is just a block of Red values (code = data)do is evaluate itfunc word alonerule/foo on not evaluated block of data, you just get a value following word 'foo, and it's word 'func. So you actually do something like: do 'funcdo) entire loaded file, but then you'll execute all code in it.>> rule
== [do-parsing: function [file result-file-name] [print "start do-parsing"
data: object [
id: none
lots: []
]
...
>> do copy/part rule 3
*** Script Error: function is missing its body argument
*** Where: function
*** Stack:do-parsing:.do-parsing:, but you have to be sure, that in each rule you use same word for function name.do-parsing: from rule.dp: do copy/part rule 3>> do/next fn: back find rule 'function 'rpos == func [file result-file-name][print "start do-parsing"] >> >> print to-word fn/1 do-parsing >> do reduce [to-word fn/1 1 2] start do-parsing >>
f: func [/local x A][foreach [x][0 1][A: x print [s: {add A 12} do s]]]composeview compose [... your VID stuff and (ID/data) <-- you put parens around paths]Data and extra are examples:o: object [a: "test"] view [ text data 1 + 1 button "Path" extra o/a [print face/extra] ]
compose today.>> fact: func [n][n: to float! n either n = 1 [1][n * fact n - 1]] == func [n][n: to float! n either n = 1 [1] [n * fact n - 1]] >> fact 12 == 479001600.0 >> fact 13 == 6227020800.0 >> fact 120 == 6.689502913449124e198
rebol >> to-date "2020-02-27 11:53:58" == 27-Feb-2020/11:53:58
red >> to-date "2020-02-27/11:53:58" *** Script Error: cannot MAKE/TO date! from: "2020-02-27/11:53:58" *** Where: to *** Stack: to-date
newDate: load replace "2020-02-27 11:53:58" " " "/" == 27-Feb-2020/11:53:58
random (issue #4308). In that connection I did some tests, and one thing that may be obvious to some, but not to others, is that for random, false < true, therefore random false is uniformly false; to get an equal chance of false and true one has to do random true.event/offsetdo to-block string is loaded and new words are global. You need to bind the block to func context do bind to-block y :f (On phone now and cannot check).function collects declared words from its body and makes these local. But as z is not declared during function initialization, it is not bound to function context when created. See:>> f: function [][y: copy "" append y ["z: 12 print z"] do bind to-block y :f] == func [/local y][y: copy "" append y ["z: 12 print z"] do bind to-block y :f]
z catched with function you need either to declare it (as you did in your comment) or make it explicitly local:>> f: function [/local z][y: copy "" append y ["z: 12 print z"] do bind to-block y :f] == func [/local z y][y: copy "" append y ["z: 12 print z"] do bind to-block y :f] >> f 12 >> z *** Script Error: z has no value
zip-debug.red and zip.red, they will be merged soon. Debug version is development version and supports UTF8 filenames.| skip (or whitespace charset) to script, then you can use whitespace interrupted multiline commands.)++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++. but the other one hangs. :+1:hello.red example shows you. Just put an icon: %myico entry in the header, and red does the rest.to? We also have make, load, and as.to, but not all, date! and map! being examples. Some use their own logic, some call their own make internally.Time! only has one syntax, and calls out to the tokenizer. Same for pair!load). Anything goes, if it's a Red form. Next comes creation (make), which can take specs in varying forms, and which requires you to know some details about value you're creating, so your spec is valid. Then we have conversion (to), where you have an existing value, but you want a different type, which *may be* possible to do, but is not guaranteed to work. Finally, there's coercion (as), which is the most restricted form of conversion, and also the most efficient.load, you specify the type you want. >> to time! [1 2 3] == 1:02:03 >> to block! to time! [1 2 3] == [1:02:03]
date!, its unique interaction with humans due to how many ways we spec and talk about them, variances due to things like today (leap day), etc. Red added many new date forms, so there's no way it can round trip (e.g. 2020-060 == 29-Feb-2020, 2020-W01 == 30-Dec-2019). Dates also change to canonical syntax when formed. to work on strings, we can, and it can just load. But it doesn't really *solve* anything. It just pushes issues around a bit.to-date. I think that these should be more like a shortcut to to date! and could handle various types.to-* funcs are simple wrappers for to, generated automatically. I have mentioned in the past that I think they can go away entirely. Person: object [ name: none age: none]
Person.new: function [ name age ] [
make Person [ name: name age: age ]
]
>> pete: Person.new "Peter" 35
== make object! [
name: none
age: none
]make, however the question is more about understanding language behavior.make Person:Person: object [ name: none age: none] Person.new: function [ name age ] [make Person compose [name: (name) age: (age)]] pete: Person.new "Peter" 35
== make object! [
name: "Peter"
age: 35
] >> Person.new: function [ name age ] [make Person probe reduce [name: name age: age]]
== func [name age][make Person probe reduce [name: n...
>> pete: Person.new "Peter" 35
["Peter" 35]
== make object! [
name: none
age: none
]Person.new: function [ name age ] [
make Person probe reduce [quote name: name quote age: age]
]Person.new: function [ name age ] [out: make Person [] set out reduce [name age] out]
pete: Person.new "Peter" 35
== make object! [
name: "Peter"
age: 35
]compose ;)>> Person.new: function [name* age*] [make Person [ name: name* age: age* ]]
== func [name* age* /local name age][make Person [name: name* age: age*]]
>> Person.new "Peter" 35
== make object! [
name: "Peter"
age: 35
]wait and forever, when you compile it for -t Windows?-t Windowsfunction1: func [myarg1] [ function2 ] function2: does [ print ["Function1 myargs: " myarg1] ;<<<<------ ]
bind body-of function2 'myarg1 or pass the words via the interface as arguments. context [
var: none
f1: func [arg][
var: arg
f2
]
f2: func [][something with var]
]bind body-of function2 'myarg1 could be done when the context of function1 is not available, I mean it externally.1) if @dockimbel is OK with that.bind have found function!!USAGE:
BIND word context
DESCRIPTION:
Bind words to a context; returns rebound words.
BIND is a native! value.
ARGUMENTS:
word [block! any-word!]
context [any-word! any-object! function!]call at runtime.Red []
endpoint: https://coinmarketcap.com/currencies/bitcoin/
btc-data: read endpoint
btc-price: copy ""
parse btc-data [thru {price__price">$} copy btc-price to {</span>}]
alter btc-price #","
print ["Price:" btc-price]view [cam: camera 300x300 select 1]works for me - Win 8.1, Asus K550J laptopconnection-data , query-string, placeholders? Have you a general rule to select the sequence?run-query satisfies the "subject first" requirement but with long queries , options disappears overscreen.run-query (on) (with-values) (subject) satifies the requirement of having long items at last but there is an additional entry in the argument list: "additional-placeholders" which is used to overwrite and extend those provided, so: run-query (on) (subject) (and apply) (and extend/replace) is more fluent when <query> is a word which contains the query. But it would be terrible if you write there the query string. , this is most redbol-likerun-query on query ... approach does the trick as it contains cues ("on", "query", etc) on what the next argument is.run-query/server/ph/ph+/query provides the sequence of arguments and you can change it. As someone has recently written to me: this is thinking out of the box! Nice one!aif [x = 1][print it]
it: x = 1 if it [print it]
expand workaif in Red console, than try to expand but the result is unexpandedtext expand [ #macro ['aif block!] func [[manual] start end][ skip insert start [it: x = 1] 2 ] aif [x = 1][print it] ]
aif in Red console, than try to expand but the result is unexpanded>> expand [
[ #macro ['aif block!] func [[manual] start end][
[ skip insert start [it: x = 1] 2
[ ]
[
[ aif [x = 1][print it]
[ ]
[it: x = 1
aif [x = 1] [print it]
]
== [it: x = 1
aif [x = 1] [print it]
]aif [x = 1][print it] should be expanded to it: x = 1 if it [print it]1 block! in this case though ;)#macro ['aif 2 block!] func [[manual] start end][
parse start [change ['aif][it: do] block! insert [if it] block! mark:]
mark
]insert in Parse, not to mention all the subtle differences between R2 and Red to account for. One more reason to avoid them.view [
button "Add one" on-click [
box: layout/only [box 0.100.0]
print ["size:" box/size "offset:" box/offset "box:" box]
]
]offset and size values yourself.100% * x ☻/ will coerce, and // will be integer divide.git installed?git clone https://github.com/red/red.gitcd redgit checkout GTKdo/args %red.r "-r environment/console/CLI/view-console.red"cd to it before compilingview-console.red in the described directory. It's possible you would need to create it (it's easy, don't be afraid :)console into view-console and add needs: view to it's header to proceedapt-get install libgtk:i386 (I'm not on Debian, so I don't know exact library name, sorry)Red[] do %atomica.red ; or how it's called view [] ; your gui here
#include fails if you later have to encapdo' or #include`view-console you compiledprobe system/options/boot check which executablef1: does [f2: does [print "Hello"] :f2]
do f1 or reduce f1 or do reduce f1 to output Hellodo reduce [f1].>> f1: does [f2: does [print "Hello"] :f2] == func [][f2: does [print "Hello"] :f2] >> do reduce [f1] Hello
probe to check intermediate results, to not act randomly ☺>> library: reduce ['f1 does [print "Hello"]] == [f1 func [][print "Hello"]] >> myselector: func [arg] [select library arg] == func [arg][select library arg] >> myselector 'f1 == func [][print "Hello"] >> do reduce myselector 'f1 == func [][print "Hello"]
Hellolibrary/f1 but I wish to use an intermediate function accessor to decouple the library from the end user.do reduce [f1] and do reduce myselector 'f1 ? ;)>> do reduce [myselector 'f1] Hello
>> a: [x [myselector 'f1]] == [x [myselector 'f1]] >> do select a 'x == func [][print "Hello"]
do by design does not evaluate functions given to itreduce **with a block**do reduce select a 'xreduce pose some limits into code sequences stored in blocks?x: load %code.red do xprobe I'll upload you a more fun tool.>> a: [x: [myselector 'f1]] == [x: [myselector 'f1]] >> probe reduce a [[myselector 'f1]] == [[myselector 'f1]]
>> show-trace [do reduce [myselector 'f1]] reduce [myselector ' => [func [][print "Hello"]] Hello do [func [][print "H => unset
20 20 at the end of the script, increase ;)print so it inserted a line inbetween.red --cli support history, or moving the cursor with arrow keys?word is variable?any-object! and function! are the only ones that provide contexts (but they are not contexts themselves), they are also called "context constructors" because of that.1 + 1+ is word?>> code: [1 + 1] == [1 + 1] >> foreach value code [print type? value] integer word integer
+ is word what is :? It's not word, right?get-* or set-* values, like e.g. ,:very/long/get/path or set-word:. And that part was also explained to you personally.[no space]view [button "sdf" on-alt-up [print "sf"]] alt-up is right mouse button./red -c -e -r -t macOS MyProgram.redMyProgram.app file but its only 748 bytes in size. It does not run.-c and the result is the same. Looks like compilation with macOS target is not working.-t darwin works but then it opens terminal window in addition to the view GUI. Is there a way to stop that?/Library/Application Support folder and then the last step with making a bundle was failing. Maybe there is some issue with path or permissions. Interesting thing is that when I was compiling with -t darwin then everything was working ok.a: 22 in the main code block, it is like you "declare" it to have value 22 in the system/words context (the default one). If you also create another context using myobj: make object! [a: 555 x: 33] you declare that in the context myobj also it has value 555. You can get the value of a in one or another context any time you want:a: 22 myobj: make object! [a: 555 x: 33] >> get in myobj 'a == 555 >> get in system/words 'a == 22
face/extra, creating an object with word/label couples. Have you any other good suggestions?csdesc in place of Customer Description.find-face, get-face you can extend it to find in various ways. You can also generate your VID spec programmatically, inserting set-words to reference faces, or set refs when building a view tree yourself.user-id its edit field will be composed to lbl-user-id, but I don't like this approach. Instead of relations defined naming rules I prefer relations defined by structure. Get-face is in R2, but not Red, but it was just a quick name that came to mind.get-face: func [spec][ switch/default type?/word spec [ word! [get spec] string! [] ; search via face/text issue! [] ; search via face/extra ][] ; default, search via face/data ]
Find* alternative can let you find a face in a pane block, which may have a fixed set of faces following it, so you just name key faces and get others based on that.get-face confused me. >> view [x: button]
>> get-face 'x
== make object! [
type: 'button
offset: 10x9
size: 78x27
text: none
image: none
color: none
men...face/extra ?[ ["a" 2] ["b" 3] ["c" 2] ]
[ ["b" 3] ["a" 2] ["c" 2] ]
sort/compare blk func [a b][a/2 > b/2], though I like to use /reverse to denote descending sorts.re: [
collect [
set name word! keep (reduce ["name:" name])
[
<begin> into re </begin>
|
end
]
]
]
probe parse [a <begin>[b <begin>[c]</begin>]</begin>] reinto is intended to be used with series! values. If you want to parse a linear structure and match opening/closing elements, then you need to maintain the stack yourself.into in your provided example.>> re: [collect [ahead word! keep (first [name:]) keep word! <begin> re </begin>]] == [collect [ahead word! keep (first [name:]) keep word! <begin> re </begin>]] >> parse [a <begin> b <begin> c </begin> </begin>] re == [name: a [name: b [name: c]]]
view/no-wait [button 100x100 "hello^/goodbye"]
>> append [1 2 3] [4 5 6] == [1 2 3 4 5 6] >> append/only [1 2 3] [4 5 6] == [1 2 3 [4 5 6]]
append/only blk newblkas-is flag? Otherwise all buttons will start wrapping. It can be worked around via manual sizing, but this is a new feature, so better not to break things if we can avoid it.wrap flag is unused for it.From trace-80.log
20/3-10:48:48.669-## Error in [task-handler-54776] : Make object! [
code: 903
type: 'internal
id: 'globals-full
arg1: none
arg2: none
arg3: none
near: [either pos: find/skip out name:]
where: 'decode-cgi
] !From chey-pid .log
20/3-14:20:57.331-## Error in [uniserve] : On-received call failed with error: make object! [
code: 311
type: 'script
id: 'invalid-path
arg1: 'root-dir
arg2: none
arg3: none
near: [cfg/root-dir req/in/path req/in/target]
where: 'rejoin
] !globals-full means you have exhausted the number of words Rebol2 can handle. You can just kill the worker tasks to spawn new clean ones. If that happens often, then you need a suicide code that will quit if the number of words in system/globals grows too close to the limit (IIRC, R2 has a limit around 32k).root-dir directive in the config section of the site or webapp. That's odd because IIRC, Cheyenne will auto-inject that property if not present already. So it might be a rooting problem leading to cfg not pointing to a valid configuration block.why/when is copy needed:>> a: [1 2 3 4] == [1 2 3 4] >> b: next a == [2 3 4] >> c: copy b == [2 3 4] >> index? b == 2 >> index? c == 1 >> head b == [1 2 3 4] >> head c == [2 3 4]
>> same? a b == false >> same? a head b == true >> equal? b c == true >> same? b c == false
>> view [s: slider [print s/data] text to-string s/data] *** Script Error: VID - invalid syntax at: [to-string s/data] *** Where: do *** Stack: view layout cause-error
to-string s/dataface here?view [s: slider [t/text: to-string s/data] t: text]
face points to current face, so you can use it even if your face has no name: input [print face/text] vs i: input [print i/text].word block or another word. So first variant syntactically 100% correct, but not working? How to debug such cases? >> view [s: slider t: text [t/text: to-string round s/data]] >> >> view [s: slider [t/text: to-string round s/data] t: text] ; that's right!
view [slider [t/text: to-string round face/data] on-change [print "change event"] t: text]
[t/text: to-string round s/data] will be evaluated, in all three cases?[t/text: to-string round s/data] will be evaluated, in both cases?t: text that will not happen. right?t: text mean in VID?[]?text do not changing?view [slider [t/text: to-string round face/data] on-change [print "change event"] t: text]
[t/text: to-string round face/data] what does this part mean in VID?[t/text: to-string round s/data] will be evaluated?on-change?view [
slider [
t/text: to-string round face/data
[
if face/data = 100% [print "Hello"]
]
] t: text
]do?widget block like: foo []do is calling under the hood? view [button [print "Hello"]]>> bin: to binary! mold system
>> length? bin
== 5111365
>> length? compress bin
== 4064159
>> length? compress/zlib bin
== 4064147
>> length? compress/deflate bin
== 4064141
>> i: make image! 5111x1000 / 1x4
>> i/argb: bin
>> length? save/as #{} i 'png
== 2663158gzip (Deflate algo) gives worst result of 2597500, whereas Red implementation of the same - 4064141 make-request function to simplify this stuff. It handles stuff like autoconversion to/from JSON or URL-encoding, authentication and other things. Feel free to ask about usage details.curl -X POST https://fax.twilio.com/v1/Faxes \ --data-urlencode "From=+1631999999" \ --data-urlencode "To=+1631444444" \ --data-urlencode "MediaUrl=https://www.twilio.com/docs/documents/25/justthefaxmaam.pdf" \ --u My_ID_cfwsedfwefewf:MY_PW_dewfdewcswf
ret: send-request/data/auth https://fax.twilio.com/v1/Faxes 'POST [From: "+1631999999" To: "+1631444444" MediaUrl: https://www.twilio.com/docs/documents/25/justthefaxmaam.pdf] 'basic [My_ID_cfwsedfwefewf MY_PW_dewfdewcswf]
/data field is just a Red block. Conversion to URL encoding is done automatically. If you provide map! instead of block!, data are converted to JSON. If you want full control over data type, provide a string! instead and no conversion is done. /auth takes two args, type - basic in your case (I believe, that's what -U does in curl) and block of user and pass. Again, conversion to an appropriate format is done automatically.send-request does a lot of work for you. You can add /verbose refinement to see what's send (good for debugging). send-request returns map! with four keys: [code headers raw data]. code is HTTP return code, headers are self-explanatory, raw are raw data and data are decoded data. If it receives, for example, JSON, it converts it to map! automatically, so there's again less work for the user./only refinement. /raw turns off auto-conversion of returned data and returns raw binary data./with refinement./raw is for returning data. Let me find my notes.send-request but to using Red as CGI. So it should work.. function. In example below I would like it to make the function filter (which takes 2 args) and convert it into an op so that it can be used as infix. So that it can be called like this:[ 1 2 3 4 ] . filter { |n| n % 10 = 0 }filter [ 1 2 3 4 ] { |n| n % 10 = 0 }.: function [ f ] [ make op! :f ]
reduce, or custom dialect preprocessorfilter anyway, so isn't it easier to make those operators in advance? like .filter: make op! :filterfilter itself useless probably, and is too much complexity (for what?)[ 1 2 3 4 ] |> multiply-by 3 |> sort
multiply-by takes 2 args - a list and a value to multiply by, and sort takes 1 arg.multiply-by: function [ a-list a-multiplier ] [ ... ]stepwise [ skip r 8 insert . "-" skip . 6 change . "-" skip . 3 clear . ]
. holds the result of last expression->: make op! func [○ body][ body: bind body 'body get/any also '○ until [ set/any '○ do/next body 'body tail? body ] ]
3 -> [ ○ * ○ + ○ form ○ reverse ○ load ○ ○ << (○ / ○) ]
dot at one point. Ended up not using mine nearly as much as I thought when I created it. And there's something funny about using advanced functional approaches to emulate imperative code. :^)context_1: [word_1, word_2, word_3]context_1: [word_1, word_2]context_2: [word_3] ; word_3 was re-bind with another context?object! value, not a list (block!) value. That being said, the answer to your question is that each _occurence_ of a word! value in the program text has its own context, and this can even be changed by the bind function.>> obj: object [a: 1]
== make object! [
a: 1
]
>>
>> context? 'a
== make object! [
datatype!: datatype!
unset!: unset!
none!: none!
logic!: logic!
block!: block!
par...
>>a should be context of obj?object! (among other values), provides a context to bind to, but is not a context itself.>> fifth spec-of :bind == [any-word! any-object! function!]
context [...] are synechdoches that we use in everyday speech.context? this gives you an object; the global context is equal to system/words.context? gave you an object, just like @meijeru said?context? is _either_ an object! value, _or_ a function! value (for arguments of functions). This is by the way explained in the spec document to which I referred in an earlier answer. I only mentioned object, in order to contrast it with block.object! and function! values currently reachable, if that makes sense at all.object! and function! values provide such tables for words to bind to. That's all there is to it, and that's what I keep repeating and rephrasing to you for months.[<spelling> <meaning>]
[foo :foo 'foo] → [["foo" <global context>] ["foo" <global context>] ["foo" <global context>]]
"car" is a vehicle "cat" is an animal "one" is an integer ...
[pi tail zero?] as an example:all are bound to the same (global) context (thesaurus)
[pi tail zero?] → [
["pi" ["pi" is 3.14159265353897932384 ...]]
["tail" ["tail" is an action that gives you the tail of a series ...]]
["zero?" ["zero?" is a predicate that returns true if value is zero ...]]
]set or set-word!. In our model that would the same as taking the spelling, taking thesaurus, searching for spelling in it and putting a new value.>> thesaurus: ["pi" 3.141592653589793] == ["pi" 3.141592653589793] >> pi == 3.141592653589793 >> put thesaurus "pi" "pie" == "pie" >> pi: "pie" == "pie" >> thesaurus == ["pi" "pie"] >> copy/part find body-of system/words 'pi 2 == [pi: "pie"]
alias for that), but meaning can. This is what bind does, it changes the meaning of a given word by *changing the link to thesaurus that it contains*.>> word: ["pi" ["pi" 3.141592653589793]] == ["pi" ["pi" 3.141592653589793]] >> pi == 3.141592653589793 >> word/2: ["pi" "pie"] == ["pi" "pie"] >> word == ["pi" ["pi" "pie"]] >> bind 'pi context [pi: "pie"] == pi >> get bind 'pi context [pi: "pie"] == "pie"
'pi and the second 'pi are different, and binding one does not affect the other (or any other pis you might have in your code).>> cutlery: [spoon spoon spoon spoon] == [spoon spoon spoon spoon] >> phrase: split "there is no spoon" space == ["there" "is" "no" "spoon"] >> forall cutlery [bind cutlery context [spoon: take phrase]] == [spoon] >> cutlery == [spoon spoon spoon spoon] >> print cutlery there is no spoon
cutlery looks like under the hood:[
["spoon" ["spoon" "there"]]
["spoon" ["spoon" "is"]]
["spoon" ["spoon" "no"]]
["spoon" ["spoon" "spoon"]]
]>> forall cutlery [print context? cutlery/1] spoon: "there" spoon: "is" spoon: "no" spoon: "spoon"
text make*: func [spelling [string!] meaning [block!]][ reduce ['spelling spelling 'meaning meaning] ] set*: func [word [block!] value [any-type!]][ put word/meaning word/spelling value ] get*: func [word [block!]][ select word/meaning word/spelling ] bind*: func [word [block!] meaning [block!]][ word/meaning: meaning ]
global-context: ["spoon" unset!] cutlery: reduce [ make* "spoon" global-context make* "spoon" global-context make* "spoon" global-context make* "spoon" global-context ] phrase: split "there is no spoon" space forall cutlery [bind* cutlery/1 reduce ["spoon" take phrase]] probe new-line/all cutlery on print collect [forall cutlery [keep get* cutlery/1]]
REBOL/Core 2.7.6.4.2 (14-Mar-2008) >> get none == none --== Red 0.6.4 ==-- >> get none *** Script Error: get does not allow none! for its word argument *** Where: get *** Stack:
none because of the common idiom get in object 'word - if object has no word then in returns none.>> select object [a: 1] 'a == 1 >> select object [a: 1] 'b == none
name: "Mike" we are add word and it's value to context table. right?parse ignores the binding of it's keywords, it just reads the word name (e.g. "some") and acts accordingly.name: "Mike" we are add word and it's value to context table. right?get, and it is applicable to objects, where it gives the same result as values-of. This seems redundant. The only reason I can think of is the symmetry with set which can set the values of object fields to the contents of a block...x: 123 but in function context it can be x: [some block]. And we can bind word from one context to another from 123 to [some block]probe reduce [aword aword aword] you should have a block with 3 different values.values-of etc. were added much later to R2, so get behavior is more legacy than anything else.REBOL/Core 2.5.0.3.1 Copyright 1997-2001 REBOL Technologies >> get none ** Script Error: get expected word argument of type: any-word ** Near: get none
clear system/console/history ?C:\Users\\AppData\Roaming\Red\Red-Console\console-cfg.red on Win10.word at startup as option, and associate it to the main, invisible, block, do you think it would be equally dangerous?abs: :absolute
sqrt and square-root, so why not? You will find sqrt is a routine with a Red/System call to the native square-root. So for efficiency one could make abs a routine that calls the action absolute....text > >> cutlery: [spoon spoon spoon spoon] > == [spoon spoon spoon spoon] > >> phrase: split "there is no spoon" space > == ["there" "is" "no" "spoon"] > >> forall cutlery [bind cutlery context [spoon: take phrase]] > == [spoon] > >> cutlery > == [spoon spoon spoon spoon] > >> print cutlery > there is no spoon >
cutlery looks like under the hood:text > [ > ["spoon" ["spoon" "there"]] > ["spoon" ["spoon" "is"]] > ["spoon" ["spoon" "no"]] > ["spoon" ["spoon" "spoon"]] > ] >
text > >> forall cutlery [print context? cutlery/1] > spoon: "there" > spoon: "is" > spoon: "no" > spoon: "spoon" >
abs: :absolute
abs: :absolute too ;) Should we PR it? @greggirwin >> words: [a b c] == [a b c] >> fun: func [a b c][print bind words 'a] *** Script Error: func is missing its c argument *** Where: func *** Stack: func
>> words: [a b c] == [a b c] >> fun: func [a b c][print bind words 'a] == func [a b c][print bind words 'a]
func ???func: func [a b c][print bind words 'a] somewhere down the line.words: [a b c]
fun: func [a b c][print bind words 'a]
fun 1 2 3
fun "hi" "there" "fred"words at first step should become 1 2 3abs some time back, and it was decided not to include it. It's a nice shortcut, and probably used more than sqrt, which I am surprised to learn is there. My 2012 function counts, from various R2 scripts, show abs count at 500, and absolute | square-root at 10 each. For comparison, if is ~29K and func ~26K in that list.sqrt. It's not used in the codebase today. Aliasing abs to absolute is easy enough, and people may reach for it. I don't care about the typing as much as the reading. But it's also not a showstopper. sqrt, leave abs for later, and let @dockimbel weigh in.abs despite your efforts? Oh I see, it was included in R2, so the numbers will be lower than 98% ;)abs count at **500**, and absolute | square-root at **10** each. For comparison, if is ~29K and func ~26K in that list.absolute: 36 abs: 133 (21 to 78%) (from what I can tell 5 absolute hits are if absolute where absolute is a refinement flag)absolute more readable than abs?Abs seems comfortable, even spreadsheets use it. But it's not a complete word, which Redbol langs favor over abbreviations. It's better than absolute-value, if anybody wants to go there. ;^) On readability, though, abs is nicer in formulae, but is it *always* better? Here are some examples of its use in Red right now:a: absolute a r: mod a absolute b if hours [hours: absolute hours] mins: absolute mins n: absolute end-idx - start-idx
abs, then we should probably remove absolute. Means about a half dozen uses in the code base to change. Then do we also use abbreviated names for all trig funcs? Is consistency important there, and as a future precedent?abs v absolute, but how many abs cases there are rel to other funcs. I had another thought, but it would be a tan.abs in the scripts you've found. Are you saying it's 210?tan and tangent as separate implemetations is hoffific, thanks @greggirwin for giving attention!a, b, c are printed from inside function. After exiting function, they are not accessible anymore. To access a, b, c after function has finished you need to assign their values in glogal context, e.g.>> fun: func [d e f][print set words reduce [d e f]] == func [d e f][print set words reduce [d e f]] >> fun 1 2 3 1 2 3 >> a == 1 >> fun "hi" "there" "fred" hi there fred >> print words hi there fred
set words [1 2 3]
a-word: second first context [rebol: 1]
>> a-word: second first context [rebol: 1] *** Script Error: first does not allow object! for its s argument *** Where: first *** Stack: second first
first reflector was far too esoteric to keep>> a-word: first words-of context [red: 1] == red
context?>> next fifth spec-of :bind == [any-object! function!]
>> bind 'pi context [pi: "pie"] == pi
'pi is bind with context of object. Right?>> bind 'x context [x: 123] == x >> context? x *** Script Error: x has no value *** Where: context? *** Stack:
>> get bind 'x context [x: 412] == 412 >> get 'x ; why this do not work?! *** Script Error: x has no value *** Where: get *** Stack:
bind does not (and *can not*) modify the word given. It returns a new word.bind to modify a word given. The problem is that people confuse one particular instance of the word with other words that look the same.>> stack: []
== []
>> append stack bind 'x context [x: 1]
== [x]
>> context? stack/1
== make object! [
x: 1
]
>> get stack/1
== 1
>> append stack 'x
== [x x]
>> system/words =? context? stack/2
== true
>> get stack/2
*** Script Error: x has no value
*** Where: get
*** Stack:>> get bind 'pi context [pi: "pie"] == "pie" >> pi == 3.141592653589793
>> insert x: [] bind 'x context [x: 123] == [] >> x == [x] >> reduce x == [123]
bind saysword param that the arg is *not* rebound. Should we?Compiling to native code... *** Loading Error: file access error: %definitions.reds
pi examples. That is, bind's result is a "use it or lose it" proposition, isn't it?1 + 2, if it doesn't modify either argument to 3 and if you don't use the returned sum, then would you say that it "doesn't add"?#include work differently in **encap** mode? I get *** Compilation Error: include file not found error.prompt$ red.dms SQLite3-test.red *** Internal Error: contains Red/System code which requires compilation *** Where: do *** Stack: do-file
> red -c SQLite\SQLite3-test.red
-=== Red Compiler 0.6.4 ===-
Compiling C:\red\SQLite\SQLite3-test.red ...
...using libRedRT built on 8-Apr-2020/18:24:41
...compilation time : 125 ms
Target: MSDOS
Compiling to native code...
*** Compilation Error: undefined symbol: zerofill
*** in file: %/C/red/SQLite/SQLite3.red
*** at line: 9567
*** near: [
zerofill dbs-head dbs-tail
close-dbs: func [
/local
p [pointer! [integer!]]
] [
p: dbs-head
while [p < dbs-tail] [
if p/value <> 0 [
print-line ["closing db: " as pointer! [integer!] p/value]
sqlite3_close as pointer! [integer!] p/value
p/value: 0
]
p: p + 1
]
]
get-db-ptr:
]
Dima@MACHINE-FCGCTD2 C:\redset and in. Set being the key comparison. -r flag).https://github.com/red/code/tree/master/Library/SQLite
definitions.reds
definitions.reds SQLite3-test-basic.reds SQLite3-test.red SQLite3-test.reds SQLite3.red SQLite3.reds
SQLite3.reds
#include %definitions.reds ;common aliases and defines
red.dms -r SQLite3-test.red
SQLite3-test
call>> x: 1 >> o: context [x: 2] >> b: [x] >> reduce b == [1] >> bind b o >> reduce b == [2] >> get b/1 == 2 >> x == 1
x is the same x which bound to o, so I get 2 each time.x, it is not the same x with the above one in the b block.>> bind 'x o >> x == 1 >> get bind 'x o == 2
xs are same, hence they should bound to o.Rebol [] ... bind 'x o print x ; expected 2, but it was 1.
>> view[t: text-list data["aa" "bb" "cc"] on-select [print [pick t/data t/selected] ]] none aa bb
selected return -1 index so all work incorrecton-changeview inside another?view[t: text-list data["aa" "bb" "cc"] on-change [ view [ b: button do [ b/text: pick t/data t/selected ] ]] ]
view/flags [] 'modal (to disable the lower windows until one closes the top one) but that's glitchy right now, so not advised.do %your-script.reddo I am getting message:>> do %app.red *** Internal Error: contains Red/System code which requires compilation
print "hello world!" on line 31 here https://github.com/red/red/blob/master/environment/console/CLI/console.red and compile it. Then replace hello world with anything you want.open:>> db1: open %/D/code/fas_2020/parser_gui/test.db *** Script Error: open does not allow file! for its port argument *** Where: open *** Stack:
-u -c), you can henceforward compile it in development mode (i.e. with -c only) which is much faster. result: [] ;preallocating block for results
test: SQLite/do [
db1: open %test.db
result: exec "SELECT name FROM Cars ORDER BY name"
]
print result ; should not have any data before I will do: `do test`SQLite/do already. Of course result is filled. To call it on demand, put it into function and call when needed.SQLite/do [
db1: open %test.db
]
result: [] ;preallocating block for results
view[
button "load" [
SQLite/do [
result: exec "SELECT name FROM Cars ORDER BY name"
]
append t/data result
]
t: text-list data []
]
SQLite/free ;closes all opened DBs and frees SQLite resourcest?x: [1 2 3 4 5]x: [1 3 4 5]remove at x 2x: copy [1 2 3 "" 4 "" "" 5] temp: copy [] repeat i (length? x) [if x/(i) <> "" [append temp x/(i)]] x: temp probe x
>> x: [1 2 3 "" 4 "" "" 5] == [1 2 3 "" 4 "" "" 5] >> remove-each val x [val == ""] >> x == [1 2 3 4 5]
remove-eachis a native and as I remember from R2, it was also nicely fast. I really like the function and wished to have a keep-eachcounterpart, thought it might be easy to get as a mezzanine wrapper ....x: [1 2 3 "" 4 "" "" 5] probe replace/all x "" []
view [image fstk-logo]
remove at x 2>> x: [1 2 3 4 5] == [1 2 3 4 5] >> >> remove at x 2 == [3 4 5]
[1 3 4 5]>> help remove
USAGE:
REMOVE series
DESCRIPTION:
Returns the series at the same index after removing a value.
REMOVE is an action! value.remove is the series at the point where you did the remove. If you want to go back to the beginning, use head.>> ssid: "FOTOATELIÉR Jana Marková"
== "FOTOATELIÉR Jana Marková"
>> bin-ssid: to-binary ssid
== #{464F544F4154454C49C38952204A616E61204D61726B6F76C3A1}
>> foreach byte bin-ssid [prin byte]
7079847965846976731951378232749711097327797114107111118195161prin to-hex/size byte 2 ?>> foreach char ssid [prin to-binary char]
#{46}#{4F}#{54}#{4F}#{41}#{54}#{45}#{4C}#{49}#{C389}#{52}#{20}#{4A}#{61}#{6E}#{61}#{20}#{4D}#{61}#{72}#{6B}#{6F}#{76}#{C3A1}>>repeat n length? bin-ssid[prin rejoin[to-hex/size bin-ssid/:n 2"\"]] 46\4F\54\4F\41\54\45\4C\49\C3\89\52\20\4A\61\6E\61\20\4D\61\72\6B\6F\76\C3\A1\
collect/into [foreach byte bin-ssid [keep to-hex/size byte 2 keep #"\"]] out: clear ""
== {46\4F\54\4F\41\54\45\4C\49\C3\89\52\20\4A\61\6E\61\20\4D\61\72\6B\6F\76\C3\A1\}head if you want to use result of remove as argument to another func or set something to it. If not, you can just use x further without head. (That is if you haven't done x: remove at x 2)>> mold bin-ssid
== {#{464F544F4154454C49C38952204A616E61204D61726B6F76C3A1}}
>> str: "464F544F4154454C49C38952204A616E61204D61726B6F76C3A1"
== {464F544F4154454C49C38952204A616E61204D61726B6F76C3A1}
>> foreach [high-byte low-byte] str [prin rejoin ["\" high-byte low-byte]]
\46\4F\54\4F\41\54\45\4C\49\C3\89\52\20\4A\61\6E\61\20\4D\61\72\6B\6F\76\C3\A1parse s: enbase/base ssid 16 [any [insert "\" 2 skip]] s>> str: head remove back tail remove remove mold bin-ssid
== {464F544F4154454C49C38952204A616E61204D61726B6F76C3A1}
>> foreach [high-byte low-byte] str [prin rejoin ["\" high-byte low-byte]]
\46\4F\54\4F\41\54\45\4C\49\C3\89\52\20\4A\61\6E\61\20\4D\61\72\6B\6F\76\C3\A1>> foreach [high-byte low-byte] enbase/base ssid 16 [prin rejoin ["\" high-byte low-byte]] \46\4F\54\4F\41\54\45\4C\49\C3\89\52\20\4A\61\6E\61\20\4D\61\72\6B\6F\76\C3\A1
fail when parse rule is false?true. But I do not see any reason why. true\false are logical type:view [
f: field b: button "Parse" [
x: parse f/text ["aabb"]
t/data: to string! x
print x
]
t: text
]to string! but I do not understand why it's neededto string!view [
f: field b: button "Parse" [
x: parse f/text ["aabb"]
t/data: x
]
t: text
]false in interface, but only truefalse as a signal to clear the text. Probably an oversight, as it should happen only with none.parse "aa" ["aa"]./text return quoted data. How I can do it?view [
f-data: field
f-rule: field
b: button "Parse" [
result: parse f-data/text [{"}f-rule/text{"}] ; this line
print f-data/text
print f-rule/text
t/data: to-string result
]
t: text
]f-rule/text is already a string, why do you need extra quotes around it?invalid rule or usage of rule: f-rule/textdata/data instead, dunno.f-data/text = f-rule/text?test1file:
Red[] total: 1 + 2 print ["total: " total]
a: ""
call/shell/output {./test1} a
print atotalas a variable back to Red (or get
totalinto a )?
do a? ;)test1:
Red[] total: 1 + 2 print total
total: ""
call/console/output {./test1} total
print ["total: " total]view[
do [repeat y 5 [ button "hi" ] ]
]x: repeat y 5 [collect [keep 'a]]
a five timescollect to include a five times. How would you do that?-d flag to see the detailed stack trace, and make sure that you use the latest automated build rather than an outdated one.v: []
append v collect [ loop 5 [ keep [ b: button "hi" ] ] ]
; v/1/b/text: "aaa" ; do not work
view vprobe v to see what it isv: []
append v collect [ loop 5 [ keep [ b: button "hi" ] ] ]
probe v/3: "aaa"
view va: "test1"
b: "test2"
form reduce [a {"} b {"}]== {test1 " test2 "}{test1 "test2"}Red[] total: 1 + 2 print total
a: ""
call/shell/output {./test1} a
print aashould be
3but it's not printing anything
{.\test1} on Windows, so.. you sure you have the rights to execute test1?chmod 777?call bug to me/shell?call/output?/shell? Maybe the shell does not properly inherit the current working directory, or it's broken totally on Mac.a: ""
b: "./test1"
d: form rejoin ["{" b "}"]
append d { a}
print ["d: " d]
; it gives me d: {./test1} acall/output dand
call/output reduce dgives me an error
*** Script Error: call/output is missing its out argument
/output needs a string obviouslyz: copy ""
call/output {./test1} z
print ["z: " z]call/console {./test1}["1" "test1" "test2" ] ["2" "jenn1" "jenn2" ] ["3" "rob1" "rob2" ] ["3" "cast1" "cast2" ]
file1: read/lines %test.txt
file1/2
["2" "jenn1" "jenn2" ]
a: {
["1" "test1" "test2" ]
["2" "jenn1" "jenn2" ]
["3" "rob1" "rob2" ]
["3" "cast1" "cast2" ]
}
b: read/lines a*** Script Error: read does not allow string! for its source argument
d: form rejoin ["{" b "}"] can be broken down into pieces, to see what form and rejoin each do, as well as using help. Also, where other langs force you to use strings or numbers everywhere, remember to leverage Red's datatypes as much as possible. For example, look at the help for call, and you'll see it can also take a file! type. help read. What does that tell you?read/linesconverts a file into lines. is there a command that converts a string into lines ?
load or convert data to Red values. And keep in mind that Red doesn't care about newlines, so if you need to treat things as strings that way, you may need to use another approach to split the data, but that may lead to other issues.help to find where something is mentioned anywhere in the spec for functions. e.g. if you do ? "lines" what funcs show up?new-line marker in a Red series, compared to a newline character in strings. Once you do, it opens a lot of doors in how you choose to process data, making it easy to work with Red values, then format them easily for writing to files and such.On a text file with a 1 million lines, it takes over 4 minutes for ```load``` to read it and convert it (sometimes it even crashes), when with ```read/lines``` only a few seconds right now I am using read/lines to search and when I find the line I need, I then convert it with ```Load```read/lines
is very fast and works great with files. I was looking for the equivalent command that would convert a string to a block of strings here is what I found when searching forline
`help "lines" where the arg is a string. Use help help to learn more. And the new fast lexer will make a big difference for you, but if you're dealing with that much data, you may want to process on demand. Look at my message above, and the highlighted words, like split. You can also use parse as you learn more.view [f: field on-change [if f/text = 123 [ f/color: red] ] ]
"123"suffix?gets the suffix of the file. is there a command that gets the name (string before suffix)
a: "test.pdf" either find/last a "." [ in: index? find/last a "." name: copy/part a in - 1 ][ name: copy a ] print name
Help copy, note that /part can take a series, so you can copy from one offset to another, without having to convert to integer indices.name: twice to reassign. A key element in Red is that functions (expressions) return useful results, so you can use name: either [..., which also makes the intent clearer.f: %test.pdf
name: either pos: find/last f %. [
copy/part f pos
][
copy f
]
print nameeither and two different types of calls to copy.f: %test.pdf name: copy/part f any [find/last f %. tail f] print name
any. Any and all are some of your best friends in Red.react? >> x: reactor [a: 0 b: 0 c: is [a + b]]
== make object! [
a: 0
b: 0
c: 0
]
>>
>>
>>
>> x/a: 5
== 5
>>
>> react? x
*** Script Error: react? is missing its field argument
*** Where: react?
*** Stack: react?
>> react? x/c
*** Script Error: react? does not allow integer! for its reactor argument
*** Where: react?
*** Stack: react?
>>view [f: field on-change [if f/text = "123" [ f/color: red] ] ]view [f: field react [] ]
view [f: field react [f/color: [ ] ] ]
react-test*.red files.>> x: reactor [a: 0 b: 0 c: is [a + b]]
== make object! [
a: 0
b: 0
c: 0
]
>> x/a: 5
== 5
>> x/b: 2
== 2
>> x
== make object! [
a: 5
b: 2
c: 7
]
>> react? x 'a
== [a + b]
>> react? x 'b
== [a + b]
>> react?/target x 'c
== [a + b]fun: func[value] [either value = "123" [red] [none] ] view [ f: field react [face/color: fun face/text] ]
view [f1: field f2: field f3: field react/link :fun [f1 f2 f3] ]
fun for all fields. But this code cause errorcontrols: layout [f1: field f2: field f3: field] foreach c controls/pane [ react/link :fun [c/text] ]
REACT - reactive functions must accept at least 2 arguments fun: func [o1 o2 o3][print rejoin [o1/text lf o2/text lf o3/text]] view [f1: field f2: field f3: field do [react/later/link :fun [f1 f2 f3]]]
faced. For example I want to specify text and offset for button. view [b: button b/text: "text" offset ... ]
[] like: view [b: button [b/text: "text" b/offset ... ]but I want to do it without any actions
view [button 50x50 "text"] but what is their order?>> ? b
B is an object! with the following words and values:
type word! button
offset pair! 10x9
size pair! 78x27
text none! none
image none! none
color none! none
menu none! none
data none! noneoffsetface object (model is called face!) and VID describes the dialect which allows the system to construct the objects. The VID interpreter sees a pair! value somewhere, and concludes it is intended as the size field of the face being constructed. That's how it works. b?view [b: button]>> view [at 100x200 b: button "hello"]
>> ? b
B is an object! with the following words and values:
type word! button
offset pair! 99x199
size pair! 62x27
text string! "hello"
...100x200 is the offset, but has applied internal rules for positioning. There was no other pair for the size of the button, so the size was taken from the defaults. What else do you not understand?100x200 is the offset, but has applied internal rules for positioning. There was no other pair for the size of the button, so the size was taken from the defaults. What else do you not understand?at is the keyrejoin?>> to-file "D:\folder" == %D:\folder
%D:\folder\to-file "D:\folder\" ?append to-file "D:\folder" "\"dirize can work with to-red-file>> dirize to-red-file "D:\folder\a" == %/D/folder/a/
>> normalize-dir %folder == %/C/Users/Toomas/Documents/Red/folder/ >> to-local-file normalize-dir %folder == "C:\Users\Toomas\Documents\Red\folder\"
xml-files: ["1.xml" "2.xml"] view [ text to-string do [length? xml-files] ]
*** Script Error: VID - invalid syntax at: [to-string do [length? xml-files]] *** Where: do *** Stack: view layout cause-error
to-string is not a VID keyword?composexml-files: ["1.xml" "2.xml"] view [ compose [ text (length? xml-files) ] ]
compose is mentioned[ you're in a Red context, after [ you're in VID context. It's like a fence - if you're trespassing, be prepared ;)data keyword:>> xml-files: ["1.xml" "2.xml"] == ["1.xml" "2.xml"] >> view [text data length? xml-files]
dir? is seems to be ok. But how to check both cases in one expression (to reduce code size). dir? do not accept empty field with none so I need to write two if expressions. if dir? folder and if folder not none (not sure about syntax). What is the short way to check both?dir? expects file! or url!... so you should check it too. I don't know what is your input and if you expect just files or also urls.[reduce compose find select append insert], objects, maps, and more. This will make your life *so* much easier. Then move back into View and VID, understanding that dialects can offer different semantics, including keywords, than Red itself. do-events/no-wait in loops, to let the system breathe.rate on a face, which gives you a "timer" event that you can use to trigger processing. You can also try adding do-events/no-wait (maybe 2-3 times even) inside your foreach xml-file loop, which should let the UI refresh.fwords: [
'func | 'function | 'funct | 'has | 'does
]
get-functions: func [
"Recursively search for all funcions in a block of code and prints them with associated specs"
code [block!]
/into
]
[
if into [code: first code]
parse code [
any [
[to set-word! copy fname thru set-word! 1 fwords copy specs block! (prin [first fname " "] probe first specs)] |
[thru 'set copy fname [word! | lit-word!] fwords copy specs block! (prin [first fname " "] probe first specs)] |
[copy a-block 1 block! (get-functions/into a-block)] | skip
]
]
]does has no spec ☻does to accept a specs block, so I don't have to modify my code? 😁>> find/last "/d/folder/subdolder/sub2/sub3/foo.txt" "/" == "/foo.txt"`
sub3/foo.txtfind but I can't think of any variants how to mix it with skip or second (I think I thould use them)find/lasttwice? ? find and study what options it provides. And think how can you go from your find/last into another find call that would return exactly what you need.>> f: "/d/folder/subdolder/sub2/sub3/foo.txt" == "/d/folder/subdolder/sub2/sub3/foo.txt" >> find/reverse find/reverse tail f "/" "/" == "/sub3/foo.txt" >> find/reverse/tail find/reverse tail f "/" "/" == "sub3/foo.txt"
find/reverse is the lightest variant. And you could use just #"/" instead of "/"probe without newline?prin moldf: tail "/d/folder/subdolder/sub2/sub3/foo.txt" f: next loop 2 [f: find/reverse f #"/"] == "sub3/foo.txt"
view [ buttons-group-1: [button button] buttons-group-2: [button button] panel red buttons-group-1 panel blue buttons-group-2 ]
buttons-group-1: [button button]
buttons-group-2: [button button]
view [
panel red buttons-group-1
panel blue buttons-group-2
]call. Is it possible to create a red prog that on exiting returns something (like a string or a block) that can be used by another red program which initiated the call?/output.view [...]) and the regular Red programming (all the words and other values that are outside of view [...].func **[arg]** [] --red-only that will show you just that. The analysis, figuring out what would benefit from conversion to R/S, could be done at the Red level though. Don't expect much speedup though. If you're using Red "properly", you're making use of the runtime, rich datatypes, etc., none of which exist at the R/S level. R/S is great if you're doing repetitive math on basic numbers, or old-school string processing. Beyond that, you'll be implementing your own special purpose code in R/S for specific needs. print("Please select Order") funny style ;)>> tree: func [path /local full dir][dir: read path foreach file dir [print full: rejoin [path file] if dir? file [tree full]]] >> tree %./
/D/zak_data/Moskva/notice/notification_Moskva_2020030400_2020030500_001.xml/fcsNotificationZK504_0373200006620000042_23063229.xml *** Script Error: reset-buffer does not allow vector! for its <anon> argument *** Where: reset-buffer *** Stack: tree tree tree tree
read-folder-recursive: function [ dir- ][ file-list: [] dir-: to-red-file dir- foreach file read to-red-file dir- [ file-: either dir- = %./ [file][dir-/:file] append file-list to-local-file file- if dir? file- [ read-folder-recursive file- ] ] new-line/all file-list on file-list ] block: read-folder-recursive %/C/RED/ ; Change the dir to a readable dir, not C:\Windows\ C:\Program Files\, etc probe block ; do anything you like with this block
read-folder-recursive: function [
dir- [file!]
][
collect [
foreach file- read dir- [
file-: rejoin [dir- file-]
either dir? file- [
keep read-folder-recursive file-
][
keep file-
]
]
]
]
block: read-folder-recursive %/C/RED/
probe blockrecdir: function [ folder ][ stack: copy [] foreach item read folder [ either dir? item [ ; Is it a folder? append stack item ; Put folders onto a stack ][ ; it's a file ; Here you can put the files into a block defined outside the function! ; You may change "to-local-file" into "to-file" ; or "to-red-file" (which is the same) probe to-file rejoin [folder item] ; Join folder and file ] ] ; Process folders one at a time foreach item stack [ recdir to-red-file rejoin [folder item] ; Call function with the joined folder and file (this is the recursion) ] ] folder: %/C/RED/ recdir folder
/text field of every field. aa: collect [loop 10 [keep [f-name: field hint "file_name" f-date: field hint "xml_date" return]]]
view[
panel aa
button "load" [
foreach a aa [ if word? a [ print [type? a ] ]] ; Am I thinking right?
]
t: text-list data [];-----------------------------------------------------------------------
; READ FOLDER TO BLOCK ITERATIVE
;-----------------------------------------------------------------------
read-folder-iterative: func [ ; do not use function!
"Read a folder iterative" folder [url! string! file!] /filter list [block! string!] /local stack paths
][
stack: copy [] fileblock: copy []
case [
type? folder = url! [folder: to-red-file to-string folder]
type? folder = string! [folder: to-red-file folder]
]
if not(%/ = back tail folder) [append folder %/]
append stack folder ; PUSH ONTO STACK
while [not (empty? stack)] [ ; stack is empty?
folder: last stack remove back tail stack ; POP FROM STACK
read-folder: read folder
foreach item read-folder [
either dir? rejoin[folder item] [ ; is it a folder?
append stack rejoin[folder item] ; PUSH ONTO STACK
][ ; it's a file
; apply filter
either filter [
foreach filteritem list [
if find item filteritem [
append fileblock rejoin[folder item]
]
]
][
append fileblock rejoin[folder item]
]
]
]
]
; paths and files
paths: copy [] files: copy []
foreach file fileblock [
splitted: split-path to-red-file file
append paths splitted/1
append files to-local-file file
]
; create a file-object
file-object: copy []
append file-object rejoin [[filecount:] length? fileblock]
append file-object rejoin [[mapcount:] length? unique paths]
append file-object rejoin [[files:] sort files]
do file-object
file-object
]
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
comment {
; Almost anything goes:
; FOLDER AS FILE
read-folder-iterative %/C/RED/DATAFILES
read-folder-iterative %/C/RED/DATAFILES/
read-folder-iterative %\C\RED\DATAFILES
read-folder-iterative %\C\RED\DATAFILES\
; FOLDER AS STRING
read-folder-iterative "C:\RED\DATAFILES"
read-folder-iterative "C:\RED\DATAFILES\"
; FOLDER AS URL
read-folder-iterative C:\RED\DATAFILES
read-folder-iterative C:\RED\DATAFILES\
; even mixed
read-folder-iterative %/C\RED\DATAFILES
read-folder-iterative %/C\RED/DATAFILES
;FILTER AS FILE
read-folder-iterative/filter C:\RED\DATAFILES\ [.exe .png]
;FILTER AS STRING
read-folder-iterative/filter C:\RED\DATAFILES [".exe" ".png"]
; Except the following:
read-folder-iterative \c\RED ; this does not work, invalid value
read-folder-iterative /c/RED ; this does not work, because it is a refinement
}
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; Two examples:
;-----------------------------------------------------------------------
r: read-folder-iterative %/C/RED/INC/
print ["Files: " r/filecount]
print ["Folders:" r/mapcount]
foreach file files [
print file
]
;-----------------------------------------------------------------------
r: read-folder-iterative/filter C:\RED\ [.txt]
foreach file files [
print file
]
;-----------------------------------------------------------------------Type? will return the datatype, which you've already checked as word?. But set-word! values (ending in colons) won't match that. The main thing is not to confuse the type? function with the /type facet for a face. flds: collect [
repeat i 10 [
keep compose [
(to set-word! join 'f-name- i) ; give each a unique name
field 150 hint "file_name"
(to set-word! join 'f-date- i) ; give each a unique name
field 150 hint "xml_date" return
]
]
]
view [
p: panel flds
button "load by name" [
foreach fld flds [
if set-word? fld [
face: get fld
face/text: rejoin ["My name is: " fld]
]
]
]
button "load by face type" [
foreach face p/pane [
if face/type = 'field [
face/text: rejoin ["I'm at offset: " face/offset]
]
]
]
t: text-list data []
]flds contains, when generated from the above. value? 'wordunset? 'wordf-name name. They should be different, otherwise you will always reference the lasts one accessing data via f-name[item loaded rest of series! any error!] now just item or error?Type? will return the datatype, which you've already checked as word?. But set-word! values (ending in colons) won't match that. The main thing is not to confuse the type? function with the /type facet for a face. >> flds: collect [ [ repeat i 10 [ [ keep compose [ [ (to set-word! join 'f-name- i) [ field 150 hint "file_name" [ (to set-word! join 'f-date- i) [ field 150 hint "xml_date" return [ ] [ ] [ ] *** Script Error: join has no value *** Where: to *** Stack: collect
(to set-word! rejoin ['f-name- i]) ; give each a unique name(to set-word! join 'f-name- i)flds: collect [
repeat i 10 [
keep compose [
(to set-word! rejoin ['f-name- i]) ; give each a unique name
field 150 hint "file_name"
(to set-word! rejoin ['f-date- i]) ; give each a unique name
field 150 hint "xml_date" return
]
]
]
view [
p: panel flds
button "load by name" [
foreach fld flds [
if set-word? fld [
face: get fld
face/text: rejoin ["My name is: " fld]
]
]
]
button "load by face type" [
foreach face p/pane [
if face/type = 'field [
face/text: rejoin ["I'm at offset: " face/offset]
]
]
]
t: text-list data []
]index on foreach loop? Like in some C-style language foreach(index, r; result) { }?print probe result show me: [
1 "4171" {fcsNotificationEA44_0138200004020000001_22657730.xml} "20200101"
2 "4172" {fcsNotificationEA44_0148300001519000068_22643157.xml} "20200101"
3 "4173" {fcsNotificationEA44_0148300001519000069_22643116.xml} "20200101"
4 "4174" {fcsNotificationEA44_0148300001519000070_22643084.xml} "20200101"
5 "4175" {fcsNotificationEA44_0148300001520000001_22647833.xml} "20200101"
]? extractx: [
1 "4171" {22657730.xml} "20200101"
2 "4172" {22643157.xml} "20200101"
3 "4173" {22643116.xml} "20200101"
4 "4174" {22643084.xml} "20200101"
5 "4175" {22647833.xml} "20200101"
]
>> extract/index x 2 3
== ["22657730.xml"
2 "22643157.xml"
3 "22643116.xml"
4 "22643084.xml"
5 "22647833.xml"
]extract docs once again. width is a size of a "row", /index specifies index of a "column" in this "row"./index refinement ;)red --catch init.red, and start the console with it.red executable to that batch, of course.init.red is in that place already.locate config.red # pierre@latitude: ~ < 2020_04_19__19:19:29 > [bashpid_9668] cat > config.red Red [] "Tentative de faire un féchier de config, à l'aveugle. print "Coucou" # pierre@latitude: ~ < 2020_04_19__19:20:20 > [bashpid_9668] red GTK VERSION: 3.24.5 --== Red 0.6.4 ==-- Type HELP for starting information. >> # pierre@latitude: ~ < 2020_04_19__19:20:26 > [bashpid_9668]
console-cfg.red# pierre@latitude: ~ < 2020_04_19__19:36:05 > [bashpid_9668] locate console-cfg.red /home/pierre/heaume_pierre/.wine/drive_c/windows/profiles/All Users/Red/console-cfg.red # pierre@latitude: ~ < 2020_04_19__19:36:15 > [bashpid_9668]
~/.Red-Console/ or somewhere.wine%user.red or %red.redif democracy [ vote: vote + 1 ]
~/.Red-Console/ or somewherexubuntugit pulled the red sources from github, and I tried to compile a Red interpreter, referring to the way I had done it in the past.do/args %red.r "%environment/console/console.red" => do/args %red.r "%environment/console/CLI/console.red"
>> do/args %red.r "%environment/console/CLI/console.red"
-=== Red Compiler 0.6.4 ===-
Compiling /home/pierre/heaume_pierre/developpt/Red/environment/console/CLI/console.red ...
...using libRedRT built on 8-Mar-2019/9:35:43
...compilation time : 563 ms
Target: Linux
Compiling to native code...
*** Compilation Error: undefined symbol: red/word/duplicate
*** in file: %/home/pierre/heaume_pierre/developpt/Red/environment/console/CLI/console.red
*** at line: 339
*** near: [word/duplicate ~script
~args|361: word/duplicate ~args
~console|362: word/duplicate ~console
]
>>join defined in my local environment.-r?%>> do/args %red.r "-r %environment/console/CLI/console.red ** Syntax Error: Missing " at do/args %red.r "-r %environment/console/CLI/console.red ** Near: halt >>
>> do/args %red.r "-r %environment/console/CLI/console.red" ** Access Error: Cannot open /home/pierre/heaume_pierre/developpt/Red/system/red.r ** Near: do/args %red.r "-r %environment/console/CLI/console.red"
cded somewhere during script evaluation, without returning where he started...>> pwd == %/home/pierre/heaume_pierre/developpt/Red/system/ >> cd .. == %/home/pierre/heaume_pierre/developpt/Red/ >> do/args %red.r "-r %environment/console/CLI/console.red" -=== Red Compiler 0.6.4 ===- Compiling /home/pierre/heaume_pierre/developpt/Red/environment/console/CLI/console.red ... ...compilation time : 2003 ms Target: Linux Compiling to native code...
%red.r is located, not from /system.cded to system at some points, during the first tries......compilation time : 48410 ms ...linking time : 483 ms ...output file size : 808180 bytes ...output file : /home/pierre/heaume_pierre/developpt/Red/console == none >> REBOL terminated # pierre@latitude: ~/dev/Red < 2020_04_19__23:05:19 > [bashpid_25284] ~/dev/Red/console --== Red 0.6.4 ==-- Type HELP for starting information. >> print "Y E S ! I C A N S T A R T P L A Y I N G !" Y E S ! I C A N S T A R T P L A Y I N G ! >>
join defined in my local environment.join, he has it available.~/.red/.Red-Console/console-cfg.redresult: [ ; db data example
1 {file1.xml} "2000"
2 {file2.xml} "2001"
3 {file3.xml} "2002"
4 {file4.xml} "2003"
5 {file5.xml} "2004"
6 {file6.xml} "2005"
7 {file7.xml} "2006"
8 {file8.xml} "2007"
9 {file9.xml} "2008"
10 {file10.xml} "2009"
]
flds: collect [
repeat i 10 [
keep compose [
(to set-word! rejoin ['f-name- i]) ; give each a unique name
field 150 hint "file_name"
(to set-word! rejoin ['f-date- i]) ; give each a unique name
field 150 hint "xml_date" return
]
]
]
view[
p: panel flds
button "load" [
foreach fld flds [
if set-word? fld [
; f-name-n and f-date-n would have same type
; but I should separate them
; how to do it? to check every fld name?
; or there is better way?
]
]
]
]view[
p: panel flds
button "load" [
foreach fld flds [
if set-word? fld [
fld-name: to-string fld
if find fld-name "f-name" [
; here I will set f-name-n
]
]
]
]
]result: [
1 {file1.xml} "2000"
2 {file2.xml} "2001"
3 {file3.xml} "2002"
4 {file4.xml} "2003"
5 {file5.xml} "2004"
6 {file6.xml} "2005"
7 {file7.xml} "2006"
8 {file8.xml} "2007"
9 {file9.xml} "2008"
10 {file10.xml} "2009"
]
file_names: extract/index result 3 2
file_dates: extract/index result 3 3
flds: collect [
repeat i 10 [
keep compose [
(to set-word! rejoin ['f-name- i]) ; give each a unique name
field 150 hint "file_name"
(to set-word! rejoin ['f-date- i]) ; give each a unique name
field 150 hint "xml_date" return
]
]
]
view[
p: panel flds
button "load" [
foreach fld flds [
if set-word? fld [
fld-name: to-string fld
if find fld-name "f-name" [
face: get fld
face/text: rejoin [take file_names]
]
if find fld-name "f-date" [
face: get fld
face/text: rejoin [take file_dates]
]
]
]
]
]~/.red/.Red-Console/console-cfg.redRed [] load %abc.red view [panel ctrls]
ctrls: [ button "Hello" ]
>> do load %app.red *** Script Error: VID - invalid syntax at: [ctrls] *** Where: do *** Stack: view layout cause-error >>
Do is the key here. Go step by step. What is the result of load %abc.red? What value does ctrls refer to after that line?load %abc.red is just load code as datado load but it does not workdo on that result?do on? Red [needs: 'view] do load %abc.red view [panel ctrls]
load first? What happens if you just do a file!?do %app.red directly cut should load every component with do load %abc.redresult, is way too human-readable.
I'd trend to rewrite it as follows:
`do, you may benefit from reading [this explanation](https://github.com/meijeru/red.specs-public/blob/master/specs.adoc#function-do). probe db-result show only first getted result that not depend of chaning sql-querymake-db-query: func[sql-query] [
db-result: [] ; some issue here
SQLite/do [
db-result: exec sql-query
]
probe db-result
db-result-id: extract/index db-result 11 2
db-result-arch_name: extract/index db-result 11 3
db-result-file_name: extract/index db-result 11 4
db-result-file_type: extract/index db-result 11 5
db-result-forced_processing: extract/index db-result 11 6
foreach cell ui-table-cells
[
if set-word? cell [
fld-name: to-string cell
if find fld-name "f-id" [
face: get cell
face/text: take db-result-id
]
if find fld-name "f-file_name" [
face: get cell
face/text: take db-result-file_name
]
if find fld-name "f-file_type" [
face: get cell
face/text: take db-result-file_type
]
if find fld-name "f-processed_date" [
face: get cell
face/text: take db-result-processed_date
]
{some code is skipped}
]
]
]sql-query I see the proper request. But result of it execution look like the first request was executed.db-result: sqlite/query sql-query.SQLite/do is a dialect with different semantics, and that set-word! in it has a different meaning?LOADload/select func [code-name [word! block!] source [file! block! url!]][]load/part pos: find read %file 'start find pos 'end ?read/seek?read/seek too once available but it would be more difficult. What I was in my mind, having some place-holders in the file like:... other parts ... <image-functions> rotate: func [] [...] my-constant: 1.0 blend: func [] [...] </image-functions>
to-csv doesn't put quote chars around the values? It did before IIRC:>> to-csv/quote [[1 2] [2 3] [3 4]] #"-"
== {1,2^/2,3^/3,4^/}
>> to-csv [[1 2] [2 3] [3 4]]
== {1,2^/2,3^/3,4^/}
>> to-csv [1 2 3]
== "1,2,3^/"
>> to-csv/quote [1 2 3] #"'"
== "1,2,3^/"to-csv, would it be better to remove the trailing newline character?write/lines, but since each CSV line has also newline.to-csv in R2 doesn't also put newline which looks more useful to me. >> to-csv/quote [[1 2] [2 3] [3 "4 5 6"]] #"-"
== {1,2^/2,3^/3,-4 5 6-^/}to-csv AFAIK, so must be from somewhere else. But it's a good question. If you're appending CSV records to a string buffer, including the newline saves you a step. If you do it with write/lines, it adds a step. Since to-csv handles blocks already, it would help to know what benefit you get in your setup from converting first to a block of strings? I can imagine doing post-csv processing on them, but then I think we just need to add notes to https://github.com/red/red/wiki/CSV-codec as a use case.start,a,b,c intermediate,1,2,3,4 end,p,"q,r",s,t,u
read/lines first, then for each line I use load-csv, then put them in separate blocks according to their types (start, intermediate or end rows have different number of colums)write/lines.to-csv (don't remember where did I get) it doesn't have quote at all.to-csv does that (for spaces only and not for tabs):>> to-csv ["a" "b^-c" "d"]
== "a,b^-c,d^/"
>> to-csv ["a" "b c" "d"]
== {a,"b c",d^/}tab *may* have been omitted because tab separated values are probably the most common, after comma separated. RFC4180 is funny in that the "Interoperability considerations" section basically says "We tried, but really, there is no definitive spec." :^) I think Brian Hawley's CSV was the most complete, but we can't call it definitive either. The biggest question, for me, is where each side of the codec *fails*, in that something from Excel or another major system doesn't load, or can't load our output. That's the reference standard, for better or worse./qoute refinement would enforce quotes for each value, so to-csv/quote [1 2 3] #"'" would result in {'1','2','3'}, what do you think?/quote, the doc string says Use different character for quotes than double quote ("), which says to me that the alternate char is used, but doesn't change the behavior. If we make the refinement mean both *change* and *force*, you can't get the current behavior with an alternate. That may not be an important use case, but it will be a breaking change later if we learn we're wrong. And since it will break data generation for people, we should avoid that if at all possible./with take a block or map, to allow specifying both the delimiter and quote values? You could include just one, if that's all you want to override. That leaves /quote to turn quoting on, where it then applies to *all* fields. trim/tail isn't so bad, but another thing we could do (which needs more thought) is add a refinement to to-csv-line to omit the newline. People can then call that directly. This gets more complicated, though, because to-csv configures the module level quote chars. Dealing with concurrent codec configs is another matter. /with proposal is also interesting. I need to do some testing, but it seems like the way to go.to-csv-line - it's not a problem to add a refinement, what's more interesting is to decide what behavior should be the default. I vote for having newline as default and adding /only or something similar to override it./only, but it has a different standard meaning. If we keep the newline, and tell users to use trim/tail, adding a refinement later won't break anything. @endo64's use case is the key. If it turns out that people want to create single CSV lines on a regular basis (say 10% of the time), we want the CSV API to make that easy to do./only was a first guess, maybe /trim would be better? /trim opens more questions, in how it relates to the trim func. If someone wants to do this, and wants a shorter func than trim/tail, they can wrap that. But we should maybe revisit trim's default behavior, which is not entirely intuitive when it comes to newlines. That is, /tail considers NL whitespace, but trim alone does not.to-csv/tail looks strange and not self-explaning IMOtrim/tail, sorry.to-csv?snip: func [val [string!]][trim/tail val] easily enough....\red.exe --catch user.red shortcut and put code you want to load in %user.red.f function 2 times but I forgot the second argument of the first one, the code still runs, it outputs code which could seem correct (4 numbers) but they are wrong because I >> a: 10 == 10 >> b: 20 == 20 >> f: func [arg1 arg2] [probe arg1 probe arg2] >> f a b f a b ;<----- correct! 10 20 10 20 == 20 >> f a f b a ;<------ without an argument 20 < 10 < 10 < Wrong number but you can't know this 10 < == 10 >>
f a check-stop f b acheck-stop becomes an argument of a function the program will stop, otherwise it will be used as a neutral word and nothing will happen (just like a comment, a string or a block).to-csv topic: I don't think a refinement is necessary for trim/tail.to-csv in my user.r doesn't accept a block of blocks, just produces 1 line of CSV, so it is more limited then the @rebolek 's version.Bind where you bind only some words of a block to a target context and not all the words that are in the context ?/qoute refinement would enforce quotes for each value, so to-csv/quote [1 2 3] #"'" would result in {'1','2','3'}, what do you think?/quote then I expect all the values will be quoted.bind and report how it works.to-csv, I propose below refinements:/with => Quote char to use /quote => Force quoting /delim => Delimiter to use
delim is the thing you'd override before the quoting char, so is a better fit for /with, and if we don't auto-quote, then does /with imply /quote? I'm leaning toward a rich /with arg, which could be defined just once, making all calls cleaner.munge (which I think @rebolek tested against), are other cases rare enough that we can keep it simpler?/with spec [block! map!] "delimiter: [char! string!] quoting: [off | on | auto] quote: [char!]"
/with spec is cool but not sure if it is, for supposed to be a simple function.load-csv already has more than I expect (records, column mode etc.)to-csv function, even without object and map support, could be enough useful.round vs [ceil floor trunc ...] is clarity of intent. Blocks-to-records or blocks-to-columns then need counterparts, and still need extra information because CSV data may have headers or not.forget: does [unset find/tail words-of system/words 'forget recycle]drop event is generated in the dragged face, not the destination face, and the event/offset is relative to the dragged face. How do I find out _where_ the face has been dropped? I mean, the identity of the destination face and the offset of the drop relative to _that_ face?find or something like that. So I'd say that right now the only way is to restart.unset words-of system/words for one way to destroy the world ;)mark-my-words that I used to track down word leaks. Same vein, different goal.>> ?? mark-my-words
mark-my-words: make object! [
init: func [][query/clear system/words]
dump: func [/local val][
...
>> mark-my-words/init
...
>> a: 1 b: "test"
== "test"
>> mark-my-words/dump
Word Type Value
a integer 1
b string "test"set function, so you could tinker with the state of the system. This is, naturally, a dangerous thing to allow, but can also be very nice viewed in other ways. Values in the system are like living, embedded config settings. With a helper system, you can also put custom UIs over them. query on objects in Red though, do we?reset native that just... reboots the interpreter, and a way to track changed words like R2's query (which was born as a hack but I think it was useful enough to consider). (And, of course, protect, but I think that's in the pipeline already.Protect is in the pipeline, and we don't have query on objects. I was just posting the old R2 stuff as an example, with the implementation being...just there. query later today.query/clear on objects is the right name for such a purpose.+= to be used like a += 3. My initial approach was to create a function increment: func [ a b ] [ set a (a + b) ] then +=: make op! :increment. But There are some pieces here that I'm not understanding 100% of how to bind the word! on left hand side (a) using the set. increment: func ['a b][set a (get a) + b] This will prevent a from being evaluated before the call, and then get a will retrieve its value.increment: func [ a b ] [ set 'a (a + b) ] but of course this wasn't working either. I knew I had to prevent the evaluation of a but wasn't doing it in the right place.query/clear might be OK as a name. What's lacking in R2 is any indication of what it does. query, but the design should come first in any case, related to how it access external information, while reflect produces internal information (but doesn't expose it directly) and face accessors (*-face*) did things another way in later R2 VID.query is the best name for it, I think it was just the most convenient way to do it back when it was added to R2 - and it wasn't added by Carl. (Carl didn't even remember it was there last time we talked about it - he was surprised it even worked.) reflect would make more sense but then of course there's the question of how to "clear" the "modified bit".get/set model. It would be nice to unify this.evoke http://www.rebol.com/r3/docs/functions/evoke.htmlreflect/modify actions for that. modify is already used as a counter-part to reflect.query/clear is bad.modify documented anywhere?style node and create two object with this style. How I can change some properties in one node (by click button), for example text for header in DRAW block?Red [Needs: 'View]
win: layout [
size 400x500
across
style node: base 100x60 transparent draw [
fill-pen blue box 5x5 95x55 5
fill-pen yellow circle 5x20 5
fill-pen yellow circle 5x40 5
header: text 20x15 "HEAD"
]
b1: button "test" [probe node0]
node0: node loose
node1: node loose
]
view/no-wait wini: j: 0
win: layout [
size 400x500
style node: base 100x60 transparent draw [
fill-pen blue box 5x5 95x55 5
fill-pen yellow circle 5x20 5
fill-pen yellow circle 5x40 5
text 20x15 "HEAD"
]
below
b1: button "test1" [change skip find node0/draw 'text 2 rejoin ["HEAD-" i: i + 1]]
b2: button "test2" [change skip find node1/draw 'text 2 rejoin ["HEAD-" j: j + 1]]
return across
node0: node loose
node1: node loose
]
view winnode1\text: "New text" b0: button "test" [alter last node0/draw ... ] but it's a bit sticky with, seems to work nicely. The question though - why does the box have the outline? Do I need to run off pen first?view [base 200x200 draw [fill-pen green box 5x5 195x195] with [color: white]] node1\text: "New text"fill-pen to glass and give node a text, then you can change this text by node/text: ...baseobject!, port! and series!. You can search for modify: in the source code. I consider it experimental so far, though it's already used at mezz level in View.b2: button "test1" [node-text node1 rejoin ["HEAD-" i: i + 1]]
]
node-text: function [n [object!] s [string!]][
change skip find n/draw 'text 2 s
]modal flag for window. But then you cannot set focus on other windows of this session until you close the modal one.base face.area's scroller, being native, cannot be manipulated programmatically. At least on Red level. Probably it can be manipulated on system level, I haven't tried. (But you can cheat and jump text's index away from head by lines. This would not adjust scroller though.)i: 0
view [
a: area "" below
button 80 "Add line" [
append a/text rejoin [{line } i: i + 1 {^/}]
if i >= 10 [a/text: find/tail a/text newline]
]
button 80 "Top" [a/text: head a/text]
button 80 "End" [j: i - 9 loop j [a/text: find/tail a/text newline]]
]if empty? a/text [a/text: ""]
append … seems to prevent crashing though and magically :) all the lines are still there...if found: find/tail a/text newline [a/text: found] there, to make it safer.query-like feature in the fast-lexer branch https://github.com/red/red/commit/05f996354ecc28eb8bd8ceafd5181126ba1a76b6:>> obj: object [a: 1 b: 2 c: 3]
== make object! [
a: 1
b: 2
c: 3
]
>> obj/c: 99
== 99
>> reflect obj 'changed
== [c]
>> modify obj 'changed none
== make object! [
a: 1
b: 2
c: 99
]
>> reflect obj 'changed
== []
>> obj/a: 124
== 124
>> obj/c: -1
== -1
>> reflect obj 'changed
== [a c]SQLite/do [use db2]SQLite/do [use db2]
sqlite/query {INSERT INTO "notice_fz44" ("purchaseNumber") VALUES ('1');}
SQLite/do [use db1]sqlite/query. I looked sources but I did not understand how to do it; open 2 databases
SQLite/do [
db1: open %test1.db
db2: open %test2.db
]
; get some data from db1
result: make block! 32 ;preallocating block for results
SQLite/do [
use :db1
result: exec "SELECT * FROM Cars ORDER BY name"
]
; process the result...
; put some data info db2
SQLite/do [
use :db2
exec {INSERT INTO "Cars" VALUES(null,'Hummer',null);}
]
; close databases when done
SQLite/do [
close :db1
close :db2
]
; release resources if no mome SQLite needed
SQLite/freeresult: make block! 32 ;preallocating block for results could be removed as [there is internal buffer in the context](https://github.com/red/code/blob/02d4263ff117fc8a75341d90e168d74babf81c9c/Library/SQLite/SQLite3.red#L427-L428)query-db: func[ "Executes SQL query with specified DB" db [handle!] sql [string!] /into result [block!] ][ unless into [result: clear head output] do compose [use (db) result: exec (sql)] result ]
SQLite/do [...]SQLite/do [
use :db2
result: exec {INSERT INTO "notice_fz44" ("purchaseNumber") VALUES ('1');}
use :db1
]SQLite/do [use db2]
sqlite/query {INSERT INTO "notice_fz44" ("purchaseNumber") VALUES ('1');}
SQLite/do [use db1]Red []
do-quit: does [
res: false
view/flags [
title "test-window.red"
text "Quit?" return
button "OK" [res: true unview]
button "Cancel" [res: false unview]
][modal popup]
res
]
view/options [
title "Test"
size 400x400
button "Quit" [if do-quit [unview]]
][
menu: [
"File" [
"Quit" doquit
]
]
actors: context [
on-menu: func [f e][
if e/picked = 'doquit [if do-quit [unview]]
]
]
]*** Runtime Error 95: no CATCH for THROW *** at: 0001F3F9h
set-focus on cancel-actor, e.g.:;popup button "Cancel" [res: false unview set-focus b] ... ;main b: button "Quit" [if do-quit [unview]] ...
>> y-m-d: func [d [date!]][rejoin [d/year "-" next form (100 + d/month) "-" next form (100 + d/day)]] == func [d [date!]][rejoin [d/year "-" next form (100 + d/month) "-" next form (100 + d/day)]... >> y-m-d now == "2020-04-28" >> y-m-d 2-Dec-2020 == "2020-12-02"
pad/left/with d/month 2 #"0"to-date accepts a block with 0, 1, 2 or 3 integers:>> to-date [2020 4 28] == 28-Apr-2020 >> to-date [2020 4] == 31-Mar-2020 >> to-date [2020] == 31-Dec-2019 >> to-date [] == 1-Jan-0000
to-date [y 3] where y is a year, is useful for finding the last day of February in the given year :)red/bugs, before possibly creating an issue.y: 2020 (to-date [1 3 y]) - 1 == 29-Feb-2020
>> if [] [print "A block is a truthy value!"] A block is a truthy value! >> to-logic [] == true
sqlite/query.SQLite/query sql-query present in code the single SQL request is execute than all stops like there is no more foreach loop. If comment this line and add simple print all works fine and I am seeing a lot of data print on console.probe sql-query to see, what you are trying to execute... and try to localize the issue in some simple case without need to hack with your project.id.sqlite/query was just a short example. It was not meant to be used like that... note that [it is using internal buffer](https://github.com/red/code/blob/02d4263ff117fc8a75341d90e168d74babf81c9c/Library/SQLite/SQLite3.red#L427-L428), which is [reused in each call](https://github.com/red/code/blob/02d4263ff117fc8a75341d90e168d74babf81c9c/Library/SQLite/SQLite3.red#L452). You don't copy the results in your script! [Like here](https://gist.github.com/bubnenkoff/80fdbf30ab91ace455d467fe4cba5c42#file-app-red-L16)calland parse results? Did so in the past and IIRC the query can stay hidden ...sqlite/query to be like:query: func[ "Executes SQL query" sql [string!] /into result [block!] ][ unless into [result: clear head output] do compose [result: exec (sql)] either into [result][copy result] ]
call where you pay for executable evaluation and complete sqlite initialization with each call.{UPDATE "xml_files" SET "processed_date" = '2020-04-28', "status" = 'success' WHERE "id" = '10155'}foreach loop. I will try to debug my project. Very strange error...db-result: copy sqlite/query generate-sql-for-processing. I am still not fully understand cases where copy is should be used, but here is good place for it>> context [a: 1 b: 2 c: a + b d: c + c]
== make object! [
a: 1
b: 2
c: 3
d: 6
]C and D can be calculated because previous words are progressively available. How is called this characteristic ?>> load "1 2 3" == [1 2 3]
>> load/next "1 2 3" 'pos == 1 >> probe pos == " 2 3"
>> find series! integer! == false
find does not always return none on failure. I wonder if it's by design.>> probe :series?
func ["Returns true if the value is any type of series" value [any-type!]][
find series! type? :value
]false when I'm passing it to pick :)found?: func [x][not none? :x] will breakfindreturn value consistent with other types.none.find series! :value directly, so that when the second argument is not a datatype!, the type will be first extracted by find before searching it in the typeset?find ?find : (get syntax)?find ;)>> b: reduce [any-word!] == [make typeset! [word! set-word! lit-word! get-word!]] >> find b any-word! == [make typeset! [word! set-word! lit-word! get-word!]]
find . A piece of R3:
>> find [a "b"] series!
== ["b"] ;) == none in red
find. :^\>> find reduce ['a "b" series!] series! == ["b" make typeset! [binary! string! file! email! url! tag! image! vector! block! paren! path! set-path! get-path! lit-path!]]
>> find reduce ['a "b" series!] reduce [series!] == [make typeset! [block! paren! string! file! url! path! l
>> find reduce [integer!] integer! == [integer!]
find/same but I don't like "exceptions to exceptions" way in design :Dparse will save us from this mess.find series! :value directly, so that when the second argument is not a datatype!, the type will be first extracted by find before searching it in the typeset?reduce your datatype:>> find series! first [string!] *** Script Error: invalid argument: string! *** Where: find *** Stack:
word!type?/word exists.type? call, is definitely worth it.op!s not only from binary functions, but also binary functions with refinements (op will just not use those refinements)? E.g.:make op! :appendmake op! :findfind has not been implemented yet. find implementation is already quite overloaded, we'll see how to achieve it. A wish ticket for that (including searching for a typeset) is welcome.>> f: func [comment arg1 arg2][print ["arg1:" arg1 "arg2:" arg2]]() >> f "This is comment" 1 2 arg1: 1 arg2: 2
>> system/lexer/pre-load: function [src part][string: [#"^"" any [#"^^" #"^"" | not #"^"" skip] #"^""] parse src [some [remove " comm " string | skip]]] == func [src part /local string][string: [#"^"" any [#"^^" #"^"" | not #"^"" skip] #"^""] parse src [some [remove " comm " string | skip]]] >> find comm "Another possibility of including comments between func and args" "abracadabra" "abra" == "abra"
COMM)>> system/lexer/pre-load: function [src part][comm: [" ^^" string] string: [#"{" any [string | not #"}" skip] #"}"] parse src [some [remove comm | skip]]]
== func [src part /local comm string][comm: [" ^^" string] string: [#"{" any [string | not #"}" skip] #"}"] parse src [some [remove comm | skip]]]
>> find ^{I am comment} [1 2 3 4 5] 3
== [3 4 5]>> find ^{I am {nested} comment} [1 2 3 4 5] 3
== [3 4 5]
>> find ^{I am {nested} "and subquoted" comment} [1 2 3 4 5] 3
== [3 4 5]>> find [a ^{comment} b] {comment}
== none
>> find [a ^{comment} b] 'a
== [a b]
>> find [a ^{comment} b] 'b
== [b]
>> length? [a ^{comment} b]
== 2
probe load {[a ^{comment} b]}
==[a b]^ has been eaten. ^{ this combination.>> f: func compose [(comment "this is a comment") arg1 arg2] [] == func [arg1 arg2][]
>> f: func (comment "this is a comment") compose [arg1 arg2] []
*** Script Error: func does not allow unset! for its spec argument
*** Where: func
*** Stack: f
>> f: func ^{this is a comment} compose [arg1 arg2] []
== func [arg1 arg2][]>> a: [ ^{this is a comment} ]
*** Syntax Error: missing #"]" at "^^{this is a comment} ]"
*** Where: do
*** Stack: load
>>read) or block-level with load (after the lexer). @toomasv unblocked the doability of first part of the idea with his solution, when we will be able to make markers visible or "transparent" at block level by choice, then the second part of the idea could be implemented.Find/marker Lenght?/marker append/marker or just a global switch system/options/marker-visible: true);... comments either) - they are not part of (loaded) language, as they are (or should be) stripped from code before loading.pre-load to strip them, your code/data becomes malformed and it should and it is good.>> do/args %red.r "-r %environment/console/CLI/console.red"
do/args %red.r "-r -t Windows %environment/console/GUI/gui-console.red"
ODBC32_SQLDrivers No ODBC drivers could be found. Check the settings for your libodbc provide (I do not know situation possible attempt to run Red on WINE). Does it mean that Red have support of ODBC connection?do/args %red.r "-t Android bridges/android/samples/eval/eval.red" -=== Red Compiler 0.4.3 ===- Compiling /a/bridges/android/samples/eval/eval.red ... ...compilation time : 551 ms Compiling to native code... ...compilation time : 22574 ms ...linking time : 474 ms ...output file size : 587976 bytes ...output file : a:\eval.so ...generating apk ...signing apk ...aligning apk ...all done!
"World" clicking enter. I have written "Hero" inside the field which is immediately updated to "world" on enter. I expected this printing X but result is "hero" x: "Hello" view [field x 100x20 on-enter [face/data: "World"]] probe x "Hero" == "Hero"
x: "Hello" view [field x 100x20 on-enter [insert clear face/text "World"]] probe x "World" == "World" >> x == "World"
X string and when I set face\text, I connect it to another string breaking the link, don't I?face/text: "World" also wouldn't work as x and the new World strings are not the same anymore.face/text or face/data is worth documenting with a WARNING here https://doc.red-lang.org/en/view.html#_field. If you start editing the field from the GUI and PROBE x you see the expected result and think the result is mirrored in x content, if you edit from the inside you think you are setting the GUI element which also updates the X string... instead you change the connection! I admit that even working with Red from some time it has really been difficult to think about it correctly.x: content changed when you enter a new value in the GUI, and you also you see that face/text: new value changes the GUI, you think that face/text: new value -> x: new value. If someone else falls in this hole and not just me, I think it is worth putting a warning.view. Consider:>> x: "Hello" b: reduce [x] == ["Hello"] >> b/1: "World" == "World" >> x == "Hello" >> x: "Hello" b: reduce [x] == ["Hello"] >> head change/part b/1 "World" tail b/1 == "World" >> x == "World"
>> x: 1 view [field data x 100x20 on-enter [x: face/data]] ; set it to 2 >> x == 2
data is formed into field’s text, and field’s text is loaded into data, but data does not retain the original datatype.face/data, for this reason, I have started thinking it retained the original datatype. Now I have tried again and yes, face/data is a pure and simple LOADing of face/text. It even converts to block!. I have enter (a)/b and found: [(a) /b] in face/datafirst line second line third line
rr: read/lines %123.txt foreach line rr [ trim/tail line ] write %321.txt rejoin rr
first linesecond linethird line
lines: {first line^/second line^/third line}
print replace/all lines " " ""
firstline
secondline
thirdlineread/lines and then rejoin. You loose newlines this way and trim/tail actually does nothing at all.rr: read/lines %123.txt foreach line rr [ trim/tail line line: append line newline ] write %321.txt rejoin rr
collect [foreach line read/lines your-file [keep trim/tail line keep newline]]parse:lines: {first line ^/second line ^/third line }
parse lines [any [change [some space [newline | end]] (newline) | skip]] lines
== {first line^/second line^/third line^/}>> lines: {first line ^/second line ^/third line }
>> remove-each c lines [c = space]
>> lines
== "firstline^/secondline^/thirdline"win: layout [400x300] react [do-my-own-resize]
view/flags [size 400x300 on-resizing [face/size: 400x300]] 'resizeon-detect doesn't help too (perhaps we can request that it stops resizing when the actor returns 'stop)x: 22 a: func [][probe x] m: make object! [ x: 44 b: func [] copy body-of get in system/words 'a ] >> m/b 22
compose or manually bind it, else it is first bound then built (and you have no literal func body to bind at bind stage)make calls bind, then evaluates the object's body. bind needs a block! to bind, but there's no block - only a couple words and a path: copy body-of get in system/words 'abind is called - that is before make. For that you may use compose: make object! compose/only [...]Make creates the context and binds the block to it then, it makes the remaining part of the work. At binding stage we have still no function body but just words to be evaluated.object and another when using it on the inside. In the latter case I omit the refinement and its words as they are already available in the context. I have to use the not so elegant compose! :(bind copy/deep body-of :a selfself is available at building !T H A N K S !x: 22 a: func [][probe x] m: make object! [ x: 44 a: func [] copy body-of :a ] *** Script Error: body-of does not allow unset! for its value argument *** Where: body-of *** Stack: body-of
:aform in place of get in system/words 'a form.:system/words/a is shorterdeep copies by default.x: 22 a: func [][probe x] m: make object! [ x: 44 a: func [] bind/copy body-of :system/words/a self ] Red: Ok Rebol: 22 ** Script Error: Cannot use reflect on integer value ** Near: make error! reduce [err-type err-id pick args 1 pick args 2 pick args 3]
off)view/flags [size 400x300 on-resizing [face/size: min 800x600 max 200x150 face/size]] 'resize
view/flags [size 400x300 on-resizing [face/size: min 800x600 max 200x150 face/size]] 'resizeoff has no effect at all. With on, a lot of flickeringface/size to as-pair maxsx maxsy before returning.clear d4/text d4/text: copy rejoin [as-pair maxsx maxsy " LIMIT!!!!"] shows the correct limited pair. Why can’t I change face/size? auto-sync :) @toomasv - and I don’t use show face.view [
size 400x300
at 390x290 base 10x10 cursor 'hand loose
on-down [system/view/auto-sync?: off]
on-up [system/view/auto-sync?: off]
on-drag [
face/offset: max 290x190 min 590x390 face/offset
face/parent/size: face/offset + 10
show face/parent
]
]system/view/VID/default-font/size would do it, but it seems not. @dockimbel @qtxie @%VID.red:L423-437 looks like at least some font setting has to be set for a face, for @L434 to be applied. I know some changes were made for style font application a while back. auto-sync? is good for…system/view/VID/default-font is a read-only property for now.on-up [system/view/auto-sync?: on] :flushed:parse filecontent [<id> copy scheme-name to "<id>"] either value? 'scheme-name ; check if scheme-name was set [ parse scheme-name [remove to "<" thru ">" remove to end] ; some other manipulation either (length? scheme-name) > 0 ; check again [ scheme-name ] [ "unknown-scheme" ; ditto ] ] [ "unknown-scheme" ; ditto ]
scheme: none parse filecontent [<id> to #"<" copy scheme thru #">"] either any [none? scheme empty? scheme]["unknown-scheme"][scheme]
f: [a: a + 1]
replace/all f 'a 'b
change-words: func [ blk [block!] "(modified)" old [word!] new [word!] /local w ][ parse blk [ any [ pos: any-word! ( if pos/1 = old [ change pos make pos/1 new ] ) | skip ] ] blk ] f: [a: a + 1] change-words copy f 'a 'b
parse, change, equality testing for words, and make.Red [Needs: 'View] view [ ticker: base on-time [print [now/precise]] ; a visual effect could be displayed instead button "rate" [ ticker/rate: 10 wait 3.0 ; some heavy calculations ticker/rate: none ] ]
view [
ticker: base on-time [print [now/precise]] ; a visual effect could be displayed instead
button "rate" [
ticker/rate: 10
loop 30 [wait 0.1 do-queued-events] ; some heavy calculations
ticker/rate: none
]
]call, having results written to a file, and poll that file in your Red app.MAKE CTX [field-name: value obj: myobject] and pass it to the functions like UPDATE-FIELD ctx which will be ARITY 1, or have the context separate separate and call the function as UPDATE-FIELD field-name value ctx?update-field is expected to change. Though I might put the context first in that case, to match series func standard order.load on a text file which contains JSON data, it is automatically converted. Does this mean that for text files, json is the default encoding? The docstring says that to load "code" one needs to specify /as none. So that would imply that "code" (i.e. molded Red values) is not default. Can anyone explain?https://api.github.com/repos/red/red/commits. This is a string which "looks" like JSON, and indeed is. But the address itself does not suggest that. Without any help from me, load makes this into a block of maps -- magically!encode into a file! or url! value, but decode only from a file! value, not from a url!. What is the reason?url!, is in contradiction with my experience described above.url!, the MIME type is determined by read/info, and for file! it is determined by the suffix. So that covers everything.load and save in the spec document [here](https://github.com/meijeru/red.specs-public/blob/master/specs.adoc#111-conversion-of-data).ctx-vid-panel -> ctx-vid-panel/validation-data or /field or /anything you want. object, other than creating a new object with inheritance, is there a way to add things to the object's body after it's been created? Something like append body-of myobject [ new-word: newval ] extend will take an object! value as first argument and a set of key-value pairs as second argument of type block! hash! or map!. It will add the keys that are not present in the object, with their values, and replace the values for those keys that are already present. The keys and values are not evaluated. **It is not yet implemented!**extend )extend is to be able to extend *in-place* objects (like the ones in system object or in a View face tree), and not to enable OOP. That last concern is the main reason why it's not already implemented. I need to figure out a way to limit its usage to in-place objects.remove would be useful.extend manage the block as make object! does with its spec block?" The answer was already in my earlier post: The keys and values are not evaluated. So that is how it differs from make object!.extend will support an object as input you can create it and just extend the target one using it as argument. This to have standard evaluation of the spec blocks before "extending" the target.check-for-context: does [ print (value? 'my-ctx) ]
my-ctx: context [
view layout [
button "check for context" [ check-for-context ]
]
]context [ my-ctx: self inner: context [ ... uses my-ctx ... ] view [... [uses my-ctx] ...] ]
cmd: path-to-exe some-dir. call/show right way to call it? /show says Force the display of system's shell window (Windows only) not saying anything about "graphical window". Runtime Error 1: access violation . I can't reproduce it because I am retting it randomly when data is processing. How I can debug it or at last get full stack-trace? Red [] #import %odbc.red drivers: odbc-drivers print drivers
*** Compilation Error: undefined word odbc-drivers
*** in file: D:\code\odbc_test\app.red
*** near: [odbc-drivers
print drivers
]-r{"some key": "some value"}k-v from two nested foreach loop/ or \?>> last split "file/foo/file.txt" "/" == "file.txt"
copy. I need to prevent touching original data and work with it's copy inside function.rules: ["bb" "cc" "dd"] f: func[] [ insert copy rules "aa" print rules ] >> f bb cc dd
aa bb cc ddinsert local-rules: copy rules "aa"print local-rules/local local-rules then yesblk1: words-of make object! [c: 99 b: 33 a: 22 ] blk2: words-of make object! [a: 66 b: 55] >> setxxx blk1 blk2 [c b a] >> probe reduce setxxx blk1 blk2 [99 55 66]
set context? :blk1/1 context? :blk2/1word [any-word! block! object! path!] "Word, object, map path or block of words to set." value [any-type!] "Value or block of values to assign to words."
value I expected only single words can be used and not couples [set-word values]. Also this working is symbol based and not positional based.blk1 could have different contexts each one series! typeset, but all that currently is there is arrays (hash! is an array powered by hashtable)>> ? series! SERIES! is a typeset! value: make typeset! [block! paren! string! file! url! path! lit-path! set-path! get-path! vector! hash! binary! tag! email! image!]
>> ? any-block! ANY-BLOCK! is a typeset! value: make typeset! [block! paren! path! lit-path! set-path! get-path! hash!]
system in http://helpin.red/Whatisinsystem.html, is system available from scripts and programs or only from the repl?foreach and I've seen the case and switch statements. Are there any more resources on Red's capabilities here? For example, what datatypes can and cannot be destructured? copy series values in funcs. I won't spoil it for you though. ;^)set using blocks of words and values, and objects.parse, but it's overkill for simple dispatching in most cases. Important basic funcs for this are any and all; learn how they work. Also, one of the most distinctive features of Red is the variety of datatypes. Leverage those for all they're worth.destruct: func [ recipients container ] [
parse recipients [
any [
'rest (rest: container)
| copy s word! (set s first container container: next container)
]
]
exit
]
~: make op! :destruct
>> [a b rest] ~ [ 1 2 3 4 5]
>> a
== 1
>> b
== 2
>> rest
== [3 4 5]find? find
...
/any => TBD: Use * and ? wildcards in string searches.
/with => TBD: Use custom wildcards in place of * and ?.set...: func [ "Like SET, but the first set-word! in words will refer to the rest of the values" words [block!] "Words to set" values [series!] "Values words will refer to" /local w ][ parse words [ any [ set w set-word! (set w values) to end | set w word! ( set w pick values 1 values: next values ) ] ] ] set... [a __:] [1 2 3 4 5] ?? __ set... [a b __:] [1 2 3 4 5] ?? __ set... [a b c] [5 6] set... [a b c __:] [1 2 [x y z] 3 4 5] ?? __
__?set-word! is a datatype in its own right.>> find "one two three" "t*o" == none >> find/any "one two three" "t*o" == "two three" >> find/any "one two three" "t?o" == "two three"
/with will allow finer-grained patterns based on what? Something regex-like?hello/world>> type? probe head insert to-path first [/world] 'hello hello//world == path! >> type? probe head insert to-path to-word first [/world] 'hello hello/world == path!
hello: [/world 1] >> reduce probe head insert to-path first [/world] 'hello hello//world == 1
probe head insert first [/world] 'hello. Then I figure it out.>> hello: [/world 1] >> key: /world >> path1: 'hello/(key) == hello/(key) >> path2: as path! compose as block! path1 == hello//world >> get path1 == 1 >> get path2 == 1
>> clock/times [get path1] 1000000 0.46 μs [get path1] == 1 >> clock/times [get path2] 1000000 0.40 μs [get path2] == 1
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 ]
print is an exampleRuntime Error 1: access violation but I do not see any stack-trace -drecycle/off somewhere at the top of your script.--header 'accept: application/json' is it possible to do with red now?>> send-request/data http://localhost/api POST "{}"
*** Script Error: POST has no value"Data to send with request (auto-converted to proper encoding)" content [string! block! map! object! none!]url 'POST object [a: 1] ?data: [database1 [table1 [[a b c][1 2 3][9 10 11]]] and data2: [database1 [table2 [[a b c][1 /table1/b 3][9 /table1/b 11]]]
/table you will it join to data1 and the the corresponding column [/table1 key]data2: [database1 [table2 [
columns-cfg
[a [] b [/table1/b] c []]
]
]
]>> type? /aword/bword == /bword >>
.. :-)table1/bred build libRed stdcall generates a dll instead of an exe?> \red\build\bin>red build libRed stdcall Target: MSDOS Compiling to native code... ...output file : \Red\red\build\bin\libRed.exe <<<<<<<
--dynamic-lib to force that.--dynamic-lib the result is an exe. Also as I see in the source code if the first argument is build then all other arguments are ignored.do/args %red.r "build libred stdcall") works. From CLI it produces exe.words-for-unset: ["aa" "bb" "cc"] foreach word words-for-unset [ unset (to-lit-word word) ]
Script Error: unset does not allow lit-word! for its word argumentunset to-lit-word "x" should work. But it does not'x is evaluated. What is the result of evaluation of a lit-word?(to-lit-word word) is evaluated instead. Does it return result of the same type as 'x?words-for-unset: ["aa" "bb" "cc"] unset 'aa unset 'bb ...words-for-unset: ["aa" "bb" "cc"]
foreach word words-for-unset [
unset to-lit-word mold word
]help unset? Read [Boris' message](https://gitter.im/red/help?at=5ecd061b2c49c45f5aa1d02f) again. to-word?reduce and other evaluators come in. Then it's a matter of learning which funcs reduce, e.g. print, and on to the deep voodoo. :^)>> type? 'a == word! >> type? first [a] == word! >> type? a *** Script Error: a has no value *** Where: type? *** Stack: >> type? first ['a] == lit-word! >> type? :a == unset! >> type? first [:a] == get-word! >> type? a: *** Script Error: a needs a value *** Where: a *** Stack: >> type? first [a:] == set-word!
lit-word when it told you it does not accept lit-word?>> to-lit-word "x" == 'x
unset. I really confuse with it. I reread your messages but I am did not understand idea behind it. to-word#macro within a #macro function body? main() { return 0;} Is it's possible to do with Red? If to compile app of course ? quitprint does)print then use a macro to get multiple dispatch from that. Is that the right approach?bind is a deeeep topic of Redbol), or when you wanna preprocess a piece of code once and use it multiple times after (saves you precious CPU cycles). In your case I don't see that need. You will call the dispatch code each time anyway.product: f-mult [x y z][ [x] [ print x ] [x y] [ print x * y ] [x y z] [ print x * y * z ] ]
#macro was doing#macro substitutes parts of source code (data). Although you can substitute some pattern with itself, and define a function on your way, it's not very efficient as you might guess. #do OTOH is for definitions.bind? map-ex: 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 args" ][ collect [ repeat i length? series [ keep/only fn series/:i :i :series ] ] ] res: map-ex [1 2 3 a b c #d #e #f] :form res: map-ex [1 2 3 a b c #d #e #f] func [v i] [reduce [i v]] res: map-ex [1 2 3 a b c #d #e #f] func [v i s] [reduce [i v s]]
:fn syntax...product: func [ args [block!] "1, 2, or 3 integers" /local x y z ][ set [x y z] args ; case [ ; integer? z [print x * y * z] ; integer? y [print x * y] ; integer? x [print x] ; ] parse args [ 3 integer! (print x * y * z) | 2 integer! (print x * y) | 1 integer! (print x) ] ] print product [2] print product [2 3] print product [2 3 4]
set to destructure a block like that.product:;for 3 values at most. Empty block returns 1 product: func [b [block!]] [multiply any [pick b 1 1] multiply any [pick b 2 1] any [pick b 3 1] ] ;recursive mathod, for any number of values product: func [b [block!]] [either tail? b [1] [multiply first b product next b]] ;or product: func [b [block!]] [either tail? b [1] [b/1 * product next b]] >> product [3 5 7 9] == 945
any [... 1] combination is to prevent multiplying by 0?product: function [b [block!]] [r: 1 forall b [r: r * b/1]] >> product [3 5 7 9] == 945 >> product [] == none
>> calculate: function [b [block!] op [op!]] [r: 1 forall b [r: r op b/1]] == func [b [block!] op [op!] /local r][r: 1 forall b [r: r op b/1]] >> calculate [3 4 5] :* == 60 >> calculate [3 4 5] :+ == 13
a: 1 switch a [ 1 [ print "hello" ] ] b: integer! switch b [ integer! [ print "hello" ] ]
switch statement print "hello" but the second does not?b: integer!
cases: [
integer! [ print "hello" ]
]
type? b
type? first cases
type? first reduce caseshelp type? for a refinement it offers.first cases gives me integer! and first reduce cases gives me integer! but type? first cases gives me word! while type? first reduce cases gives me datatype!do, compose, reduce or try it (and a few others)switch doesn't reduce its second argument. >> mold none == "none" >> mold/all none == "#[none]"
parse? I want to be able to iterate over a block and simply note if and where there is this particular word that has been given no value. Is that possible?_ above. It would be convenient if it did not need to be given a value to find where its position is in the block. I find I can print it just fine, but haven't found any other functions that can grapple with it.unset! _ to make sure it isn't some other unset!, like x.equalish: func [ block1 block2 ][ l1: length? block1 l2: length? block2 repeat i l1 [ b1: pick block1 i b2: pick block2 i case [ not b1 = b2 or (not value? b1) or (not value? b2) [return false] ; i > b2 and b1 is not _ [return false] ] ] true ]
return false if block1 is longer and the elements of block1 beyond the length of block2 are not the unset! _.equalish: func [block1 block2][ len: length? block2 repeat i length? block1 [ b1: block1/:i b2: block2/:i if any [ not any [ b1 = b2 b1 = '_ b2 = '_ ] all [ i > len b1 <> '_ ] ][return false] ] true ]
> >> type? 'x > == word! >
'x is evaluated. What is the result of evaluation of a lit-word?lit-word! value is an unevaluated word! value".'x is evaluated"?>> type? x == integer! ; type of evelauted word value >> type? 'x ; type of word literal, not word value == word!
'x lit-word to x word.x can be evaluated again to it's value?equalish: func [b1 b2][ forall b1 [ if not any [ b1/1 = b2/(i: index? b1) b1/1 = '_ b2/:i = '_ ][return false] ] true ]
foo: [ 1 3 ] val: match/deep foo [ [ 1 y z ][ y * z ] [ x 3 _ ][ x + 3 ] [ _ _ z ][ z ] _ [ "default" foo ] ] print val ; => 4 bar: [ 1 3 5 ] val: match/type bar [ integer! [ "type int" bar ] ;-- type [ block! ] [ "type block" bar ] ;-- wrapped type [ logic! | float! ][ "enum" bar ] ;-- enum _ [ "default" bar ] ;-- default ] print val ; => "type block" 1 3 5 baz: 7 val: match baz [ [ 1 | 2 | 3 ][ baz + 100 ] ;-- enum 4 [ baz * 10 ] ;-- value [ 5 .. 9 ] [ baz + 10 ] ;-- range [ 10 ] [ baz * 800 ] ;-- wrapped value _ [ 1000 ] ;-- default ] print val ; => 17
match/type doesn't work particularly well, unfortunately. It throws errors if you try to match action!, op!, function!, and probably others.match feels like it's most of the way to multiple dispatch. I will have to tinker with that some more.:bar & :baz) if your problem is evaluating functions where you don't need tomatch function that is handling them incorrectly.read http://... that returns JSON and...you're done.map: function [ series fn ][ s: [] repeat i length? series [ append s fn series/:i i series ] s ] print map [ 1 2 3 4 5 ] function [ a ][ a * a ] ; 1 4 9 16 25 print map [ 5 4 3 2 1 ] function [ a b ][ a + b ] ; 1 4 9 16 25 6 6 6 6
s: copy []collect [repeat i length? series [keep fn serires/:i series]]
s: copy [][] refer to something in memory?>> second body-of :map == [] >> print map [ 1 2 3 4 5 ] function [ a ][ a * a ] 1 4 9 16 25 >> second body-of :map == [1 4 9 16 25]
collect script that @rebolek posted? That's not mutating anything, so it genuinely creates a new data structure every time?collect though ;)map-each](https://gitlab.com/hiiamboris/red-mezz-warehouse/-/blob/master/map-each.red)collect is extra verbose most of the timemap example about it's too muchcollect in people's code is only used to wrap a loop (mostly foreach).loop and recur combo, or is there something that would fit Red better?across or nothing and then return nothing to add. How should I do this?C-string type. But should it have strings without that store it's length in itself? I have heard that C-string are very dangerous and error-prone secure dialect like Rebol used.-e when compiling and never have an issue, because it forces code to always be interpreted. Or you can use do for sections of code to force that on a more granular level.do [...] in the current compiler).function! values etc. after everything has been set up by the interpreter, especially all the binding; this makes any macro preprocessing unnecessary because you can just build your code dynamically in the interpreter before the compiler even kicks in. But, I digress.)ping site). # pierre@latitude: ~ < 2020_05_31__19:45:51 > [bashpid_14979] ping -c 1 doc.red-lang.org PING cdn.gitbook.com (138.68.189.76) 56(84) bytes of data. 64 bytes from eu2-do-lon.gitbook.me (138.68.189.76): icmp_seq=1 ttl=51 time=43.3 ms --- cdn.gitbook.com ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 43.272/43.272/43.272/0.000 ms
ping doc.red-lang.org
Esecuzione di Ping cdn.gitbook.com [107.170.223.154] con 32 byte di dati:
Risposta da 107.170.223.154: byte=32 durata=194ms TTL=52
Risposta da 107.170.223.154: byte=32 durata=229ms TTL=52
Risposta da 107.170.223.154: byte=32 durata=198ms TTL=52
Risposta da 107.170.223.154: byte=32 durata=203ms TTL=52
Statistiche Ping per 107.170.223.154:
Pacchetti: Trasmessi = 4, Ricevuti = 4,
Persi = 0 (0% persi),
Tempo approssimativo percorsi andata/ritorno in millisecondi:
Minimo = 194ms, Massimo = 229ms, Medio = 206msmold/all is quite important, unfortunately not yet implemented fully in Red. In the meantime, if you can, use map! instead of object!, or even blocks etc.zsh: bad CPU type in executable: ./red-064
>> ? open
USAGE:
OPEN port
DESCRIPTION:
Opens a port; makes a new port from a specification if necessary.
OPEN is an action! value.
ARGUMENTS:
port [port! file! url! block!]
REFINEMENTS:
/new => Create new file - if it exists, deletes it.
/read => Open for read access.
/write => Open for write access.
/seek => Optimize for random access.
/allow => Specificies right access attributes.
access [block!]
>>
>> f: open/new %123.txt
*** Script Error: open does not allow file! for its port argument
*** Where: open
*** Stack:
Ports represent external resources in the most general sense. In particular, they are a generalization of files and urls. In this, they implement the concept of Uniform Resource Identifier (URI), as defined in RFC3986, and the various operations on the resources represented by URIs; the functionality offered by ports will be more complete than the basic file and url I/O currently provided. In addition, they may represent all other external resources such as serial ports, database servers, audio and video devices, timers etc.
The operations applicable to ports are described in section 11.4.2; besides I/O operations proper, these comprise most of the series operations as already described in sections 9.2/3. These operations differ according to the type of resource, which RFC3986 calls its scheme. The ports facility of Red extends this notion to all external resources, not only those considered by RFC3986. For certain schemes, Red provides a built-in implementation of the operations, in the form of Red actions (action! values). For other schemes, the user can provide the implementation in the form of Red functions (function! values).
yield: function [items] [ f: first items items: next items f] data: [ 1 2 3 4 ] >> yield data == 1 >> yield data == 1 >> yield data == 1 >> yield data == 1
items and f are local to a function. Also, index of series is kept inside word, not the series itself:>> a: "1234" == "1234" >> b: a == "1234" >> a: skip a 2 == "34" >> b == "1234"
yield: func ['items] [ f: first get items set items next get items f ] >> yield data == 1 >> yield data == 2 >> yield data == 3 >> yield data == 4 >> yield data == none
also is a new one for me. Will check it out!?? but to list all the words and their values?body-of system/words for global ones.probe new-line/all sort words-of system/words true may be of more use (or maybe what).also. Pretty cool:yield: function ['items] [
also
first get items
set items next get items
]function as you define no words there (but function is rewritten into func).foreach word sort words-of system/words [
if not unset? :system/words/:word [
print [
pad word 15 #" "
pad type? get word 15 #" "
replace/all copy/part help-string :word 100 #"^/" #" "
]]]browse linkxde-openprogress. Suppose I have 4 progress, like this:view [
p1: progress 20x100 100%
p2: progress 100x20 100%
at 150x10 p3: progress 20x100 50%
return at 40x90 p4: progress 100x20 0%
]progress solutions - no need to waste your time.1%? Can I change it? progress, if someone can verify what features work across platforms, that would be great. spec field of the port in case the resource has no URI (e.g. the GPIO port already provided). Is it obliged to have the same structure as a URI spec (system/standard/url-parts)?"system/schemes, similar to how codecs work. You create a new scheme and add it to the system with register-scheme. Beyond this, you can think of Red as providing a simple interface for common cases, but you are not limited to that. For example, when file!s support open, you get a port with a scheme name of 'file, and that port can leverage some of the same fields as for urls (which get their scheme name from the first part of the URL); e.g., path and target. The file and URL types map to a common port configuration. crypt port, like files and urls, let you insert raw data, while the GPIO port provides a dialected interface. base's draw)? If not is there a plan to add it? view [base 100x100 draw [box 49x49 51x51]] but without hardcoded values: view [b: base 100x100 draw [box (50% |- 1x1) (50% |+ 1x1)]] (pseudo code, but it shows using not-hardcoded values).system/view/VID/styles?stylize function long ago, but it needs to be updated. He may be the best to advise on it. https://github.com/red/red/pull/3825resize-deep-test.red and play with resizing the window./into result [block!] put result to block? output: make block! 16 ;use for temporary outputs ?copy for a series, a new copy is created each time. When you see clear, the existing series may not deallocate memory, so it can be reused. myword: copy "" That's the only way I know to clear a string. myword: clear ""copy is the standard approach, and good for most cases.SQLite/query sql-query
result: SQLite/query sql-query clear result
*** Compilation Error: undefined word x *** near: [x align anchor-of y align]
Red [needs: view] #include %elasticity.red view/flags elastic [ area "Hello tensile world!" #fill button "OK" [quit] #fix ] 'resize
sqlite/query call](https://github.com/red/code/blob/8bc261749fbf9920e2155c077411c64e7c1bdae8/Library/SQLite/SQLite3.red#L452)recycle off.-d)license: BSD-3 - from the file-e?-c -e:*** at line: 353
*** near: [word/duplicate ~script
~args|467: word/duplicate ~args comment "Literals"
ctx48:
]-u then. recycle off.random keeps generating the same number every time I run the program? For instance random 100 keeps giving me 53. I can't understand this behavior...random/seed now/timerandom without having to seed it first?random without seeding if you are doing "soft randomness" (e.g. pick one number a day, but you don't have any/many constraints like it can output the same number 3 days in a row).ask. I added #include %./red-source/environment/console/CLI/input.red to my code but I keep getting random compiling errors related to win32.reds.-r and it worked!-c I get this error: Target: MSDOS
Compiling to native code...
*** Compilation Error: undefined symbol: red/unicode/cp-to-utf16
*** in file: %/C/Users/wally/Coding/Red/red-source/environment/console/CLI/win32.reds
*** in function: exec/terminal/emit-red-char
*** at line: 282
*** near: [unicode/cp-to-utf16 cp pbuffer
pbuffer: pbuffer + n
]-c -u-c -u but I get this error now: *** Compilation Error: undefined symbol: root *** in file: %/C/Users/wally/Coding/Red/red-source/environment/console/CLI/input.red *** in function: exec/terminal/init-globals *** at line: 356 *** near: [root 1]
Compiling to native code...
*** Compilation Error: argument type mismatch on calling: exec/parse-text-styles
*** expected: [integer!], found: [struct! [
header [integer!]
head [integer!]
node [pointer! [integer!]]
cache [pointer! [integer!]]
]]
*** in file: %/D/devel/red/red-src/red-master/modules/view/backends/windows/text-box.reds
*** in function: exec/gui/OS-text-box-layout
*** at line: 365
*** near: [str catch?][root 1] error you mentioned. I'll report this bug.-r. Unlikely you need to compile things often, as Red is primarily an interpreted language.-r mode is actually required when the program contains #include statements or Red/System code. So, I guess those errors with -c seem to be an expected behavior. -e (or do in code) to force interpreted mode in compiled apps, when your code is either very dynamic or runs up against compiler limitations.#include statements, or when it contains Red/System code."callinterface), or any work already being done wrapping some OS level libraries?/foo /bar signatures like here:/data and /auth together send-request/data ... is ok, but how to add /auth?send-request/data/auth server method content auth-type auth-datasend-request/auth/data server method auth-type auth-data contentsend-request is overloaded with refinements (eight, the horror!), so my plan is to create make-request and accept one or two args, link and dialect (and probly also settings object, I don't have the design done yet). I'll keep send-request as a wrapper for compatibility, but make-request will be main code. No ETA, but I'm still adding new stuff to send-request so I need to make the switch ASAP.auth-data contain prefix Bearer like: 'Bearer "eyJhbGciOiJIUzI1N ...... hSns=" or only: "eyJhbGciOiJIUzI1N ...... hSns="?auth-type so your code should look like this:send-request/data/auth server method data 'Bearer "asdf"
answer: send-request/auth http://localhost:8529/_db/ztest/_api/collection/protocols 'POST 'Bearer "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjEuNTkzMTcyOTU4NTg4MzQ3OGUrNiwiZXhwIjoxNTk1NzY0OTU4LCJpc3MiOiJhcmFuZ29kYiIsInByZWZlcnJlZF91c2VybmFtZSI6InVzZXIifQ==.a9L7AGDqjjZv1OdFYmT_uFUGLbX_NBva00UoUQXhSns=" *** Script Error: invalid argument: none *** Where: write *** Stack: send-request
/data 400 -- bad request:answer: send-request/data/auth http://localhost:8529/_db/ztest/_api/collection/protocols 'POST to-json object [a: 1] 'Bearer "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjEuNTkzMTcyOTU4NTg4MzQ3OGUrNiwiZXhwIjoxNTk1NzY0OTU4LCJpc3MiOiJhcmFuZ29kYiIsInByZWZlcnJlZF91c2VybmFtZSI6InVzZXIifQ==.a9L7AGDqjjZv1OdFYmT_uFUGLbX_NBva00UoUQXhSns="
answer: send-request/data http://localhost:8529/_db/ztest/_api/collection/protocols 'POST to-json object [a: 1]
to-json, it should convert authomatically/verbose and /debug refinements to see what is going on, full reply then will be available in raw-replycurl -X POST http://127.0.0.1:8529/_open/auth --data '{"username":"user","password":"123"}'send-request/data http://127.0.0.1:8259/_open/auth 'POST #(username: "user" password: "123")
*** Access Error: cannot connect: http://127.0.0.1:8259/_open/auth reason: timeout *** Where: write *** Stack: send-request
send-request/data http://127.0.0.1:8529/_open/auth 'POST #(username: "user" password: "123")
>> send-request http://localhost 'POST *** User Error: POST method needs data. Use /data refinement.
send-request/data/auth?data: #(
jwt: {eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjEuNTkzMTc5NjY3NDYyMTUyNGUrNiwiZXhwIjoxNTk1NzcxNjY3LCJpc3MiOiJhcmFuZ29kYiIsInByZWZlcnJlZF91c2VybmFtZSI6InJvb3QifQ==.kltSJm_SzzuNUf3tlGtK_ISxcxnerjMNkFqlsbr4vw0=}←
)send-request yet (although I have some partial implementation).send-request to be able to use ArangoDB, sorry.send-request however to use ArangoDB, you actually don't need it. Do this:reply: send-request/data arangodb-server:port/_open/auth 'POST #(username: "name" password: "pass") token: reply/data/jwt reply: send-request/auth arangodb-server:port/_db/mydb/_api/version 'Get 'Bearer token
http://static.red-lang.org/dl/branch/GTK/linux/red-latest on Linux? Trying some docker images - seems to run in Ubuntu but not on Alpine.#(f: function [] [print 'yes]). Is it a feature or a bug (without gui console closing of course)?map! is not reduced at creation. It's by design and [documented](https://github.com/red/docs/blob/master/en/datatypes/map.adoc#3-creation-syntax).... 'basic ["username" "password"], it Will convert it to proper formatextra being a block or map?type & size)? Based on the links (and red's site) I was able to define actor but I cannot set a default actor (that which is set without on-even text):extend system/view/VID/styles [
ttt: [
template: [
type: 'text
color: 255.0.0
size: 100x100 ; you need to define it!!!!
default-actor: function [f e] [print 'default]
fas: function [a] [a * 2]
actors: [
on-down: function [face event] [
print 'text-on-down
probe face/fas random 100]
]
]
]
]
; works:
view [ttt "foo" ]
; error:
view [ttt "foo"[print 'not-default-actor]]
; Script Error: make-actor does not allow none for its <anon> argument?? system/view/VID/styles is your tutorial ;)size, but it should be obvious that if you don't define it - you *have* to explicitly set it in the VID block.type it's not obvious. Why I should define size but not color? Well, I'm going to check system/view/VID/styles.default-actor in the wrong placekeep within a collect, and keep is a red word:; my function
foreach*: function ['items collection body] [
body: replace/all/deep body 'yield 'keep
collect [ foreach items collection body ]
]
; some test
foreach* i [ 1 2 3 4 5 6 {hello} 45 {world} ] [
if string? i [ yield i ]
]
==
*** Script Error: keep has no value
*** Where: do
*** Stack: do-file*** Script Error: i has no value *** Where: string? *** Stack: do-clip foreach* collect string?
do-clip is my own func to do from the clipboard. You need to compose in (items), then I get the error you posted. Remember that foreach itself uses a lit-word argument. I'll also suggest using the same parameter names, if you're using a variant of foreach for the name. Replace modifies the series in place, so you don't need to reassign body:, as another side note.compose the body into the body that is collect's arg. Even talking about things like this can show how important context is. :^)foreach*: function ['items collection body] [
replace/all/deep body 'yield 'keep
collect compose/only [
foreach (items) collection (body)
]
]
; some test
blk: [1 2 3 4 5 6 {hello} 45 {world}]
foreach* i blk [
if string? i [yield i]
]compose .body after replace doesn't hurt anything, but it's a subtle idiom that can aid readers. If you don't use the result of an expression, it's a hint that you are relying on side effects.Red [] from: 'x x: [ [cat dog elegant] ] print (from)/1/1
select action.get returns the value form refers to (x -> [cat dog elegant]), pickreturns the value of the series at the given index.>> view [] creates windows etc., but the console itself is strictly CLI).>> o: object [a: 1]
== make object! [
a: 1
]o after it's createdextend function... but it's not implemented yet. Not sure how it would work though.map! (or block!). If you have to use an object then maybe you can create another object with old fields, like in this case:m: #() m/o: object [ a: 1 ] m/o: make o [b: a]
init text's size? Or is it a bug:extend system/view/VID/styles [
style-name2: [
template: [
type: 'text
size: 200x200
color: red
]
]
]
view [ style-name2]type: 'base , the size is set correctly.text face also ignore the font and always use a static height?view [text "foo" 10x10]layout function to work as you like.init shouldn't count) it works as expected -> it sets correct size. /bug. size is not a size of a face.extend system/view/VID/styles [
style-name2: [
template: [
type: 'text
size: 200x200
color: red
]
]
]
view [ style-name2]view [text 200x200 red]
size/y is never used?init or on-create? I've tried init [
print 'initiation
face: none
]face: make-face 'another-type works for changing face type).on-create and init. One thing is I can set another style/face. I was wondering if there is more.init is used internally by the style, while on-create is for the user to override.init you have to create external style (extending built-in styles) but with on-create it's inside block.init, on-create and on-created are especially bags of tricks, and when you try to use reactivity inside them... well I hope you don't.do-actor is an internal thing, not guaranteed to not go away. While actors are functions so why not call them directly as face/on-down face event?do-actor -> well, I took it from the main page. It has some nice error checking and it checks whenever or not an actor/event exists but face/on-actor face event should be sufficient in a lots of cases.with is not *only* for setting some face fields, it actually just binds the given block to the newly created face object and then evaluates. So you can execute any code in there.with block will override the previous ones:>> view [style btn: base red with [print "I'm Here!" ] btn with [print "I'll be overwritten :("] with [print "Here I am!" ]]
I'm Here!
Here I am! view/no-wait [bs: base red] do bind [color: red] bs do-events
Only (?) with init you can change a face, init block is also bind & evaluated during the face creation (after the face object created before the events triggered).with will override first with?do-actor: [do-actor](https://github.com/red/red/wiki/%5BTUTORIAL-EXAMPLES%5D-gui-styles#triggering-an-actor) d: do "1976/03/14" returns a date! type. Similar to load as suggested by Boleslav.walk-files.red gist. (https://gist.github.com/dockimbel/1c0f51e3044f23688aae696a28d3096b). The first line of the dive function binds the word 'path to action. Without really understanding what bind does, it appears to make 'path available inside action. My question is how does action know what file is since file isn't bound to action like 'path is?bind action 'path is the same as bind action context? 'path which in this case is the same as bind action :dive, thus it exposes arguments and locals of dive to action. file is one of those locals (function collects foreach argument as a local).bind or specific to this example?view [
style s: base red 100x20
s
s rotate 90
s rotate 180
s rotate 270 transform -100x20
]draw?bind action 'path followed with do action instead of having action be a function and then calling the function?>> a: func [x] [fnc: [probe x] do fnc] () >> a 1 1 == 1 >> a 2 2 == 2 >> a 3 3 == 3 >> a 4 4 == 4 >>
X in my example? The block is static between function iteration, so I suppose that once the function is created it will have the context of the first run but X returns results reflecting the current argument value. So X is not bound to an "absolute context" connected to the function. It is the one of the current run. But how is happening the rebinding or the context retrieval? The X context is not a fixed one, it seems different at each run!X is part of locals. You pass the arguments and the respective context entries are set. X is set to a value during the first run. Then you invoke the function for the second time with different arguments, local values are cleared, aren't they? I have tried and it seems they are set to none at each run. >> a: func [val /local x] [probe x if x = none [x: val] fnc: [probe x] do fnc] == func [val /local x][probe x if x = none [x: val] fnc: [probe x] do fnc] >> a 1 none 1 == 1 >> a 1 none 1
none too ?f1: func [/local x][ x: [] append x 1 print x ] f1 ;-- 1 f1 ;-- 1 1 probe body-of :f1 ; [ ; x: [1 1] ; append x 1 ; print x ;]
f1: func [/local x][ x: copy [] append x 1 print x ] f1 ;-- 1 f1 ;-- 1 probe body-of :f1 ; [ ; x: copy [] ; append x 1 ; print x ;]
copycopies the empty block, every time.x is. x takes on a particular value [1] by the end of the function. But unlike the first example, that change isn't reflected in the function body after the fact. x: [1] just on the stack somewhere but doesn't get placed in Red's representation of the code?f1 you have 3 literal blocks: [/local x] [x: copy [] append x 1 print x] and [] inside it.copy does what you expect of it: copies the given block and returns the new one. x is now a copy. It's not anymore the same [] block that is within the f1 body.x points to it and x is locked by the function body during evaluation.x, you now have it on the stack or assigned to something, so it's not lost.x, that value is now inaccessible?f1, which in turn links to it's body, which links to [].system/wordsf1 is just a block. It has a word x which refers to no value after the f1 returns, and it has a literal block []. But not your copied block.x in memory?x is a word, it's not collected.none too ?>> y: 33 a: func [/ref y] [probe y] >> a none
x: [1]x refers to may be collected.set-word rather than a wordx: won't be collected as it's a flavor of a word (anyway, a scalar).[1] because you have a link to it.x is getting collected?1 is never appended to x, but to the value x refers to, in your case a block.x when it doesn't act as a variable.f1 and not only the definition of f1 which exists in a context that wraps around f1?f1 points to this new inner context during the function call and then not again?func creates a context. But function context is a stack. That is, it is layered ;) You call f1 - a layer of values is added. You return - the layer is stipped away.>> f: func [/local x] [local: 100 print [local x]] == func [/local x][local: 100 print [local x]] >> f 100 none >> f/local 200 100 200
x is [1] only in the second context. But the value of x as copy [] still exists in the first context. Whereas in the first example the second context created from the call to f1 does not assign a new value to x? context).func sets the value of local to true or false in the new context created by the function call?VID and parse were the clear audience favorites, but it was a trick question. Carl was in the front row, looking at who was voting for what, and getting very excited. I finally told them they were all wrong, and asked Carl to tell them. context.set creates and destroys both.context and make object! create contexts. func creates contexts. function calls create context. VID and parse...button outside of a view block, it has the same value as within?view [ btn: button "click here" [ alert "I've been clicked" ] ] probe btn
btn is a face outside of the view block. So not a different context. Gotcha.1 then it will get this value. If you link the word to another context it will take another value. You manipulate the link with BIND. BIND = LINKER. [A A A] is a block with 3 elements and each A has its own link. Once you REDUCE the block Red will scan the link (the context) of each one and will return the value associated to each instance of to the word A. So REDUCE [A A A] can return [33 55 "HELLO"] if 3 different links exists.func creates a context, it only binds the /local words to it? All the other words are still bound to the outer context?x being rebound to [] every time the function is called? But [] is always the same [] that was bound to the function when the function was created?[rock rock rock]. x is getting set every time, but the *context* is not being edited as in the previous example, where [] (which exists in the function context) was getting appended to?none for LOCALs and then the block evaluation starts! [] is not in the global context.[] does not feature in any table, then?f: func [ARG1 ARG2 /local x ][ probe ARG1 x: copy [] ]
view [ size 300x300 at (face/offset) button red ]
view/flags [size 500x500 on-over [print ["Button is at" foo/offset: event/offset + 20 "coordinate."]] foo: button] 'all-over
view [size 500x500 button loose on-drag [print ["Button is at" face/offset "coordinate."]]]
foo) in order to update its position. all-over flag is described in [View documentation](https://github.com/red/docs/blob/master/en/view.adoc#2-face-object).button/offset doesn't work?button is a VID keyword which describes a type of the face; you can have many buttons, but you cannot refer to either of them by their type.view [button "Move text" on-over [face/offset: 30x20 face/text: "Now I'm here"]]
face inside on-over actors refers to that particular button face. Internally each actor is a function with two arguments, face and event.face so that face can refer to itself even without knowing its proper name, or you can index a face by a path to it, or by any other indirect means:view [button "Click" [face/parent/pane/1/text: "Clicked!"]]
button at the end of the code and I thought you had already declared it at the beginning. foo and now it works:view [button on-over [print ["Button is at" face/offset: event/offset + 20 "coordinate."]]] all-over
view [on-down [print ["I am a" face/type]]]
view [ size 300x300 at (/offset) button red ]
view [ size 300x300 at (x/offset) x: button red ]
at takes an expression which specifies where the next widget should be placed, so this expression should return a pair!:view [at random 300x300 base red]
x at the time it evaluates x/offset, you can refer to x only after the button was defined, e.g. inside a do block:view [x: button do [x/offset: x/offset + 10x10]]
>> list: "abc, a, bc" == "abc, a, bc" >> parse list [collect [some [keep to ", " 2 skip] keep to end]] == ["abc" #"a" "bc"]
#"a" to be "a"copy.thing: [copy x [to ", " | to end] keep (x)] >> parse list [collect some [thing 2 skip]] == ["abc" "a" "bc"]
text >> parse "abc, a, bc" [collect some [keep copy _ to [comma | end] [end | comma space]]] == ["abc" "a" "bc"]
keep copy _ is nice.parse (basics) wiki page for things like this?_ (like in keep copy _). It sounds to me like a trick. Is it a feature of parse ? I did not find any mention of it in the docs_ is just a throwaway word.keep copy idiom because, technically, copy here is not an option like e.g. pick, but a separate rule; it's just that Parse [handles](https://github.com/red/red/blob/a1d14954e5c906556d0e29fb4266951549db935f/runtime/parse.reds#L1061) it in a specific way.copy as _matching_ portion of the input (i.e. not a single value, but a series with zero or more values inside) and keep preserving the _match_.>> parse "a" [collect keep skip] == [#"a"] >> parse "a" [collect keep copy _ skip] == ["a"] >> parse "a" [collect keep pick copy _ skip] == [#"a"]
collect/keep work, perhaps it should be moved into Parse Cookbook.keep pick.keep copy didn't click right away because I thought keep would copy it, and I'm copying it with copy again, so what a waste. I wonder if it's true? ;) If not, then there should be a special case for it in parse.keep, it checks if there's a copy sub-rule; if there is, then it preemptively fetches the value slot into which the matched value will be eventually copied, and then appends content of that slot as-is. You can see it in the code I gave above.collect needs a design review. This particular case always seemed to me as a crude workaround.a: random 100 always returns 53 as the initial number? I can close and reopen the console and I always get 53. ? random? If you want different results, use /seed. The behavior is by design, so you get reproducibility by default.random without a seed will always produce the same sequence of numbers, is that right?random is common across languages I've seenrand 100 and you get a random number from 0 up to 100. random question from the Beginner's FAQ until I can find a better place for it. Thank you for your recommendation.random :point_up: [Aug 15 2019 21:56](https://gitter.im/red/red?at=5d55aacd4e17537f5239de0c) *** Error: not a Red program!--encap toolchain flag.Red [] x: copy ["a" "b" "c"] A: remove random/only x 1 remove x "" B: remove random/only x 1 remove x "" C: remove random/only x 1 remove x "" print A
help take in the console.help random. :^) 1 doing in your example?Red [] x: copy ["a" "b" "c"] remove random/only x 1 probe x ; ["" "b" "c"] remove x "" probe x ; ["b" "c"]
1.1 and "" in your examples. Use help. Try each function separately.x: copy ["a" "b" "c"] remove random/only x probe x ; ["a" "" "c"] ; But I want "b"
help in the console and study embedded documentation for all the functions that you used.x: ["a" "b" "c"] A: take random x print A
x: ["a" "b" "c"] random/seed now A: take random x print A
now returns current date & time.extend system/view/VID/styles [
custom-progress: [
default-actor: on-down
template: [
type: 'base
draw: copy [
transform 50x50 0 1 1 20x0 [fill-pen progress-color box 0x0 20x20]
;transform center-of-rotation 0 1 1 20x0 [fill-pen progress-color box 0x0 20x20]
]
progress-color: purple
size: 100x100
center-of-rotation: 50x50
]
]
]
view/no-wait [
cp1: custom-progress
]progress-color works, center-of-rotation doesn't work. It gives me: *** Script Error: invalid Draw dialect input at: center-of-rotation 0 1 1 20x0 fill-pen progress-color box 0x0 20x20.transform.Red 0.6.4 for Windows built 20-Jun-2020/19:24:25+02:00 commit #4d864b1>> block: [a b c] == [a b c] >> value: take at block random length? block == b >> block == [a c] >> value == b
random/only should rather randomize series' index.random function returns different values at start. Just be careful when you see random without random/seed.draw's commands accepts word! and some don't. Would it be possible that all commands would accept word!? For example: transform center angle scale-x scale-y translation [box start-pos end-pos]. If not all words, could it at least check for words defined in a template, for example:template: [
type: 'base
draw: copy [box _start _end]
_start: 0x0
]_end is not in the template.random/seed 1 or smth.draw from another block, like this: extend system/view/VID/styles [
custom-progress: [
default-actor: on-down
template: [
type: 'base
draw-block: copy [
transform (center-of-rotation) 0 1 1 20x0 [fill-pen (progress-color) box 0x0 20x20]
]
center-of-rotation: 50x50
progress-color: purple
size: 100x100
center: 50x50
update-draw: function [][
self/draw: compose/deep self/draw-block
]
]
init: [
face/update-draw
]
]
]
view/no-wait [
cp1: custom-progress
]random is seeded with some [arbitrary constant](https://github.com/red/red/blob/7f2db9b69d69d6c0216cef23a5aafb81eaeefd03/runtime/random.reds#L133) on booting.until's design, and it ties to HOF as well.random/seed 19650218 at the beginning of any scripts that were counting on that random sequence.randomize at the start of scripts where they need it.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 form any [seed now/precise] 'sha1 ] ]
randomize at the start of scripts where they need it.SSL_ERROR_RX_RECORD_TOO_LONG. This is one of those days.to-string (the spaces before and after 2)?>> a: [0 [1 2 3] 4 5] == [0 [1 2 3] 4 5] >> to-string a == "01 2 345"
formed values together.>> collect [foreach value [0 [1 2 3] 4 5][keep form value]] == ["0" "1 2 3" "4" "5"] >> rejoin collect [foreach value [0 [1 2 3] 4 5][keep form value]] == "01 2 345"
>> to string! [1 [2 [3 [4 [5]]]]] == "12 3 4 5"
to string! on rich values isn't something we want to encourage, if any kind of control over formatting is needed. to string! logic internally, rather than form.>> collect [foreach value [0 [1 2 3] 4 5][keep to string! value]] == ["0" "123" "4" "5"] >> rejoin collect [foreach value [0 [1 2 3] 4 5][keep to string! value]] == "012345"
Rename has been added somewhere on the road to 6.5.view [text gray on-down [face/color: white] on-up [face/color: gray]] view [text #808080 on-down [face/color: white] on-up [face/color: #808080]]view [my-face: text gray on-down [face/color: white] on-up [face/color: gray]] my-face/color view [my-face: text #808080 on-down [face/color: white] on-up [face/color: #808080]] my-face/color
view [my-face: text #808080 on-down [face/color: white] on-up [face/color: to tuple! #808080]] my-face/color
gray and white are just shortcut words for their respective RGB values and VID accepts Hex color but it actually converts it back to RGB.view [text #808080 on-down [face/color: white] on-up [face/color: 128.128.128]]? tuple!.colors: exclude sort extract load help-string tuple! 2 [transparent glass]
view/tight collect [
until [
foreach color take/part colors 4 [
keep reduce [
'base 70x40 form color get color pick [white black] gray > get color
]
]
keep 'return
empty? colors
]
]help-string is available in console only, you might want to change it to something like:colors: collect [ foreach word words-of system/words [ if tuple? get/any word [keep word] ] ] colors: exclude sort colors [transparent glass]
red/code](https://github.com/red/code/blob/master/Scripts/palette.red).remove-each w colors: words-of system/words [try [not tuple? get w]]parse colors: to [] system/words [collect any [thru tuple! p: keep (to 'p p/-2)]];colors: exclude sort extract load help-string tuple! 2 [transparent glass]
colors: [
aqua
beige
…red —help though. Is there an option to prevent console showing up?-t WindowsrcvGetSystemColors: function [ "Get system colors" return: [block!] ][ sColors: collect [ foreach word words-of system/words [ if tuple? get/any word [keep word] ;--use get/any for unset words ] ] exclude sort sColors [transparent glass] ]
img: make image! [255x255]
repeat i (255 * 255) [
img/:i: to-tuple reduce [random 255 random 255 random 255 200]
]
view [
base 300x300 draw[
fill-pen red
box 10x10 50x50
push
[
fill-pen bitmap img
box 10x10 50x50
]
fill-pen red
box 50x10 100x50
]
]fill-pen bitmap img isn't popped from the stack. I've tried writing pop but it doesn't work. Red 0.6.4 for Windows built 20-Jun-2020/19:24:25+02:00 commit #4d864b1fill-pen off.pop command in Draw, at the end of the block the state is restored automatically.noise: make image! 255x255 forall noise [noise/1: random white] ? ( draw 100x100 [ fill-pen red box 0x0 50x50 push [ fill-pen bitmap noise box 50x50 100x100 ] box 0x50 50x100 ] )
fill-pen red before the last box. But with e.g. fill-pen blue it works.img: make image! [255x255]
repeat i (255 * 255) [
img/:i: to-tuple reduce [random 255 random 255 random 255 200]
]
view [
base red
base red draw [ fill-pen bitmap img box 0x0 100x100]
]fill-pen off at the end of push works. As @9214 mentioned I've tried to move few lines of code to the push and it worked:img: make image! [255x255]
repeat i (255 * 255) [
img/:i: to-tuple reduce [random 255 random 255 random 255 200]
]
view [
base 300x300 draw[
push
[ ; those 2 lines:
fill-pen red
box 10x10 50x50
fill-pen bitmap img
box 10x10 50x50
;fill-pen off
]
fill-pen red
box 50x10 100x50
]
]fill-pen off.Saves the current state (transformations, clipping region, and pen settings) on the stack. If pen settings including fill-pen, then it's a bug.rebol> write %test.txt to-char 199
write to-file "calendar.txt" areacalendar/textset-face read to-file "calendar.txt"; Basic UTF-8 conversion for RED:
bin-to-string: function [bin [binary!]][
text: make string! length? bin
foreach byte bin [append text to char! byte]
text
]collect) in my HTTP-tools (now CASTR):load-non-utf: func [
data [binary!]
] [
copy collect/into [forall data [keep to char! data/1]] {}
]copy be rather before {}? Currently it keeps growing as {} is not copied:>> length? b: load-non-utf read/binary %whatever == 734 >> length? b: load-non-utf read/binary %whatever == 1468 >> length? b: load-non-utf read/binary %whatever == 2202
function, is there a way to use set so that it doesn't set at the global scope? Example:myfunc: function [ varname value ] [ set to-word varname value ] a: 1 myfunc "a" 3 print a == 3
function, all words inside it are local. What I'm trying to do is programmatically do a: 3 so that a = 3 only inside the function. But set seems to set at the global scope. fn "myfunc" [ string "param1" integer "param3" ] [ var [ "a" 3 ] var [ "b" 4 ] ... ]
set doesn't "set at the global scope", there are no scopes in the language at all. You give it a word a bound to the global context, and it changes the value to which it is set in that context, that's all there is.a to be local, then you need to manually craft a context, and then bind a to it.foo: func [word value][ bind word: load word context compose [(to set-word! word) value] ]
>> a: 123 == 123 >> get foo "a" 456 == 456 >> a == 123
>red.exe app.red -foo/red roomwindow-title: "" open-img: func[][ img-file-name: request-file/filter ["png" "*.png" "jpeg" "*.jpg" "gif" "*.gif"] only-file-name: find/last img-file-name "/" window-title: rejoin ["File name: " only-file-name] ] open-img menu-block: layout [ title window-title ] view/options/flags menu-block [offset: 0x0][resize]
?) you can not to use func at all:
`open-img: does [ img-file-name: request-file/filter ["png" "*.png" "jpeg" "*.jpg" "gif" "*.gif"] only-file-name: last split-path img-file-name img/image: load img-file-name img/size: img/image/size lay/text: rejoin ["File name: " only-file-name] lay/size: img/size + 20 ] lay: layout [ on-menu [switch event/picked [open [open-img]]] img: image ] view/options lay [offset: 0x0 menu: ["Open" open]]
open-dir: function [][ img/image: none change-dir folder: request-dir/keep files: read folder remove-each file files [not find [%png %jpeg %gif] find/tail/last file dot] list/data: files ] lay: layout [ on-menu [switch event/picked [open [open-dir]]] list: text-list 150x200 on-change [ file: pick face/data face/selected img/image: load file img/size: img/image/size lay/text: rejoin ["File name: " file] lay/size: as-pair 30 + list/size/x + img/size/x 20 + max list/size/y img/size/y ] img: image ] view/options lay [offset: 0x0 menu: ["Open dir" open]]
read/info might do it but it seems to have the same behavior as read.query is meant for that, but currently it returns date only.read/info you can get metadata for web pages, e.g.>> data: read/info https://www.red-lang.org/ second data
== #(
Cache-Control: "private, max-age=0"
Date: "Thu, 30 Jul 2020 07:56:51 GMT"
Transfer-Encoding: "chunked"
Content-Type: "text/ht...system/script/args contains a string of them, and system/options/args has a list of them in tokenized form.Red [File: %test.red] probe system/script/args probe system/options/args
$ red --cli test.red some command-line arguments "some command-line arguments" ["some" "command-line" "arguments"]
compose them into your draw blocks.composeing might destroy things (if not used carefully!).Draw is implemented in Red/system, so it would have to be some kind of extension system, where you register new shapes and their associated parameters and R/S routine code, which means things have to be compiled.draw has something *similar*.Draw doesn't not have anything like styles, but it's a good design space.open-img: function [/recent file][
img-file-name: either recent [
to-file replace/all to-string file #"|" #"/"
][
request-file/filter ["png" "*.png" "jpeg" "*.jpg" "gif" "*.gif"]
]
only-file-name: last split-path img-file-name
if not recent [
repend lay/menu/("File")/("Recent") [
form only-file-name
to-word replace/all to-string img-file-name #"/" #"|"
]
]
lay/text: rejoin ["File name: " only-file-name]
img/image: load img-file-name
lay/size: 20 + img/size: img/image/size
]
lay: layout/options [
on-menu [
switch/default event/picked [
file-open [open-img]
][
open-img/recent event/picked
]
]
img: image
][
menu: [
"File" [
"Open" file-open
"Recent" []
]
]
]
view layrepend reduce so there is another reduce):insert lay/menu/("File")/("Recent") reduce [if 3 < length? lay/menu/("File")/("Recent") [
remove back tail lay/menu/("File")/("Recent")
]if not recent [...] part. It should show only 3 files. When you pick 4th it will delete the earliest one.open-img/recent event/picked? event/picked returns none (tried on 20-Jun-2020/19:24:25+02:00 and recent build).; If you use this consistenly on a series, you will always have
; unique instances. If you don't, you can apply UNIQUE yourself.
; So this function doesn't need a /unique refinement.
insert-MRU: func [
"Insert value in series; removing first existing instance."
series [series!]
value
/limit size [integer!] "Limit the series to the given size by removing the last item."
][
remove find/only series value
insert/only series value
if all [size size < length? series] [remove back tail series]
series
]event/picked return only words from menu and none for other types, e.g. file and path? It would be much easier to implement e.g. MRU file-lists, if file type were also returned. Now we have to invent cunning ways :)if 6 < length? lay/menu/("File")/("Recent") [
remove/part back back tail lay/menu/("File")/("Recent") 2
]>> c: [a false] probe type? c/a word! == word! >>
#[false]c: reduce [a to-logic false] mold/all cto-logic before the path considers false as word because it is picked by path as this type and not for its content, so:>> to-logic first [false] == true >> first reduce [to-logic false] == false >>
first reduce [to-logic false], when you reduce, to-logic is not necessary as false word evaluated to false logic!.first reduce [false] or first compose [a (false)].Ctrl + Shift + M in the message field to see the cheatsheet), so you can format code using fences — that way people who help you will have an easier time reading what you've posted.type? first append [] true arr: [meh] arr/1: true type? first arr
open-img function the first expression (setting img-file-name) seems confused, as you are (re)setting same name inside either.file-name (third line from bottom) is used only once and seems superfluous.view/options [
on-menu [tx/text: form next face/menu/("File")/("Recent")]
tx: text 200
][
menu: ["File" ["Recent" ["Try" It works nevertheless]]]
]menu/("File")/("Recent") is not working.>> to-word replace/all to-string %/C/some.file #"/" #"|" == |C|some.file
File/Resent/Try is selected from menu:view/options [on-menu [tx/text: form next face/menu/("File")/("Recent")] tx: text 200][menu: ["File" ["Recent" ["Try" It works nevertheless]]]]>> parse file: to-string %"/C/Red programming" [any [change #"/" #"|" | change #" " "__" | skip]] fw: to-word file == |C|Red__programming >> parse file: to-string fw [any [change #"|" #"/" | change "__" #" " | skip]] to-file file == %"/C/Red programming"
view/options [on-menu ... works for me, I see "It works nevertheless" message on the window.view/options [on-menu [tx/text: form next face/menu/("File")] tx: text 200]
[menu: ["File" ["Recent" ["Try" It works nevertheless]]]]view/options [on-menu [tx/text: form select face/menu/("File") "Recent"] tx: text 200][
menu: [
"File" [
"A" A
"B" B
"C" C
"Recent" [
"Try" YESS I DID IT]]
]
]>> o: make object! [a: "test" on-change*: func [word old new] [print [word "changed"] ] ]
== make object! [
a: "test"
]
>> o/a: "ok"
a changed
== "ok"f with [extra: 'line image: (draw 23x23 [line 5x5 17x17])]
canvas: none out of the block, is this enough .>> img: draw/transparent 23x23 [line 5x5 17x17]
== make image! [23x23 #{
000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000...
>> view [button 25x25 with [image: img]]view compose/deep [button 25x25 with [image: (draw/transparent 23x23 [line 5x5 17x17])]]
view [button 25x25 with [image: system/words/draw/transparent 23x23 [line 5x5 17x17]]]
temp-img.pngcompose will copy the block. But it will matter in case of large blocks or tight loops only. It also affects how parens in other places in the block will be interpreted, which sometimes may force you to reconsider parens for grouping purposes.reduce is superfluous in constructs like reduce[compose [...]]mouse-state and then using mouse-state = 'down you can use event/down?reduced or composed a block, then using rependis superfluous, use append instead. Or use repend but then no need for reduce or compose.parse and I found the C++ [API](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-idesktopwallpaper-setwallpaper?redirectedfrom=MSDN) for setting a wallpaper on Windows.shobjidl.h uses extern "C" idiom mentioned in the wiki article, so symbols should not be mangled.C:\Users\yourname\AppData\Roaming\Microsoft\Windows\Themes and execute RUNDLL32.EXE USER32.DLL,UpdatePerUserSystemParameters ,1 ,True by call.image! from Bing first.parse!? replaces view and opens a window?? is a wrapper on top of help-string. You can ?? help-string to see how it behaves with image! values.cross-link-text: func [ o1 o2 ] [
o1/text: o2/text
o2/text: o1/text
]
my-react: make object! [
object-name: ""
on-change*: func [word old new
/local srs
][
print ["on-change* object-name =(" object-name ") word=(" word ") old=(" old ") new=(" 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
]
]
o1: construct/with [ text: "O1 TEXT" object-name: "o1" ] my-react
o2: construct/with [ text: "O2 text" object-name: "o2" ] my-react
react/link :cross-link-text [ o1 o2 ]
o2/text: "brand new text"on-change* object-name =( o1 ) word=( text ) old=( O1 TEXT ) new=( O2 text ) on-change* object-name =( o2 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o1 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o2 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o1 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o1 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o2 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o1 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o2 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o2 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o1 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o2 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o1 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o2 ) word=( text ) old=( O2 text ) new=( O2 text ) on-change* object-name =( o2 ) word=( text ) old=( O2 text ) new=( brand new text ) on-change* object-name =( o1 ) word=( text ) old=( O2 text ) new=( brand new text ) on-change* object-name =( o2 ) word=( text ) old=( brand new text ) new=( brand new text ) on-change* object-name =( o1 ) word=( text ) old=( brand new text ) new=( brand new text ) on-change* object-name =( o2 ) word=( text ) old=( brand new text ) new=( brand new text )
cross-link-text should probably include temporary varreact/link/later should be usedon-change* without most of the body would give better result in this case IMO:clear-reactions
cross-link-text: func [ o1 o2 /local tmp] [
tmp: o1/text
o1/text: o2/text
o2/text: tmp
]
my-react: object [
object-name: ""
on-change*: func [word old new][
print ["on-change* object-name =(" object-name ") word=(" word ") old=(" old ") new=(" new ")"]
system/reactivity/check/only self word
]
]
o1: construct/with [ text: "O1 TEXT" object-name: "o1" ] my-react
o2: construct/with [ text: "O2 text" object-name: "o2" ] my-react
react/link/later :cross-link-text [ o1 o2 ]
o2/text: "brand new text"on-change* object-name =( o2 ) word=( text ) old=( O2 text ) new=( brand new text ) on-change* object-name =( o1 ) word=( text ) old=( O1 TEXT ) new=( brand new text ) on-change* object-name =( o2 ) word=( text ) old=( brand new text ) new=( O1 TEXT ) on-change* object-name =( o1 ) word=( text ) old=( brand new text ) new=( O1 TEXT ) on-change* object-name =( o2 ) word=( text ) old=( O1 TEXT ) new=( brand new text )
my-react: reactor [object-name: ""]
insert body-of :my-react/on-change* bind [
print ["on-change* object-name =(" object-name ") word=(" word ") old=(" old ") new=(" new ")"]
] :my-react/on-change**on-change I like your example for modifying the *on-change function as well. What will the tmp variable accomplish in cross-link-text ?>> o1: object [text: ["o1 text"]] o2: object [text: ["o2 text"]] () >> swap o1/text o2/text () >> print [o1/text o2/text] o2 text o1 text
>> swap o1: ["o1"] o2: ["o2"] () >> print [o1 o2] o2 o1
unset!)a: copy [] b: [a b c d] if not empty? b [append b a]
empty?, tail? can pass-thru their argument if the condition is true or return false|none if the condition is not met. Also instructions like append* could have an /if refinement to act conditionally.append*/if a not empty? b
/if refinement because I think that I would loose the ability to add NONE or FALSE to a series but I have still not examined how FALSE|NONE behaves on series, but if there is another way of looking at this without /IF your ideas is welcome.append from Red standard one.empty?* but I have forgotten to do this.append*/iftake?a, b and condition as argument to /if refinement. But how would append* differentiate these arguments from your above line? (append*/if a not empty?* b)? /if just changing the way second arg is interpreted. Second arg in this case would be the result of not empty?* b. Now it needs to pass through b in case it is **not** empty, so that a could be appended to it. So empty?* should pass it through if false and then not should pass it through. It's becoming too weird indeed! :smile: You would need not-empty? to pass b through if true.b IMO. But you give as first argument something secondary and include the main argument as an argument to an argument (condition). Blasphemy! :imp: >> not-empty?: func [series][get pick [false series] empty? series] == func [series][get pick [false series] empty? series] >> not-empty? [] == false >> not-empty? [a b c] == [a b c] >> append*: func [a b /if][either if [either b [append b a][none]][append a b]] == func [a b /if][either if [either b [append b a] [none]] [append a b]] >> append*/if [a] not-empty? [] == none >> append*/if [a] not-empty? [b] == [b a] >> append* [a] [b] == [a b]
append* could also be defined asappend*: func [a b /if][either if [system/words/if b [append b a]][append a b]]
NOT is not passthru, so we have to define a not* to not be forced to create functions with multiple test. I have missed this too while being in "urgency to express my idea".IF or any other refinement or escaper because APPEND would lose the ability to append logic true and false to a series. Append* with a /where refinement which accepts functions or blocks to use for any.range1: func [data] [any [data > 10 data < 50]] test: [data > 10 data < 50] append*: func [ "Conditionally append a value" target [series!] "The target series" data "The value" /where condition [function! block!] "An ANY block with DATA word or an arity function to pass DATA to" ] [ either where [ case [ all [function? condition condition data] [ append target data ] all [block? condition] [ condition: bind copy/deep condition 'data if any condition [append target data] ] ] ] [ append target data ] ]
test: [data > 10 data < 50] append*/where [a b] 20 test == [a b 20]
range1: func [data] [any [data > 10 data < 50]] append*/where [a b] 20 :range1 *** Script Error: cannot compare true with 10 *** Where: do *** Stack: do-file
function? condition.... all [function? :condition condition data] ...
>> append*/where [a b] 5 test == [a b 5]
test. append*: func [ "Conditionally append a value" target [series!] "The target series" data "The value" /where condition [function! block!] "An ANY block with DATA word or an arity function to pass DATA to" ] [ either where [ case [ all [function? :condition condition data] [ append target data ] all [block? condition] [ condition: bind copy/deep condition 'data if any condition [append target data] ] ] ] [ append target data ] ]
range1: func [data] [all [data > 10 data < 50]] append*/where [a b] 5 :range1
*** Script Error: condition is missing its data argument *** Where: do *** Stack: do-file
range1: func [data] [all [data > 10 data < 50]] append*/where [a b] 18 :range1 == [a b 18]
any > 10, don't you? But I still don't see the problem.all, function? :condition returns true and condition data returns false — this means that all by itself returns false. What case will do if one of its branches fails?all [block? condition]. But condition is still a function, which gets called without an argument. Hense the error message. It's the same problem as with function? condition before.: as you @9214 are outlining.if condition [append target data]
if do condition [append target data]
ANY or ALL writing them directly in the test code.test: [any [((data > 10) and (data < 30)) data = 50]]
è and similar accented ones which block Red, ASCII code 138./where refinement on series focused functions like append/rename/insert/take/change about 1 month ago. It has taken some time to boil down. but now I have it in the most complete form: *conditionally selecting item form series passed as SOURCE. *range1: func [data] [all [data > 10 data < 50]] probe append+/where [a b] [5 11 89 22 55] :range1
[a b 11 22]
test: [any [((data > 10) and (data < 50))]] probe append+/where [a b] [5 11 89 22 55] test
[a b 11 22]
>> append+/where [a b] 5 func [x][all [x > 10 x < 50]] == [a b 5]
browse. do https://raw.githubusercontent.com/toomasv/learning/master/browser/text-browser3.red
view [ links-list: text-list data ["https://red-lang.org" "http://www.slashdot.org"] on-select [probe face/selected ] ]
on-change, which returns newly selected index.on-select returns previously selected index, and as you don't have anything selected originally, it returns -1on-select returns the list of all selected rows in a block. Empty block means "no selection" (it can happen after the last "unselect") otherwise it returns a block with all the indexes. IMHO, I find the block of indexes approach useful at it simplifies list selections processing without extra conditional checks. A simple forall list [] does not need to start without extra if face/selected <> none. Also, once multi selection will be implemented you will have to check multiple scenarios like having none, numbers! and block! type at the same time. list: ["one" "two" "three" "four" "five" "six" "seven" "eight" "nine" "ten"] i: 0 view [text-list data list on-time [if 12 = face/selected: i: i + 1 [unview]] rate 1]
face/selected.lucky?: function [numbers][
forall numbers [
total: if (third numbers) <> none [(first numbers) + (second numbers) + (third numbers)]
luck: either total = 7 [print true return true][false]
]
print luck
]
;Tests
lucky? [2 1 5 1 0]
lucky? [0 -2 1 8 ]
lucky? [7 7 7 7 2]
lucky? [3 4 3 4 2]text lucky?: function [streak [block!]][ set [width: total:] [3 7] also no forall streak [ slice: copy/part streak width all [slice/:width total == sum slice return yes] ] ]
map?[{},{}, ...]) and I need to know number of elements length? keys-of map perhaps. That will give you a number of key/value pairs.length? keys-of map perhaps. That will give you a number of key/value pairs.print response/data print type? response/data print length? keys-of response/data
data: [[366 "contracts" {contracts/Moskva/contract_Moskva_2015010100_2015020100_001/contract_1770707263715000001_18887516.xml} "Moskva"] [367 "contracts" {contracts/Moskva/contract_Moskva_2015010100_2015020100_001/contract_1770707263715000002_18887624.xml} "Moskva"] [365 "contracts" {contracts/Moskva/contract_Moskva_2015010100_2015020100_001/contract_1770700350615000003_18568535.xml} "Moskva"]]
map
1#(data [...]) map, with a single key/value pair.either create new scope?x: 1 r: 0 either x = 1 [ r: 6 ] [ r: 7 ] print r
0either?x: 1 r: 0 either x = 1 [ r: 6][ r: 7] print r works, check your format. either doesn't create a context>> x: 1
== 1
>> r: 0
== 0
>> either x = 1
*** Script Error: either is missing its true-blk argument
*** Where: either
*** Stack:
>> [
[ r: 6
[ ]
== [
r: 6
]
>> [
[ r: 7
[ ]
== [
r: 7
]
>>
>> print r
0either.>> x: 1 == 1 >> r: either x = 1 [6][7] == 6 >> x: 2 == 2 >> r: either x = 1 [6][7] == 7
>> x: 1 == 1 >> r: pick [6 7] x = 1 == 6 >> x: 2 == 2 >> r: pick [6 7] x = 1 == 7
>> x: 1 == 1 >> r: any [all [x = 1 6] 7] == 6 >> x: 2 == 2 >> r: any [all [x = 1 6] 7] == 7
>> x: 1 == 1 >> select reduce [true 6 false 7] x = 1 == 6 >> select reduce [true 6 false 7] x = 2 == 7
x: "hello" f: function[] [ x: copy x append x " world" print x ] f
x: copy x I thought it will create copy of global x but I am getting error:*** Script Error: copy does not allow none! for its value argumentx: copy system/words/xfunc will not make set-words local to function context, in your function's body:x: "hello"
f: func[] [
x: copy x
append x " world"
print x
]
ff: function[/extern x] [ ... ] would also work.x: "hello"
f: function ['word] [
s: copy get word
append s " world"
print s
]
f xa/2: "val1" a/10: "val2" a/1234: "val3"?x: 123 view compose [text (rejoin ["value: " to-string x]) button [x: 777]]
t: text and than to access to it from button, but I do not want to duplicate text theretext
x: "123"
view [
text with [text: rejoin ["value: " x]]
f: field "777" 40
button "Change" [change/part find/tail t: face/parent/pane/1/text ": " form x: f/data tail t]
]react is only work with widgets, not with regular code? react needs reactive source. x: "123" is not reactive source.view compose [
text with [text: rejoin ["value: " x]] react [
change/part find/tail face/text ": " form x: f/data tail face/text
] f: field "123"
]reactor! - see [docs](https://github.com/red/docs/blob/master/en/reactivity.adoc)view compose/deep [
clock: field rate 1 on-time [face/text: form now/time]
at 10x10 text 100 hidden react later [
if clock/data > (now/time + 5) [
face/visible?: yes face/text: "Time has come!" clock/rate: none
]
]
]set-key/get-key/.... You lose path syntax support that way, but could dialect it if you really wanted to. Now that we have maps, @9214's article will let you decide what's best for your use case. ; create a picture with random red pixels (takes a few seconds to create) bg: make image! 480x2400 repeat i 1152000 [bg/(i): random red] y: 1520 code: does [ if l = 500 [im/rate: none] ; stop after 500 iterations to prevent memory breakdown im/image: copy/part skip bg as-pair 0 y 480x480 ; scroll one line down y: y - 1 ] l: 0 view [im: image im1 rate 24 now on-time [do code l: l + 1 ]]
Red[ Needs: view ] ; create a picture with random red pixels (takes a few seconds to create) bg: make image! 480x2400 repeat i 1152000 [bg/(i): random red] xy: 0x0 drawBlk: compose [translate (xy) image bg] l: bg/size/y code: does [ l: l - 10 if l = 0 [im/rate: none] xy/y: to integer! negate l / bg/size/y * (max 0 bg/size/y - im/size/y) print xy drawBlk/2: xy ] view [im: image 480x480 bg rate 24 on-time [code] do [im/draw: drawBlk] ]
Red[ Needs: view ] ; create a picture with random red pixels (takes a few seconds to create) bg: make image! 2400x2400 print rejoin ["Patience! Generating " form bg/size " image..."] repeat i bg/size/x * bg/size/y [bg/(i): random white] xy: 0x0 drawBlk: compose [translate (xy) image bg] l: bg/size/y c: bg/size/x inc: 1 scroll: does [ if r1/data [l: l - inc if l <= 0 [l: bg/size/y]] if r2/data [l: l + inc if l >= bg/size/y [l: 1]] if r3/data [c: c - inc if c = 0 [c: bg/size/x]] if r4/data [c: c + inc if c >= bg/size/x [c: 1]] ;--vertical scrolling if any [r1/data r2/data] [xy/y: to integer! negate l / bg/size/y * (max 0 bg/size/y - im/size/y)] ;--horizontal scrolling if any [r3/data r4/data] [xy/x: to integer! negate c / bg/size/x * (max 0 bg/size/x - im/size/x)] drawBlk/2: xy ] win: layout [ text 100 "Direction" r1: radio 60 "Down" [if face/data [l: bg/size/y]] r2: radio 60 "Up" [if face/data [l: 1]] r3: radio 60 "Right"[if face/data [c: bg/size/x]] r4: radio 60 "Left" [if face/data [c: 1]] pad 20x0 button "Quit" [Quit] return text 100 "Velocity" slider 100 [inc: 1 + to-integer face/data * 99 f/text: form inc] f: field 30 "1" button "Start" [im/rate: 24] button "Stop" [im/rate: none] return im: image 480x480 bg on-time [scroll] do [im/draw: drawBlk r1/data: true r2/data: r3/data: r4/data: false] ] view win
my-vocabulary: [
next: func [arg] [... any code... NEXT arg ...any code...]
prev: func [arg] [... any code... PREV arg ...any code...]
skip: func [arg] [... any code... SKIP arg ...any code...]
]NEXT/PREV/SKIP inside functions' body are bound to my-vocabulary but I don't want this, I need to bound them to the global system/words vocabulary.system/words/WORD but I do not want to use explicit paths, it should be implicit in the word binding.b: make object! [ skip: func [s [series!] value][skip s 4] next: func [s [series!]] bind [skip s 1] system/words] ]
system/words instead of the object. This is a way to change the default vocabulary to system/words for some or all the words of the function body of one or many object members.setto set function in object to global context?>> x: construct compose [x: (does [? x])]
== make object! [
x: func [][? x]
]
>> x/x
X is an object! with the following words and values:
x function! []set your function words to function values after creating the object, whatever seems best for your casetext
>> set x: construct [x:] does [?? x]
== func [][?? x]
>> x/x
x: make object! [
x: func [][?? x]
]>> x: construct [x:]
== make object! [
x: none
]>> construct [x: a b]
== make object! [
x: 'a
]x which is initialized to none.>> does [?? x] == func [][?? x]
set x: construct [x:] does [?? x]X in the object created by construct to the function func [][?? x]?X inside the function body is not bound, isn't it?read only, but support for write can be added easily). It doesn't contain any codepages, but grabs them from Wikipedia (tested with Windows-1250 and Windows-1252, grabber may need adjustments for other pages):; standard READ requires UTF-8 text, but IDNES is known not only for shitty news, but also for a shitty webpage
>> page: read http://idnes.cz
*** Access Error: invalid UTF-8 encoding: #{96207320}
*** Where: read
*** Stack:
; let's switch to codepage aware READ-AS
>> do %codepage.red
== func [...
>> page: read-as http://indes.cz 'Windows-1250
== {<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">^M^/<html xmlns="http://www.w3.org/1999/xhtml"...write-as support added. Characters missing in required codepage are encoded as zero byte.Red [] m: #() o: make object! [ name: copy "" list: copy [] ] a: copy o a/name: "A" a/list: [1 2] put m a/name a b: copy o b/name: "B" b/list: [3 4] put m b/name b ?? m save/all %data.txt m n: load %data.txt ?? n
>> put map: #() 'foo object [bar: 1]
== make object! [
bar: 1
]
>> map
== #(
foo: make object! [
bar: 1
]
)
>> save %test map
>> load %test
== #(
foo: make
object!: [
bar: 1
]
)make object! [...] turns into 3 separates values.>> put map: #() 'foo object [bar: 1]
== make object! [
bar: 1
]
>> save/as %test map 'redbin
>> load/as read/binary %test 'redbin
== #(
foo: make object! [
bar: 1
]
)>> put map: #() 'foo object [bar: 1]
== make object! [
bar: 1
]
>> save %test.redbin map
>> load %test.redbin
== #(
foo: make object! [
bar: 1
]
)wait, although I'm not sure if it will suit your needs.wait and periodically query files, which right now returns the last modification date.language:red ?site:github.com works on google and maybe bing>> x: make map! 0?{aa: false bb: false cc: false}w value instead of w as name:x: make map! 0 ww: [aa bb cc] foreach w ww [set 'x/w false]
w but I can't understand how to do it.text
>> m: #()
== #()
>> foreach w [a b c][m/:w: false]
== false
>> m
== #(
a: false
b: false
c: false
)stepwise](https://gitlab.com/hiiamboris/red-mezz-warehouse/-/tree/master) version.do %codepage.red page: read-as http://indes.cz 'Windows-1250 print page
on-deep-change*, see an example in "Object ownership system" chapter in https://www.red-lang.org/search/label/ownership[[a false] [b false] [c false]]l: [] foreach w [a b c][append l reduce [[w false]]] >> probe l [[w false] [w false] [w false]] == [[w false] [w false] [w false]]
falses are not logic values, instead they are word!sbitset!.a: make object! [mistake: none ok: none] and I wanted to get rid of the 'mistake.remove-words: func [ "Returns a copy of the object with the specified words removed." object [object!] words [word! block!] "The word, or words, to remove" /local spec ][ spec: body-of object foreach word compose [(words)] [ remove/part find/same/skip spec to set-word! word 2 2 ] make object! spec ]
remove-words o 'mistake. But you can't change the object in place.while *without* using a block for the condition argument... :)i: 2tags: [
["dd" "aa" "hh"]
["aa" "hh" "dd"]
["aa" "bb" "cc" "dd"]
]tags/i do not works. The task is move second element with next to get: tags: [
["dd" "aa" "hh"]
["hh" "dd"]
["aa" "bb" "cc" "dd"]
]tags/:i.>> if (first t) = needle [tags\:i: next tags\:i] *** Syntax Error: missing #"]" at "\:i: next tags\:i]"
pick tags i>> p: :print
== make native! [["Outputs a value followed by a newline"
value [any-type!]
]]
>> p "123"
123
>> p: 'print
== print
>> p "123"
== "123"p: 'print sets p to a word (a "symbol") print, not to a function to which we refer as print.p "123" expression is evaluated, p evaluates to print and "123" evaluates to itself. Since "123" was the last value in the expression, it then got returned as a result.reduce [p "123"] has the answer!p evaluates to print, print itself is not re-evaluated at the call site.>> p: 'print == print >> reduce [p "123"] == [print "123"] >> do reduce [p "123"] 123
[1 3 5]/2 doesn't work, is it something at the low level of Red, or it happens 'naturally'? I can't figure out when refinements apply or not (yet) [1 3 5]/2 is a syntactically invalid path. You can construct it at run-time though:>> as path! [[1 3 5] 2] == [1 3 5]/2
>> do as path! [[1 3 5] 2] *** Script Error: path must start with a word: 1 3 5/2 *** Where: do *** Stack:
none if indexing goes out of boundaries.>> franken: [path wut] == [path wut] >> as path! [franken /path] == franken//path >> do as path! [franken /path] == wut >> franken//path *** Syntax Error: (line 1) invalid path at franken//path *** Where: case *** Stack: load
/, or !, or ? and what meaning do they have. This context thing grows on you I guess paren!s acts as the training wheels in such cases. And then there are embedded DSLs (aka dialects) which, I would argue, improve the readability by a significant factor.>> do-events
data: [ regNum none price none lots [ lot [ code none ; I need to set none to 12345 ] ] ] data-walk: func[data] [ foreach [a b] data [ either (type? b) = block! [ print [a " is multiple"] data-walk b ] [ ; a is single if a = 'code [ print ["----> " a] b: "12345" ] ] ] ] data-walk data probe data
b: "123" would be setting none (b is the value of the tuple) to "123"? I've no idea what would try to do theredata/a: "123" says Script Error: cannot set none in path data/a:, which means that a is not evaluated, so you're trying to add to that /a path. What I don't know is why data can't be extended with new keys though.data/:a: "123" it had to work :). As I parse it is :a being the read-word!, and evaluating it to 'code, then the second : makes it a set-word! . data/:a is a good way to achieve what @bubnenkoff wants, just some corrections:b: "123" doesn't set none to "123", it changes value of word b from none to "123". And because there is no link between b and the original block, it's not very useful.:a is get-word!, not read-word! and the second : makes it set-path! as it's part of path!.data/code: "12345" which is the same as data/:a: "12345" because value of ais code.pair! (e.g. 2x3) with the float! support. Do you have any news on that. Can I expected it "soon" or was it just wishful thinking of somebody?data: [
regNum none
price none
lots [
lot [
code none ; I need to set none to 12345
some none
code none
]
]
price none
]
data-walk: func [data][
forall data [
either block? data/2 [
print [data/1 "is multiple"]
data-walk data/2
][
switch data/1 [
code [print "----> code" data/2: "12345"]
price [print "----> price" data/2: 54321]
]
]
data: next data
]
]3.141592653x2.7182818284).(x, y).pair! slot for two 64-bit floating-point values, so they are limited to 32-bit only.Internally, you also need to differentiate between pairs with integers and pairs with floats, but this can be done with a bit flag in the header.(x, y) looks like a paren! on the first sight. Some datatypes (vector!, function!, hash!, etc) don't have literal forms at all and can be constructed at run-time only.x(a b c) would have some similarity to pairs (eg 5x6) and Red uses the prefixing parens thing for map! literals. Commas feel a little strange at this point.(x, y, z) (aka point!) was chosen precisely because it mimics the human notation for coordinates.x() distinct from x () could open up a lot of lexical space for new literalsa/b/x()? :x(), 'x()? yx()? Also, this "stickiness" of words to series delimites is used quite a lot, e.g. in Red/System #define FOO(bar baz) ... is a conventional form for macros.X (a b c) means "run X function with (a b c)as an argument" or " evaluate X as type with (a b c) as an argument". One space could break your code... and you don't want it. Unless you want to do python like language (or hard to code language).1 + 1 vs 1 +1). For me, the biggest issue is the breaking change. As @9214 indicated, there's a lot of code that uses the form x(a b c) already.a/b/x()? :x(), 'x()? yx()? a/b/x() now means something different from a/b/x (). That's creates a difference (another bit of information), strictly increasing the space of possible combinations. Before x()_, x_(), and _x() were all equivalent. But with this change, you now have new meaning. _x() and x()_ would mean one thing. x_() would mean something else.a/b/x() "select from a/b, whatever it is, with key x()", or is it an entirely new lexical form that now needs to be supported (or not)? Is :x() a get-word! then paren!, or a get-point!, or neither of the two? What about @max()? Is that a ref! followed by paren!, or is it a @ma x()? http://min.max()? mad@max(), %file-x()?x you're throwing all the other literals into a morass of syntactical ambiguity.x(). I was more thinking that any word char (or group of word chars) prepended to () (or possibly other delimiters "", [], {}) would constitute a possible literal form. So y(), a(), abc-1() could all be possible (though not necessarily defined) literals.class Foo data-a = 1 fun-b = func [][data-a] end var f = Foo(42, func [a] [a * data-a]) f/fun-b(1) ; => 10
type Foo = a | b type Baz = a | b | c var qux : Foo qux = a
qux knows that it is the Foo type. > data: [ > regNum none > price none > lots [ > lot [ > code none ; I need to set none to 12345 > some none > code none > ] > ] > price none > ] > data-walk: func [data][ > forall data [ > either block? data/2 [ > print [data/1 "is multiple"] > data-walk data/2 > ][ > switch data/1 [ > code [print "----> code" data/2: "12345"] > price [print "----> price" data/2: 54321] > ] > ] > data: next data > ] > ] >
regNum: none instead of regNum none. Could you help me to adopt your example to this data structure:data: [
regNum: none
price: none
lots: [
lot: [
code: none ; I need to set none to 12345
some: none
code: none
]
]
price: none
]foreach [a b] data [] but not sure how to code should look like at assign part: data/2: "12345" (in your example)switch data/1 [
code: [print "----> code" data/2: "12345"]
price: [print "----> price" data/2: 54321]
]switch requires exact value, unlike for example find: find [a b c] quote b: == [b c]switch doesn't.>> switch "foo" ["FoO" [print "bar"]] bar
any-word!, switch behaviour is like find/case, but with string!, it's like plain find.switch should also get /case refinement to be more consistent with find.data: [ regNum: none maxPrice: none lots: [ number: none objects: [ name: none ] number: none objects: [ name: none ] ] ] foo: func [tag value] [ data-walk: func[data] [ probe data forall data [ either block? data/2 [ data-walk data/2 ] [ if equal? to-string data/1 to-string tag [ data/2: value ] ] ] ] data-walk data ] list: ["regNum" 777 maxPrice: 950 "number" "1" "number" "2" "name" "Apples" "name" "Bananas"] foreach [a b] list [foo a b] probe data
>> probe data
[
regNum: 777
maxPrice: 950
lots: [
number: "2"
objects: [
name: "Bananas"
]
number: "2"
objects: [
name: "Bananas"
]
]
]list and fill data. The problem that multiple sections will get latest value from list. I tried to move data with next after filling. But it's not work because I have recursion call.none and then exit the foo function.foo level) to know if you should reenter the function. Let's say changed? that would be initialy set to false. You would call data-walk from data-walk only when changed? is false and when you change the value, you also set changed? to true. That way you prevent second change.data: [ regNum: none maxPrice: none lots: [ number: none objects: [ name: none ] number: none objects: [ name: none ] ] ] foo: func [tag value] [ changed?: false data-walk: func[data] [ forall data [ either block? data/2 [ if (changed? = false) [ data-walk data/2 ] ] [ if equal? to-string data/1 to-string tag [ data/2: value changed?: true ] ] ] ] data-walk data ] list: ["regNum" 777 "maxPrice" 950 "number" "1" "number" "2" "name" "Apples" "name" "Bananas"] foreach [a b] list [foo a b] probe data
>> 21 / 5 == 4.2
>> 0 + $0 == $0.00 >> 0 + 0.0 == 0.0 >> 0 + 0% == 0.0 >> 0 + 1.2.3 == 1.2.3
data: [
regNum: none
maxPrice: none
lots: [
number: none
objects: [
name: none
]
number: none
objects: [
name: none
]
]
]
foo: func [tag value] [
data-walk: func[data] [
forall data [
either block? data/2 [
data-walk data/2
] [
if equal? to-string data/1 to-string tag [
if none? reduce data/2 [
data/2: value
break
]
]
]
]
]
data-walk data
]
list: ["regNum" 777 "maxPrice" 950 "number" "1" "number" "2" "name" "Apples" "name" "Bananas"]
foreach [a b] list [foo a b]
probe data[
regNum: 777
maxPrice: 950
lots: [
number: "1"
objects: [
name: "Apples"
]
number: "2"
objects: [
name: "Apples"
]
]
]name elementdata-walk: func[data tag value] [ forall data [ either block? data/2 [ if data-walk data/2 tag value [return true] ] [ all [ equal? to-string data/1 to-string tag 'none = data/2 return data/2: value ] ] data: next data false ] ] list: ["regNum" 777 "maxPrice" 950 "number" "1" "number" "2" "name" "Apples" "name" "Bananas"] foreach [a b] list [data-walk data a b]
data: [
regNum: none
maxPrice: none
lots: [
number: none
objects: [
name: none
]
number: none
objects: [
name: none
]
]
]
foo: func [tag value] [
; print ["tag: " tag " value: " value]
changed?: false
data-walk: func[data] [
forall data [
either block? data/2 [
data-walk data/2
] [
if equal? to-string data/1 to-string tag [
if (changed? = false)
[
if none? reduce data/2 [
data/2: value
changed?: true
print ["tag: " tag " value: " value]
break
]
]
]
]
]
]
data-walk data
]
list: ["regNum" 777 "maxPrice" 950 "number" "1" "number" "2" "name" "Apples" "name" "Bananas"]
foreach [a b] list [foo a b]
probe data>> probe data
[
regNum: 777
maxPrice: 950
lots: [
number: "1"
objects: [
name: "Apples"
]
number: "2"
objects: [
name: "Bananas"
]
]
]data: next data ?forall walks every value. In your case only every second value needs to be looked at. So there is no need to check the second value of the pair. data: next data skips the second value -- you already checked it with data/2 and possibly changed it.if test1 [
if test2 [
if test3 [
...
]]]all [test1 test2 test3 ...]unset 'word ?format: func [value delim /local v][collect/into [keep first value foreach v next value [keep delim keep v]] copy ""] >> format ["aa" "bb"] #"_" == "aa_bb"
mapping: function [transform][ function [reduce*] compose [ t: (:transform) ] ] a: mapping function [id][id] probe a :reduce*
*** Script Error: ?function? is missing its id argument *** Where: t *** Stack: probe a
t being called?>> a :reduce* *** Script Error: = does not allow unset for its reduce* argument *** Where: a *** Stack: a
reduce* is a function i wrote but didn't include.reduce*: function [ coll reducer /into buffer ][ accumulator: either into [buffer][to type? coll []] foreach i coll [ accumulator: reducer accumulator i ] accumulator ]
>> probe a :reduce* *** Script Error: ?function? is missing its id argument *** Where: = *** Stack: probe a
a: mapping function [id][id] you give as argument to mapping not a construction of the function but a constructed function. This function is assigned to t. When you call a, t is not assigned but called already.>> length? probe body-of :a
[
t: func [id][id]
]
== 2mapping, and for that give it unevaluated construction:mapping: function [transform][
function [reduce*] compose [
t: (:transform)
]
]
a: mapping [function [id][id]] ;<-- construction only
a :reduce
;== func [id][id]a, not evaluated>> length? probe body-of :a
[
t: function [id] [id]
]
== 4mapping? That would seem like a more natural interface.source but ended up with the same results.mapping: function [transform][
function [reduce*] compose/only [
t: function (spec-of :transform) (body-of :transform)
]
]
a: mapping function [id][id]
a :reduce*
;== func [id][id]do block:redraw: func [fig] [ repeat i 4 [ do [eq/:i/setPeakEQ params/:i/omega params/:i/gain 1.0] do [eq/:i/magnitude omega mag/:i] ] plot fig mag/1 + mag/2 + mag/3 + mag/4 ]
red -c eq.reddata: [ lot: [ number: none object: [ name: none ] ] ]
ar: [lot obj obj lot obj]obj second lot should have one obj. In result I want to get:data: [ lot: [ number: none obj: [ name: none ] obj: [ name: none ] ] lot: [ number: none obj: [ name: none ] ] ]
object: and in other obj:? Should object be replaced by obj? If yes, then how should application know this, if you don't want hardcoded names? data: [
lot: [
number: none
obj: [
name: none
]
]
]
walk-data: func [list /local out found] [
out: make block! 30
main: first list
rest: copy data/:main
foreach tag list [
either tag = main [
out: skip insert tail out copy/deep data -2
forall rest [rest/2: 0 rest: next rest]
][
if 1 < rest/:tag: rest/:tag + 1 [
append out/:main to-set-word tag
append/only out/:main case [
series? data/:main/:tag [copy data/:main/:tag]
true [data/:main/:tag]
]
new-line skip tail out/:main -2 true
]
]
]
head out
]
ar: [lot obj obj lot obj]
probe walk-data arar is top-level, rest are inside block. There are no hardcoded words in walk-datawalk-data: function [list][...links-list/data/(links-list/selected): before main-list/(links-list/selected) in edit-button action.links-list/data does not refresh itself when main-list changes. Alternatively to the above enforced renewal you can enforce the refreshing by adding links-list/data: links-list/data to the end of edit-button action.head out do? Same question with main: first list Returns a series at its first index.out if the index is else than at beginning.>> block: [1 2 3 4 5] == [1 2 3 4 5] >> block: skip block 2 == [3 4 5] >> block == [3 4 5] >> head block == [1 2 3 4 5]
index value with index? function:>> index? block == 3
out: skip (insert (tail out) (copy/deep data)) -2
append out that does the same) deep copy of data. Then you skip 2 values back. that's the minus.data into tail of out and hops 2 elements back from out tail, so as to be able to reference latest lot.main-list is the same data of links-list/data, in other words if they are the same block. list-data: [ "hello" "my" "beautiful" "world!" ] view [ data-list: text-list data list-data btn-edit: button "edit" 80x20 [ if all [data-list/selected data-list/selected > 0] [ view ask-input-panel: [ ipt-fld: field 150x20 [list-data/(data-list/selected): face/text unview ask-input-panel] with [text: list-data/(data-list/selected)] ] ] ] ]
out: make block! 30Who not 10 оr 50? Is there any logic?do https://tinyurl.com/y3lgh2vm >> rtx: rtd-layout [<b> "Rich text" </b>]() >> rtx/text = "Rich text" == true
view>> view [rtx: rich-text data [<b> "Rich text" </b>]] ;... >> rtx/text = "Rich text" == true
view [
below
rtx: rich-text "Rich text" with [data: [1x9 bold]]
return
fld: field "Rich text"
button "Compare" [txt/text: form rtx/text = fld/text]
txt: text ""
]>> view compose/deep [rt: rich-text draw [text 10x10 (rtx)]] ;... >> rt/draw/3/text = "Rich text" == true
rtd-layout and single-box rich-text create faces with plain text in their text facet. Multi-box rich-text contains this face in appropriate position in itsdraw facet.>view either immediately or when show command is used, depending on value of system/view/auto-sync?.translate, vertical slider changes y-value of matrix:view [
below pad 10x10
base 101x101 draw [
tr: translate 0x0
mx: matrix [1 0 0 1 0 0]
circle 0x0 10
]
pad -10x0
slider 120x20 [tr/2/x: to-integer 100 * face/data]
return
pad -8x0
slider 20x120 data 1.0 [mx/2/6: 1 - face/data * 100]
]append outappend too. As I needed to skip -2 from tail, either tail append out or insert tail out had to be used.data: [ lots: [ lot: [ number: none objs: [ obj: [ name: none ] obj: [ name: none ] ] ] ] ]
lot: [ number: none objs: [ ] ]
obj: [name: none code: none]
data2: []
foreach w [lots lot obj obj] [
if w = 'lots [append data2 [lots: []] ]
if w = 'lot [append data2/lots reduce [ lot]] ; problem is here
; ...
]
probe data2code: none?foreach loop. But you'll be in trouble with this when you intend to run it on repetitive structures, e.g. [lots lot obj obj lot obj] -- your first lot/objs will get the last obj too. Or e.g. should you add another lots, first one will get all the rest lots and objs. That's why I used skip earlier.foreach w [lots lot obj obj] [ switch w [ lots [append data2 copy/deep [lots: []] ] lot [append data2/lots reduce [quote lot: copy/deep lot]] obj [append data2/lots/lot/objs reduce [quote obj: copy obj]] ] ]
code: none?parse data2 rule: [any [ahead block! d: (new-line/skip first d true 2) into rule | skip]] probe data2
foreach w [lots lot obj obj lot obj lots lot] [ switch w [ lots [data2: skip tail append data2 copy/deep [lots: []] -2] lot [lots*: skip tail append data2/lots reduce [quote lot: copy/deep lot] -2] obj [append lots*/lot/objs reduce [quote obj: copy obj]] ] ] data2: head data2 parse data2 rule: [any [ahead block! d: (new-line/skip first d true 2) into rule | skip]] probe data2
lots as in data2, but you can delete it, it doesn't matter.-2 is because word is word and it's value (block in current case)?data2 was not wrapped. You can use new-line/skip data2: head data2 true 2 instead of data2: head data2 to wrap it.view [b: base 52.52.52 draw [box 0x0 100x100] "foo"]. b/text is not *very* visible. I want to make it more visible, like this: view [base 52.52.52 draw [box 0x0 100x100 fill-pen yellow box 30x30 50x50 text 30x30 "foo"]] but without doing it programmatically (calculating bounding box etc). I want something like face/text-background: true.view [p: panel 80x80 52.52.52 [b: box 30x20 yellow "foo"] do [center-face b]]
view [b: base 52.52.52 yellow "foo"]view [
base draw [
fill-pen red
box 0x0 50x100
]"50%"
]50%) I'm changing b/draw/5/x(progress bar). User can change color (fill-pen red), so while I guess I could change text's color (probably using fonts) I thought backgrounds looked better and where less problem-friendly.draw is drawn over face's text, so that your text will not be seen.panel-approach, using slider to simulate progress:view [
below
p: panel 81x81 52.52.52 draw [
fill-pen red box 0x0 0x80
] [b: box 30x20 yellow "0%"]
slider [
p/draw/5/x: to-integer 80 * face/data
b/text: form round face/data
]
do [center-face b]
]b: box 30x20 glass yellow bold "0%"comment function. The guidlines say the it is used for multiline comments in form of: comment {}. But the function source says it accepts any 'value, which technically means that you can use: comment (), comment [], comment "", or even comment 1 2 (1 gets ignored). This suggests it may have some other practical uses aside of pure multiline commenting, right?comment {} (would make life simpler), or all possible forms?comment [ ... ] may be usual practice.comment anyway. Trying to determine if such a block is a comment is beyond the abilities of syntax highlighters.comment {}. It's better than nothing and can be extended.comment as a comment. because comment is a regular Red function and that takes one regular Red value, and does nothing eith that value (but the function still evaluated). So syntax highlighter should treat the value as a value (block, integer, string, etc.)comment [] and comment {} together as an actual "comment", but in every other case, comment remains colored as a functiondraw is drawn over face's text, so that your text will not be seen.draw code. Never mind, thank you for reminding me this.panel-approach, using slider to simulate progress:> view [ > below > p: panel 81x81 52.52.52 draw [ > fill-pen red box 0x0 0x80 > ] [b: box 30x20 yellow "0%"] > slider [ > p/draw/5/x: to-integer 80 * face/data > b/text: form round face/data > ] > do [center-face b] > ] >
x to y only string!:x: ["Hello" foo] y: copy/types x string! probe y ; y become "Hello"
context [
copyable!: make typeset! [series! map! any-object!]
copyable?: func [e][find copyable! type? e]
is-type?: func [element [any-type!] type [datatype! typeset!]][case [
typeset? type [find type type? element]
datatype? type [type = type? element]
]]
set 'copy-types function [block [block! paren! hash!] types [datatype! typeset! block!]][
if block? types [types: make typeset! types]
collect [foreach e block [if is-type? e types [
either copyable? :e [keep/only copy/deep e][cause-error 'user 'message rejoin [e " cannot be copied!"]]
]]]
]
]>> a: copy-types b: ["string" [block [and another]] %file 1 2 <tag>] string! == ["string"] >> a: copy-types b: ["string" [block [and another]] %file 1 2 <tag>] any-string! == ["string" %file <tag>] >> a: copy-types b: ["string" [block [and another]] %file 1 2 <tag>] [block! string!] == ["string" [block [and another]]] >> a: copy-types b: ["string" [block [and another]] %file 1 2 <tag>] integer! *** User Error: 1 cannot be copied!
*data: [
lots: [
lot: [
number: none
objs: [
obj: [
name: none
]
]
]
]
]
;lot: [ number: none objs: [] ]
;obj: [name: none code: none]
copy-words: function[from] [
list-of-words: copy []
foreach [k v] from [
either block? v [
append list-of-words compose [(k) [] ]
] [
append list-of-words compose [(k) none ]
]
]
return list-of-words
]
data: []
foreach w [lots lot obj obj lot obj] [
switch w [
lots [data: skip tail append data copy/deep [lots: []] -2]
lot [lots: skip tail append data/lots reduce [quote lot: copy-words *data/lots/lot] -2]
obj [append lots/lot/objs reduce [quote obj: copy *data/lots/lot/objs/obj]]
]
]
data: head data
parse data rule: [any [ahead block! d: (new-line/skip first d true 2) into rule | skip]]
probe data*data insetead of commented fragment. Because I want to see complete data structureobj socopy-words that do shallow copy. But now I am getting 3 obj in every objs. And I can't understand reasonlot: [ number: none objs: [] ]
obj: [name: none code: none]
copy-words: function[from] [
unset 'list-of-words
list-of-words: copy []
foreach [k v] from [
either block? v [
append list-of-words compose [(k) [] ]
] [
append list-of-words compose [(k) none ]
]
]
return copy list-of-words
]
data: []
*data: [
lots: [
lot: [
number: none
objs: [
obj: [
name: none
]
]
]
]
]
foreach w [lots lot obj obj lot obj] [
switch w [
lots [data: skip tail append data copy/deep [lots: []] -2]
; lot [lots: skip tail append data/lots reduce [quote lot: copy/deep lot] -2]
lot [lots: skip tail append data/lots reduce [quote lot: copy-words lot] -2]
obj [append lots/lot/objs reduce [quote obj: copy obj]]
]
]
data: head data
parse data rule: [any [ahead block! d: (new-line/skip first d true 2) into rule | skip]]
probe datacopy/deep and copy/deep?copy []:either block? v [
append list-of-words reduce [k copy []] ;<-- hereobjs:. All three obj are appended to the same block.copy but did not understand exact place of problem so I tried even copy/deep. Thanks!compose (and reduce) make copies of their argument-block, series inside this block are not copied automatically. So, if you need inner series to be copied too, then you need to either insert copy inside block or copy/deep the whole block in addition to composing/reducing.>> x: "abc" a: reduce b: compose [(x) []] == ["abc" []] >> append b 1 == ["abc" [] 1] >> a == ["abc" []] ;a is copied (by `reduce`) from b, so appending of `1` to `b`does not affect it >> append b/2 2 == [2] >> a == ["abc" [2]] ;but series inside `b` is shared with `a`, so `2` appended to block in `b` appears in `a` too >> append a/1 #"d" == "abcd" >> b/1 == "abcd" ; and *vice versa*, string changed in `a` is the same that is in `b`
comment [] and comment {} together as an actual "comment", but in every other case, comment remains colored as a functioncomment with subsequent value was colored as a comment. Function's name is more than enough to deduce programmer's intention :-)a: ["aa" "bb" "cc"] view [field a]
to string! is not suitable for itmold/only.test.red file with follow content: Red []
foo: make map! [
a ["Hello"]
]
; ...a: append foo/a/1 " World"a. You can do it directly/implicitly:>> a: ["Hello"] view [f: field with [text: a/1] button "World" [append f/text " World!" probe a]] ["Hello World!"]
>> a: ["aa" "bb" "cc"] view [f: field with [text: mold/only a] button "Add b" [insert find f/text "bb" "b" probe a: f/data]] ["aa" "bbb" "cc"]
write/seek if you have the index. E.g.:save/header %foo [foo: make map! [a ["Hello"]]] []
i: index? find read %foo "Hello"
write/seek %foo "B" i - 1
read %foo
;== {Red [^/]^/^/foo: make map! [a ["Bello"]]}on-change event on my field that triger function and pass field ID:save-value: function[i] [
f: to word! rejoin ['f-tagname- i]
print f
] f-tagname-5f/text but it does not work. Or maybe I can get access on rejoin?f? It is local to save-value. You can access it inside func only. If you want to have it outside of func you can just return it. And print does not return it. print returns unset. Use probe instead to see it and return.get.>> f-tagname-1: "Value1" () >> f-tagname-1: "Value1" save-value: function [i][get to word! rejoin ['f-tagname- i]] () >> save-value 1 == "Value1"
set :)>> f-tagname-1: "Value1" () >> save-value: function [i value][set to word! rejoin ['f-tagname- i] value] () >> save-value 1 "Other value" () >> f-tagname-1 == "Other value"
ui-tags-list: collect [repeat i 20 [keep compose [
(to set-word! rejoin ['f-tagname- i]) field 220x25 hint "Tag Name" extra (i) on-change [save-value face/extra]
(to set-word! rejoin ['f-tagstack- i]) field 960x25 hint "Tag Stack" ; wip: ... on-change [save-value face/extra]
pad 0x-11
return] ] ] tags-tapes-map:foreach cell ui-tags-list [
if set-word? cell [
row: row + 1
fld-name: to-string cell
if not none? tags-tapes-map/lots/(row) [ ;
if find fld-name "f-tagname" [
face: get cell
face/text: mold tags-tapes-map/lots/(row)/1 ;
]
if find fld-name "f-tagstack" [
face: get cell
face/text: mold tags-tapes-map/lots/(row)/2 ;
]
]
]
] fields if they are was changed. So I need pass values from them back to tags-tapes-map.save-value: func[i] [
x: reduce to word! rejoin ['f-tagname- i]
print get in x 'text
; than I hope to set it back to tags-tapes-map
]tags-tapes-map?native!s.tags-tapes-map?#(
lots: [
["purchaseNumber" ["purchaseNumber"] false]
["docPublishDate" ["docPublishDate"] false]
["responsibleOrg_inn" ["purchaseResponsible" "responsibleOrg" "INN"] false]
; ...
]
)row: func [i][to-integer i - 1 / 2 + 1]
col: func [i][to-integer i - 1 % 2 + 1]
save-value: func [face][
print ["Changed value:" face/text]
print ["Original value:" mold/only tags-tapes-map/lots/(row face/extra)/(col face/extra)]
]
get-text: func [i][
tags-tapes-map/lots/(row i)/(col i)
]
tags-tapes-map: #(
lots: [
["purchaseNumber" ["purchaseNumber"] false]
["docPublishDate" ["docPublishDate"] false]
["responsibleOrg_inn" ["purchaseResponsible" "responsibleOrg" "INN"] false]
]
)
ui-tags-list: collect [
repeat i 3 [
keep probe compose/deep [
tagname extra (j: 2 * i - 1) with [text: (mold/only get-text j)]
tagstack extra (j: 2 * i) with [text: (mold/only get-text j)]
pad 0x-11
return
]
]
]
view compose [
style tagname: field 220x25 hint "Tag Name" on-change [save-value face]
style tagstack: field 960x25 hint "Stack Name" on-change [save-value face]
(ui-tags-list)
]j: 2 * i - 1? extra facet identifies it uniquely.print in save-value could use get-text face/extra; and get-text itself could include mold/only.row: func [i][to-integer i - 1 / 2 + 1]
col: func [i][i - 1 % 2 + 1]
save-value: func [face][
if face/text <> get-text face/extra [
print ["Changed value:" face/text]
print ["Original value:" get-text face/extra]
]
]
get-text: func [i][
mold/only tags-tapes-map/lots/(row i)/(col i)
]
tags-tapes-map: #(
lots: [
["purchaseNumber" ["purchaseNumber"] false]
["docPublishDate" ["docPublishDate"] false]
["responsibleOrg_inn" ["purchaseResponsible" "responsibleOrg" "INN"] false]
]
)
rows: length? tags-tapes-map/lots
view compose [
style tag: field on-created [face/text: get-text face/extra]
on-enter [save-value face]
on-unfocus [save-value face]
(collect [repeat i rows [keep compose/deep [
tag 220x25 extra (2 * i - 1)
tag 960x25 extra (2 * i)
pad 0x-11 return
]]])
]foldl implementation that I'm using as the base of it:foldl: function [ reducer coll /init initial ][ either init [accumulator: :initial c: coll][accumulator: coll/1 c: next coll] foreach i c [ accumulator: reducer :accumulator :i ] :accumulator ]
get-word! types around in order to deal with possible function! parameters. Is there a better way to do this?:initial, :accumulator and :i, unless you intend to have list of functions folded. Which is possible but then coll/1 should also be get-path. Another remark is that you might feed in ops as reducers, e.g. :+ or something, for which you'll need different ordering in foreach.coll/1 and ops%console.red on path ../source/red/. load and do?unset! words in a block and then to be able to selectively evaluate all syntax subtrees which do not contain unset! words. Symbolic programming for systems of equations and the like.do %solve.red set-values [a: none b: 5 c: 4 d: 3 e: 2 f: 1]() formula: [a = b + c / (d * e) - f]() solve/eval formula ;== 0.5 get-values ;== make object! [ ; a: 0.5 ; b: 5 ; c: 4 ; d: 3 ; e: 2 ; f: 1 ;] solve/eval/for formula b ;== 5.0 formula ;== [[b] [a + f * (d * e) - c]] set-value a 1 set-value f none () solve/eval/for formula f () get-values ;== make object! [ ; a: 1 ; b: 5.0 ; c: 4 ; d: 3 ; e: 2 ; f: 0.5 ;]
set-values [a: 5 b: none c: 3]() solve/eval/for f: [a = (b ** 2 + (c ** 2)) ** 0.5] b ;== 4.0 set-values [a: 5 b: 4 c: none]() solve/eval/for f c ;== 3.0 f ;== [[c] [a ** (1.0 / 0.5) - (b ** 2) ** (1.0 / 2)]]
compose? I need to display dict. Next code is work, but is there better way?m: #(a: 10% b: 15% c: 20%) view compose [area (to-string m)]
view is low impact, unless you're composing a huge amount of work that might slow the display (it would have to be a *lot* though). My general approach is to do the easy and obvious thing, that makes the code and intent clear. Only if I hit performance issues, or can see ahead of time that you'll get a 10x+ improvement where it counts do I worry about optimizing.m: #() m/a: 2% m/b: 4% m/c: 1% m/d: 3%
Map!s are unordered. If you need ordering, you a block and sort. Sort has a number of refinements that give you detailed control.take sort/reverse values-of m and than take key-value by it's result?sorted-set pseudotype that is able to do what you want:>> do %set.red
== func [/local value][
value: make sorted-set! []
value/data
]
>> s: make-sorted-set
== []
>> append s [a 5]
== [a 5]
>> append s [b 3]
== [b 3 a 5]
>> append s [c 1]
== [c 1 b 3 a 5]
>> append s [d 3]
== [c 1 b 3 d 3 a 5]
>> highest: copy/part tail s -2
== [a 5]
>> lowest: copy/part s 2
== [c 1]> >> 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] >
m: #()
m/a: 2%
m/b: 4%
m/c: 1%
m/d: 3%
sort/skip/reverse/compare sort/skip/reverse to-block m 2 2 2
== [
b: 4%
d: 3%
a: 2%
c: 1%
]sort/skip/compare/reverse to-block m 2 2
== [
b: 4%
d: 3%
a: 2%
c: 1%
]deflate? Here's a temporary link to the epub: https://we.tl/t-p33WBuneDNdecompress source to tell exactly what's the problem (I'm not an author).unzip on Linux doesn't show any errors. I may change the decompressor to ignore ivalid files and skip them, so you can get get at least the rest of archive.try to get rid of the 'faulty` files :)try is what I meant :-)set to set values within some context other than the global context?in.>> o: object [a: b: none]
== make object! [
a: none
b: none
]
>> set 'a 1
== 1
>> set in o 'b 2
== 2
>> a
== 1
>> b
*** Script Error: b has no value
*** Where: catch
*** Stack:
>> o
== make object! [
a: none
b: 2
]>> o: object [a: b: c: none]
== make object! [
a: none
b: none
c: none
]
>> oc: in o 'c
== c
>> set oc 'Whaaaat?
== Whaaaat?
>> o
== make object! [
a: none
b: none
c: 'Whaaaat?
]list: [
["aaa" "bbb" "ccc"]
["ddd" "ddd" "fff"]
]
append list [["ggg" "hhh" "jjj"]]
== [
["aaa" "bbb" "ccc"]
["ddd" "ddd" "fff"] ["ggg" "hhh" "jjj"]
]new-line bit, that can be set for each value. So, to make it short, there is a function new-line allowing you to set this bit:>> a: [1 2 3]
== [1 2 3]
>> new-line/all a true
== [
1
2
3
]new-line for detailed info.list: [ ["aaa" "bbb" "ccc"] ["ddd" "ddd" "fff"] ] append list [["ggg" "hhh" "jjj"]] new-line/all list true write %1.txt list
[
["aaa" "bbb" "ccc"]
["ddd" "ddd" "fff"]
["ggg" "hhh" "jjj"]
]append-nl: func [list appendum /only /skip n][ n: either n [0 - n][-1] either only [append/only list appendum][append list appendum] new-line (system/words/skip tail list n) true list ]
>> append-nl/only list ["ggg" "hhh" "jjj"]
== [
["aaa" "bbb" "ccc"]
["ddd" "ddd" "fff"]
["ggg" "hhh" "jjj"]
][aa bb cc] block of strings: ["aa" "bb" "cc"] ? mold\form not suitable for itmap-each yet. You can write your own function:form-each: func [b] [collect [forall b [keep form b/1]]] form-each [a b c] ;== ["a" "b" "c"]
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/only series fn first series] series ]
>> change-dir %\F\code\ == %/F/code/
>> change-dir %\F\code\ *** Access Error: cannot open: /C/red/\F\code\ *** Where: do *** Stack: change-dir cause-error
to-red-file if needed.>> change-dir %/d/temp/ == %/d/temp/ >> change-dir to-red-file %\d\temp\ == %/d/temp/
unset to free memory from object? Or is there any way to force GC to run? recyclerecycle free memory>> f: func [] [
[ print "aa"
[ return
[ print "bb"
[ ]
== func [][
print "aa"
return
print "bb"
]
>> f
aa
bbreturn takes valueprint "bb"exit if you don't want to return valueforeach xml list-of-files [ auto-processing do-events/no-wait ]
/no-wait to main view/no-wait [...] but it did not help.do-events/no-wait I see that it's trying to display sometimes result but most of time I am see only gray background instead of areachange-dir, etc. is very nice. normalize-dir that has a specific check for a forward slash which causes the extra path issue. But even if we change that, supporting backslashes means making changes everywhere to allow them, including telling users they need to check for them in their own funcs.logic! type, such as zero?, odd?, dir?, etc.. But there are exceptions to this, such as type?, size?, length?. Is there an overarching logic that ties these different uses together?zero?, odd?, dir?, type?, size?, length? etc. - represent nouns, although functions are (something like) verbs - that's why there's a ? at the end, adding a meaning of query. func? All set words inside it is public, but it can be cause of name conflicts. It's usage should bu minimized? > foreach xml list-of-files [ > auto-processing > do-events/no-wait > ] >
/no-wait to main view/no-wait [...] but it did not help.do-events/no-wait in code to get it look:foreach xml list-of-files [ do-events/no-wait file-name/text: xml do-events/no-wait auto-processing ; cpu bound operation do-events/no-wait ]
do-events/no-wait I am seeing gray zone instead of area with result.function(possibly with /extern ), otherwise use /local with func.field and wait for user press button. So I process should continue. But setting value to field will not cause stop of foreach looplist: next list unless tail? list [show-item first list]
hash! related functions? "hash!"f: func[] [ loop 500 [append t/data "aaa"] ] view [ t: text-list 200x400 data [] button [f] ]
[1 2 3 4] to get: [1 3 4]remove at [1 2 3 4] 2 and other head. :)head remove at [1 2 3 4] 2remove returns series at removed index, so you have to move to the head of series.show: func ['items] [
?? :items
]
breakpoint: func [msg] [
print ["breakpoint:" msg]
until [
print do cmd: ask "debug> "
cmd = ""
]
exit
]breakpoint where you want to "pause" execution. Execution is "paused", but you can still type in any red code while paused. This allows me to probe the value of variables or even change values while execution is paused. To continue with the execution, just do enter. I have a show helper function that I also use to probe variables while execution is paused. But Im just a beginner. I'm sure the veterans have more advanced tooling they've created.probe is your best friend during development and quick debugging.profile function: https://gist.github.com/greggirwin/908d44dc069ed84cf69f053e1308390d>> profile/show [[3 * 5] [multiply 3 5]] Time | Memory | Code 1.0x (107ns) | 452 | [3 * 5] 2.14x (228ns) | 404 | [multiply 3 5]
view but only in particular place? I need to display value in text but do not want to make all view compose (because I am not sure that I need it, or it's OK?)xml-count: 0 view compose [text (to-string xml-count)]
>> view [text compose [(to-string xml-count) ]] *** Script Error: VID - invalid syntax at: compose to-string xml-count
compose is not part of VID dialectdo-eventsdo-events is doing step inside event loop?compose [text (to-string xml-count) button (form my-count) ... ] is perfectly OK and fast enough, no need to optimize by sacrificing readability.parse, but there is still lot of stuff that is missing.parse commands. Once it was proven it's worth adding it, it was implemented natively.system/options/path.system/script/path in place yet, and how things are executed makes a difference. Red has the same issues as Rebol here, where flexibility can make some things trickier. We need a good reference and best-practice doc on this.red arg1 --arg2 # etc... red "file" arg1... red "file" "arg1 arg2"
do/args?Red [File: %test.red] print what-dir print system/options/path
>> do %../test.red /home/isheh/ /home/isheh/
bash @"%~dp0exe/red-app.exe" --cli "%~dp0scripts.red"
Red [File: %test.red] have any programmatic meaning or difference vs do %test.red? Right now I've designed my script to conditionally import the code . . . but perhaps I should actually make sure to only do that once instead of multiple times 😅do %config.red because of this, so I did do read %config.red. That ended up working nicely. So the question is, am I going about this right, learning common approaches in Red correctly? do (a facade for the Red interpreted) or with a dialect, such as Parse or View.do is smart enough and loads the string that read returns before interpreting it. You could also write do load %config.red, which amounts to the same thing.system/script/header, but that's TBD. In the meantime, it might be better to construct a dedicated object from the header block (which, like anything else, is just a passive data), that way all the configuration options are localized and can be applied to specific parts of your script, e.g. with bind.>> script: [date + 10]
== [date + 10]
>> date: 10-10-10
== 10-Oct-2010
>> config: context second load %../test.red
== make object! [
File: %test.red
Date: 28-Sep-2020
Author: @9214
]
>> do script
== 20-Oct-2010
>> do bind script config
== 8-Oct-2020
>> date
== 10-Oct-2010>> script: object [foo: 0]
== make object! [
foo: 0
]
>> config: [set 'foo 6 * 7]
== [set 'foo 6 * 7]
>> do bind config script
== 42
>> script
== make object! [
foo: 42
]do is like eval in some other langs, and you don't want to use it on untrusted data. But load is safe, and (without worrying about bind), you can use construct to make objects without evaluating their specs, which makes it safer as well.reduce load ... then? If so - then there must be a fundamental difference between doing and reduceing, right? Only other way I can think of getting around untrusted data is I've seen something called "use" which I'm guessing allows context to be more specific? Or I guess I'd just have to parse the data haha. Thanks, Gregg! do evaluates and returns the result of the last expression (if any), reduce evaluates and retains the result of every expression. They both rely on Red interpreter: do, by design, invokes interpreter at runtime (which sometimes helps to bypass AOT compiler limitations), but IIRC reduce's body, if it's a block!, is statically compiled.>> do [add 1 2 3 * 4] == 12 >> reduce [add 1 2 3 * 4] == [3 12]
do, are Turing-complete and allow for the possibility of arbitrary code execution, and some (notably dialects) are completely harmless no matter what you feed them. Rebol had a special [Secure](http://www.rebol.com/r3/docs/functions/secure.html) dialect for sandboxing, Red plans to expand on it at some point.use is an equivalent of let in other languages, it introduces a throw-away "local scope" to evaluate a piece of code that contains "variables". Red doesn't have it by default (and Red/System has, OTOH with a bit different semantics in mind), but it's a very common idiom.data to object with foreach loop (the would be some processing inside):o: object [] data: [id: 1 name: "foo"] foreach [k v] data [ ; print [k v] append o [k v] ]
Script Error: = does not allow object for its series argument
object data?object! is not a series and so you cannot append anything to it. Moreso (and assuming that o is, say, a block!), you append [k v] literally, i.e. it should rather be reduce [k v], or even repend o [k v].lots array instead of map? o: object [ id: 1 price: 777 lots: object [obj: object [a: 1 b: 2 c: 3]] ]
>> to-json o
== {{"id":1,"price":777,"lots":{"obj":{"a":1,"b":2,"c":3}}}}{{"id":1,"price":777,"lots":[{"obj":{"a":1,"b":2,"c":3}}]}}o: object [ id: 1 price: 777 lots: [object [obj: object [a: 1 b: 2 c: 3]] ] ]
block! :point_right: array; object! :point_right: map; you want a map within an array, so just combine the two.block! :point_right: array; object! :point_right: map; you want a map within an array, so just combine the two.block word?o: object [ id: 1 price: 777 lots: to-block object [obj: to-block object [a: 1 b: 2 c: 3]] ] to-json o
== {{"id":1,"price":777,"lots":["obj:",["a:",1,"b:",2,"c:",3]]}}obj: to-block object [a: 1 b: 2 c: 3]] is getting "obj:",["a:",1,"b:",2,"c:",3]] as result> {{"id":1,"price":777,"lots":[{"obj":{"a":1,"b":2,"c":3}}]}}
>>> to-json object [id: 1 price: 777 lots: reduce [object [obj: object [a: 1 b: 2 c: 3]]]]
== {{"id":1,"price":777,"lots":[{"obj":{"a":1,"b":2,"c":3}}]}}reduce is need here?[object [foo: 'bar]] and reduce [object [foo: 'bar]] blocks.foo. The request can be failed because server is down.bar. So what I should to return from foo? Dhow I throw exception or I can exit and someway check from bar?remove which can silently handle none! values, so find remove ... won't throw an error on you if the value isn't found. exit, though you can check for unset results. Unset is special and shouldn't be passed around like a regular value if you can avoid it.none! ever a meaningful result for a call? That depends on the call of course. If you are doing something like a query against a server, none may mean "not found" and can't be used to indicate failure. foo function?>> foo: func[url][try [read/info url]] == func [url][try [read/info url]] >> error? foo http://rebol.com == false >> error? foo http://rebol.abc == true
either all [ block? result: foo http://google.com result/1 < 400 ;<--- http response code check ][ ?? result/2 ?? result/3 ][ print "Read failed!" ]
make error! "some text" from function and than check it with error? than doing throw "some error"and that catching it. Am I right?try out of foo function as well.. hard to say how it looks in your real life.error how to extract text of it?text
>> ? (make error! "Error message")
make error! [
code: 800
type: 'user
id: 'message
arg1: "Error message"
arg2: none
arg3: none
near: none
where: none
stack: none
] is an error! value.do in do make error! "Empty response from server"?a: 1 f: func[] [ if a = 1 [ make error! "some error"] ] bar: func[] [ either error? f [print "there was an error"] [print "all ok"] ] bar
print "1111" if none? res [make error! "Empty response from server"] print "2222"
do make ...error! value and evaluating it are two different things.cause-error wrapper:>> cause-error 'user 'message "Error message" *** User Error: "Error message" *** Where: do *** Stack: cause-error
my-type!: object [ is-alive: true ] is-alive?: func [ obj [my-type!] ] [ obj/is-alive ]
object [...] so that it identifies a specific object a type from the table on creation - under some form of meta information date! values here? I thought they were passed by reference.Red[] n: 1-Oct-2020 print n ;=> 1-Oct-2020 n2: n n/day: 2 print n ;=> 2-Oct-2020 print n2 ;=> 1-Oct-2020 ;-- ???
n2date! chat, you can use typesets to learn a lot about related types. e.g. ? scalar!.? copy. You'll see things that can be copied, which you might think of as reference types, or mutable, but we don't use those terms in Red. Another typeset to look at is immediate!.date! values are self contained. That is, a date! doesn't reference a separate time! value for its time component.copy it), which looks like a call-by-reference to the uninitiated. Datatype having accessors doesn't mean that it's indirect (i.e. contains references).is-process-started-by-user? is-process-started-by-user or maybe something better?user-process? but it's up to you. If it's logic value, ending with question mark is a good idea.n itself is given a new value, rather than the date valuedate! value is added to it, and n gets re-set to this newly created value.n's value, which is a date!. [Here](https://github.com/red/red/blob/ba500c73bfc20952b1030ead14533f444faf4124/runtime/datatypes/date.reds#L964) is how such named accessors are resolved: name is simply mapped to a corresponding integer, and then a [gigantic switch](https://github.com/red/red/blob/ba500c73bfc20952b1030ead14533f444faf4124/runtime/datatypes/date.reds#L998) is dispatched on it. So:>> date: now/date == 2-Oct-2020 >> date/3 == 10 >> date/month == 10
cmd /c '"E:/Programmi/red.exe" "e:/Dati/color-slider.red"'
cmd /c "E:/Programmi/red.exe e:/Dati/color-slider.red"
Error: Server Error The server encountered a temporary error and could not complete your request. Please try again in 30 seconds.
date!, but rather falls under the general description of Red evaluation model.>> f: func [d [date!]] [d/day: 2 probe d none] == func [d [date!]][d/day: 2 probe d none] >> dd: now == 5-Oct-2020/20:49:32+02:00 >> f dd 2-Oct-2020/20:49:32+02:00 == none >> dd == 5-Oct-2020/20:49:32+02:00
copy, but copying as in memcpy.4 * 32 = 128 bits ATM.link-text: function [ text-tgt text-src ] [ text-tgt/text: text-src/text ]
== func [text-tgt text-src][text-tgt/text: text-src/text]
>> F1: make reactor! [ text: "F1" ]
== make object! [
text: "F1"
]
>> F2: make reactor! [ text: "F2" ]
== make object! [
text: "F2"
]
>> G1: make reactor! [ text: "G1" ]
== make object! [
text: "G1"
]
>> G2: make reactor! [ text: "G2" ]
== make object! [
text: "G2"
]
>> probe re-res: react/link :link-text [ F1 F2 ]
func [text-tgt text-src][text-tgt/text: text-src/text]
== func [text-tgt text-src][text-tgt/text: text-src/text]
>> probe re-res: react/link :link-text [ G1 G2 ]
func [text-tgt text-src][text-tgt/text: text-src/text]
== func [text-tgt text-src][text-tgt/text: text-src/text]
>> probe re-res: react/unlink :link-text [ G1 G2 ]
none
== nonestack/arguments + 1).f1 f2 and then g1 g2). Although in your case only f2 and g2 are reactive sources, so you don't need to unlink f1 with g1.integer!, date!, string!, block! or whatever else. Most of these 128 bits are metadata, some hold actual value (in case of scalar! types like integer) or pointer to actual value (for series! types). See actual layout of slot here https://github.com/red/red/blob/master/runtime/allocator.reds[1 "hello" 2-3-2023], Red allocates four slots: one for block! that holds other values, one for integer!, one for string! and one for date!. integer! and date! slots hold the value, block! and string! slots holt pointers to actual values as you won't fit that data in the slot.API Docs link needs to be updated? Currently it brings you to a white page with red text "Not here"date!, for example, is one of such specifications that results in the creation of a "box" in the "storage room" of RAM.unset!?object! or a function!. Context, in turn, contains symbol/value pairings. Specific value can be found if you know its index (which every any-word! value also holds alongside the binding). See [this](https://gitter.im/red/help?at=5accc5a91130fe3d36c0b7e9) ad-hoc diagram.system/words aka "global context". unset! is used to indicate that word is not set to any meaningful result of a computation, i.e. it's just a filler.unset!; I can't come up with any other one.word!s and get-word!s: the former "activate" whatever can be activated, the latter always treat everything passively by fetching values as-is.word!s always introduce at least 1 extra reference between themselves and the values they will evaluate to? Due to the evaluation model, there's no way to inline those values during compilation because then you lose the words which are an essential part of Red semantics.>> this: copy that: [a b c d e] == [a b c d e] >> set this move that tail that == [b c d e a] >> get 'a == b >> get get 'a == c >> get get get 'a == d >> get get get get 'a == e >> get get get get get 'a == a >> get get get get get get 'a == b ...
>> foo: has [bar][bar: 'qux do block] == func [/local bar][bar: 'qux do block] >> block: [get bind 'bar :foo] == [get bind 'bar :foo] >> do block ; FOO is not called, so there's no stack frame *** Script Error: context for bar is not available *** Where: get *** Stack: >> foo ; stack frame is laid down == qux
function! and object! which are not really that different between each other:foo: func [a b /bar c][a + b - c] foo/bar 1 2 3
do bind [a + b - c] context [a: 1 b: 2 bar: true c: 3]
function! provides "protocoling" in the form of argument's order and typing;function! provides optimization by keeping argument values off the heap and on the evaluation stack;function! provides niceties like embedded docstrings and different modes of argument passing.context-type! in turn is [just an enumeration](https://github.com/red/red/blob/5e2956277dc3d7f203e9dfd66edb597ad7fd585c/runtime/definitions.reds#L70). transcode (or load for that matter). Nothing is evaluated until you say so.load :)load doesn't seem to group the expressions into a traverable tree, which is what I'm after.do a block. It's like a second-order structure emerging from the arrangement of values. You can traverse this bunch of values whichever way you want.do is going to construct but not fully evaluate them.Red [
Title: "Group expressions"
Author: 9214
Date: 07-Jun-2018
]
group: function [
list [any-list!]
][
gather: [to paren! copy/part list mark]
also list until [
mark: preprocessor/fetch-next list
tail? list: change/part/only list do gather mark
]
]>> group [add 1 2 reverse [a b c]] == [(add 1 2) (reverse [a b c])]
>> group [add 1 2 + 3] == [(add 1 2 + 3)] ; rather than (add 1 (2 + 3))
op! would be very nice.fetch-next](https://github.com/red/red/blob/5e2956277dc3d7f203e9dfd66edb597ad7fd585c/utils/preprocessor.r#L161). So whatever it can do, this wrapper can do also.>> group [add 1 add 2 3] == [(add 1 add 2 3)]
function! values, not block! values. So, you let the interpreter do as much work as possible beforehand (kind of a super-powered pre-processor), then compile a "main" function that represents your program. Even then, the compiler needs to do a LOT of static analysis to be useful.unset! word. Any nested blocks where mini-dialects might be lurking, I will simply not attempt to reduce (I think). view[] where\how I should to call it? I need to start it without any user-actionview [... do [...]]
append x body-of func/object [ additional code ]. Also noticed there's an "extend" (action? or function) word that might not have a finished implementation yet. I was also hoping perhaps I could "bind" the words from one object/context to another at some-point during run-time but that also seems to only be supported for context-onto-block for now. So what's the right way to create a namespace/object that can extend its number of accessible properties (paths) during runtime? I'm not trying to do something like some-word: make some-word [new things] or copy. >> sin 90.0 == 0.8939966636005579 >> clear body-of :sin == [] >> sin 90.0 == 0.8939966636005579 ; no change, even though the body is empty
do [...] work for view unless it's supported? Silly metext
>> clear body-of :math
== []
>> math [1 + 2 * 3]
== 7
... in another session ...
>> math: func spec-of :math body-of :math ; reconstruction
== func ["Evaluates expression using math precedence rules"
datum [block! paren!] "Expressi...
>> insert body-of :math bind [print ["Math evaluates" datum]] :math
== [print ["Math evaluates" datum]
order: ['** ['* | quote / | quote % | quote //]]
in...
>> math [1 + 2 * 3]
Math evaluates 1 + 2 * 3
== 7bind a function's body with an object then>> foo: does bind [a: a + 1] context [a: 0]
== func [][a: a + 1]
>> foo
== 1
>> foo
== 2
>> foo
== 3
>> ? (context? first body-of :foo)
a integer! 3do in this case is a VID keyword; there's also support for embedded expressions for certain facets:view [text data 1 + 2 * 3]
>> foo: 0 bar: does [foo: foo + 1] == func [][foo: foo + 1] >> bar bar bar == 3 >> foo == 3 >> bind body-of :bar context [foo: -3] == [foo: foo + 1] >> bar bar bar == 0 >> foo == 3 >> get in context? first body-of :bar 'foo == 0
block!, but can be constructed from the two halves that constitute object's context, which is a list of symbol and a list of associated values. This is what body-of called on object! [does](https://github.com/red/red/blob/5e2956277dc3d7f203e9dfd66edb597ad7fd585c/runtime/datatypes/object.reds#L1088) by the way. You can do whatever you want with it, but it won't reflect onto the object's state.system/words) is a default one for that. Each words that gets introduced appears in it first, even if it is never used afterwards.module/functionality/refinement x y z. So if I wanted the user to opt-out of writing the module name and use it like some functions are available globally (I guess system/words?), what would be the idiomatic approach? I'm thinking anyone here would really just do something like foreach word in words-of x [ set . . . . ]? set/any bind words-of x system/words values-of x should be enough, but that would export absolutely everything, which defies the purpose of a module.module/public-words to be used with that would be a nice-to-include*exports though.help math. Otherwise... you're going into one deep rabbit hole. :)unset! words (and any expressions which contain them). Otherwise, I'm wanting to maintain the same red semantics that you have with do. I don't see any way to do this without producing an AST.group function, but to selectively reduce expressions with no unset! words.a: 1000 symbolic-reduce [a + x + 2 * a] == [((1000 + x) + 2000)]
preprocessor/fetch-next as doing static analysis. Surely it takes live values into account? scalar! values get substituted, but e.g. op!s are not. What if + is not set to an op!? What if something that doesn't look like + is set to addition op!? What if left and right arguments both look like +? Etc, etc.preprocessor/fetch-next is looking up the value of words that it encounters in the relevant context, words that may have been set by the program while it runs. So the analysis is static with respect to the block but not with respect to the entire program. I suppose I’m more accustomed to the idea of static analysis being something that happens before the program runs. Though with the way Red works, that isn’t a useful model.>> to-integer "2410525241" *** Script Error: cannot MAKE/TO integer! from: "2410525241"
>> to-float "2410525241" == 2410525241.0
>> to-integer to-float "2410525241" *** Script Error: integer overflow/underflow *** Where: to *** Stack: to-integer
app.red and foo.red in app.red I am doing do load %foo.red. After compiling with red.exe -c app.red I got app.exe with external dependence to foo.red. Is there any way to inline (put in) all context from foo to app.red to get only one file?#include %foo.redfunc like:f: func[] [some-value: "123"]
some-value available outside. So it's work with REPL, but does not allow me to compile app because compiler find variables before they are declared.some-value: none
func like:> f: func[] [some-value: "123"] >
some-value available outside. So it's work with REPL, but does not allow me to compile app because compiler find variables before they are declared.> some-value: none >
view or parse) and should not be tampered with.math is a dialect as a small evaluator, parse is dialect as a DSL.-e) to get interpreted behavior and a single standalone EXE. Unless you're doing heavy math, like in the mandelbrot demo, you likely won't see much change in performance. It would be good to have an article that highlights when compilation makes a difference, because people think everything will go faster when a) it won't, and b) it only matters in special cases. The key, of course, is knowing what parts of your code are slow, which is where profiling tools will help. Then you think next about the algorithms used, and what you might do in R/S, because a better algo will give you massive gains, while general Red compilation won't. -e) to get interpreted behavior and a single standalone EXE. Unless you're doing heavy math, like in the mandelbrot demo, you likely won't see much change in performance. It would be good to have an article that highlights when compilation makes a difference, because people think everything will go faster when a) it won't, and b) it only matters in special cases. The key, of course, is knowing what parts of your code are slow, which is where profiling tools will help. Then you think next about the algorithms used, and what you might do in R/S, because a better algo will give you massive gains, while general Red compilation won't. -e syntax, because it's not compile app with: red.exe -e F:\code\app.redRed [] #include %foo.red view [panel foo]
Red [] foo: [button]
red.exe -r -e D:\test\app.redScript Error: view has no valueNeeds: View in the header.red -t windows -r file.red when having Red [ Needs: View ] in the header, works nicely! some-word: view [...] does not capture the window (probably gets unset). f: func [] [ some-data-that-need-be-accessible-everywhere: [] append some-data-that-need-be-accessible-everywhere "foo" ]
some-data-that-need-be-accessible-everywhere: [] ; near top of code ... ... ... f: func [] [ append some-data-that-need-be-accessible-everywhere "foo" ]
view to exit the GUI event loop (and then errors out because it returns unset). Use layout to get a hold of the tree of faces, which you then can reference and manipulate.view [do [self/offset: 0x0]]
func in real app? I mean that it;s very hard to control and prevent words overlay. Words declared at top at last placed near each otherview/no-wait gets around that :). Wonder if that's a bugfunc inside of a context/object for when you understand your context. I'm not sure you can get the same behavior using function which I believe only use words local to the functionself/xyzfunction [/local x] [x] to have different behavior than function [][x] within a contextfoo: func[] [x: 1] bar: func[] [x: 2]
foo: lfunc [data][
/local x: 1
parse data [copy /local value to end]
]func and function is that the latter tries to be smart and collects all set-word!s and words of iterators for you in a /local list.context [ . . . . context[ func [] [ words ] ] ] ] Is this not what I described?> foo: func[] [x: 1] > bar: func[] [x: 2] >
foo: func[] [x: 1] bar: func[] [x: true]
a: context [x: y: none] b: context [c: a] d: context [e: a] a/x: b a/y: d
a is "child" of b and d and "parent" to both of them.a are whatever was known at the time of writing until otherwise redefined . . . words are "scoped" at all times? I am of the impression that when you write them like this they are "initially" scoped to what is known when written or "realized", but after that there's no more "scoping" appliedwords in your example>> catch [context [foo: 1 context [bar: 2 qux: does [throw reduce [foo bar]] qux]]] == [1 2]
func?view/options [button "OK"] [offset: 10x10]>> cutlery: [spoon spoon spoon spoon] == [spoon spoon spoon spoon] >> set cutlery 'spoon == spoon >> print cutlery spoon spoon spoon spoon >> phrase: split "There is no spoon" space == ["There" "is" "no" "spoon"] >> forall cutlery [bind cutlery context [spoon: take phrase]] == [spoon] >> cutlery == [spoon spoon spoon spoon] >> print cutlery There is no spoon
[spoon spoon spoon spoon], those aren't evaluated. However, putting that _specific_ block inside of context block or func [...] block - and there's nothing else wrapping it, spoon spoon spoon spoon will evaluate to whatever a single "spoon" is . . . no? spoon.forall.>> forall cutlery [print head bind cutlery context [spoon: take phrase]] There There There There There is is is There is no no There is no spoon
word → object / function → context | | • symbol • symbols • index • values
; We can omit the catch in an example, as `catch/throw` isn't ; needed to understand binding. catch [ context [ ; Red creates a context, an anonymous one foo: 1 ; and binds set-words in the spec to it. ; Since context can't grow, it has to find ; all the set-words first. context [ ; But what happens here? We have another ; anonymous context, so the "outer" context ; doesn't have a reference to it. bar: 2 ; And words in its spec are bound to it. ; But how does the body of `qux` know the ; context of `foo`? It doesn't. `Foo` knows. ... qux: does [throw reduce [foo bar]] qux ] ] ]
context grabs the provided block and traverses it in search of set-word!s, but only at the top level. It founds only foo: and extends its list of symbols with it, filling associated value with unset. The context is created, and the block is bound to it (and so is the content of the nested block), then evaluated.foo is set to 1, and the nested context kicks in, repeating the operation described above. This sepearate (N.B.) newly created context has bar and qux as its symbols, again pre-filled with unset. Block is evaluated...bar is set to 2, and qux is set to the result of evaluation of does, which creates a function. Within function's body, throw and reduce are bound to a global context, foo is bound by the operation of top-level context to one context, and bar is bound by the nested context to another context. does itself creates an empty context because that's what it does (no pun intended).qux calls that function, which throws the reduced block up the call stack, and gives you [1 2].-------------------------------------------+
| |
+-------+ v
lots [data2: skip tail append data2 copy/deep [lots: []] -2](copy/deep [lots: []])
(append data2 (copy/deep [lots: []]))
(tail (append data2 (copy/deep [lots: []])))
(skip (tail (append data2 (copy/deep [lots: []]))) -2)
lots [data2: (skip (tail (append data2 (copy/deep [lots: []]))) -2)]+---------------------------------------------+
| +------------------------------------+ |
| | +-------------------------------+ |
| | | +------------------+ |
lots [data2: skip tail append data2 copy/deep [lots: []] -2]+-----+-------------------+------------------------+
v | +---------------+--------------------+ |
lots [data2: skip tail append data2 copy/deep [lots: []] -2]tail? lots [] to data2, this needs to be first lots you see in data2 otherwise things will be appended not to the latest lots but to first one. Because if you don't skip back from tail then you'll see other lots before the last one. This matters only if you append several lots of course.data: [ lots: [ lot: [ name: "foo" ] ] ]
[lots lot name]>> to-path [lots lot name] == lots/lot/name
data? I need: data/lots/lot/name
data and block [lots lot name] to single pathto path! [data lots lot name]? Or append to path! 'data [lots lot name]. Path is a series, so the same set of familiar operations applies to it.[]a/b/c: []to-set-path [a b c] == a/b/c:
set to-set-path [a b c] [] but it's do not workput a/b 'c [], do reduce [to set-path! [a b c] []], set 'a/b/c [], set to set-path! [a b c] [] (which actually works in the latest version).[]datadata: [] append data set to set-path! [a b c] []
[a/b/c: []] into an empty block?a.>> a: [b [c none]] == [b [c none]] >> set to set-path! [a b c] [] == [] >> a == [b [c []]]
[a/b/c: []] into an empty block?[a b c]). I need so make them set path with value and then to add in another empty blockexe compiled with -c -e and be sure that there were no errors with shared resources like some global vars?a.text > >> a: [b [c none]] > == [b [c none]] > >> set to set-path! [a b c] [] > == [] > >> a > == [b [c []]] >
a in path do not exists. But I did not understand how to create such path of un-existen elements to set-path! [a b c]. a can be created afterwards.>> unset 'a >> path: to path! [a b c] == a/b/c >> a: [b [c d]] == [b [c d]] >> set path 'q == q >> a == [b [c q]] >> a: [b [c x]] == [b [c x]] >> set path 'y == y >> a == [b [c y]]
a/b/c by itself doesn't care if either of its elements exists or not, just like [a b c] doesn't (and internally path! and block! are one and the same). It matters only when you try to evaluate the path, e.g. by calling set on it.set value to it?>> data: []
== []
>> append data reduce [to set-path! [a b c] []]
== [a/b/c: []]
>> new-line/skip data on 2
== [
a/b/c: []
]#system or routine code inside of the repl. Will/should this be supported? Should I make a wish on this? Otherwise I'm thinking I have to adapt the REPL (rebuild it with bindings) for when I want to use my own Red/System code? any-word! share the same structure and the same interface, ditto for any-path!. It makes sense, design-wise, to allow generic operations that work on one type of value to work on all the other ones. As for "why" — people find it more convenient; in case of set and get, the difference in datatype is most usually just a syntactic nuissance not worth of extra conversion. And, in general, semantic of a datatype is what you want to make out of it: in Red issue! is for preprocessor, in VID its for hex-encoded colors, in Parse they are just values used for direct matching.load-json, right? https://github.com/red/red/blob/master/environment/codecs/JSON.red>> write %file.json {{"a":1,"b":"ok"}}
>> load %file.json
== #(
a: 1
b: "ok"
)
>> load-json {{"a":1,"b":"ok"}}
== #(
a: 1
b: "ok"
)read/as, which according to help system, should allow reading via a codec?load/asload/as works fine, I use it all the timeread/asis just for an encoding?read/as to be honest and I doubt there is support for other encodings than UTF-8, I would be really surprised. But I need to look at source to be sure.>> read/as %delme.w1250 'Windows-1250 *** Internal Error: reserved for future use (or not yet implemented)
data: [ foo: [name: "aaa"] foo: [name: "bbb"] ] data/foo/name ; == "aaa"
data/2/name or foreach [name value] data [print value/name]forskipforskip: func ['word skip-num body][until [do bind body :word set :word skip get :word skip-num tail? get :word] set :word head get :word]
for iterator but in the end got neither? :-)> forskip: func ['word skip-num body][until [do bind body :word set :word skip get :word skip-num tail? get :word] set :word head get :word] >
forskip data 2 [something]. Anyway, having same set-word in your data structure does't make any sense, there is better way to do this.text data: [foo: [name: "a"] foo: [name: "b"]] data: [foo: [name: "a" name: "b"]] data: [foo: [name: ["a" "b"]]]
data: [
foo: [name: "aaa"]
foo: [name: "bbb"]
]
data: skip tail data -2
data/foo/name
;== "bbb"name from last foo.data: [
foo: [name: "aaa"]
foo: [name: "bbb"]
foo: [name: "ccc"]
foo: [name: "ddd"]
foo: [name: "eee"]
foo: [name: "fff"]
]data: [ [foo: [name: "aaa"]] [foo: [name: "bbb"]] ] == [[foo: [name: "aaa"]] [foo: [name: "bbb"]]] ? data/1 DATA/1 is a block! value. length: 2 [foo: [name: "aaa"]] ? data/2 DATA/2 is a block! value. length: 2 [foo: [name: "bbb"]] ? data/1/2 DATA/1/2 is a block! value. length: 2 [name: "aaa"] ? data/2/2 DATA/2/2 is a block! value. length: 2 [name: "bbb"]
? data/2/2/1 DATA/2/2/1 is a set-word! value: name: ? data/2/2/2 DATA/2/2/2 is a string! value: "bbb"
data/foo/1 ; bbb data/foo/2 ;aaa or data/foo ; [ [aaa] [bbb] ] ...set-word! for different blocks. You're right it's valid code (or data, to be precise), but just being valid doesn't mean it's right :)foo: you wouldn't loose any information (just the foo set-word that can be stored separately) and will gain simple accessible structure.[ word: 1 word: 2 word: 3] should be no different than . . .data: append append append [] bind [word] object [word: 1] bind [word] object [word: 2] bind [word] object [word: 3] foreach word reduce data [ print word ] ; --> 1 2 3
data/word == data/1 ; true data/word == data/2 ; true data/word == data/3 ; true (reduce data/word) == (reduce data/1 ) ; false (reduce data/word) == (reduce data/2) ; true (reduce data/word) == (reduce data/3) ; false
reduce data results in [1 2 3] but data/word resolved to the second word?>data/word uses word as a key to select what comes after it in data. Since the first value that matches this key is the first word, it select the second word, in all of the 3 cases.block/x as a form of query set-word would do haha. Edit -- I should have noticed that! I was so caught off about there being no set-words . . .select doesn't know anything about them. You simply need to write processors that understand your data model.forskip is handy at times, to be sure, and for is still a possibility which could subsume it as well. Forall is no more valuable IMO, but what I loved most about them in R2 was that forall was a special case of forskip and so was a one-liner that used it internally. I can't say if forall is a native now because of a specific use case in the code base where performance was needed, but I *think* the same thing could be done at the R/S level. Forall could then even be a one-liner mezz which calls the native forskip. There may be details that make that harder than I expect though.all-but-last: function[b] [ b: reverse b b: next b b: reverse b ] path: [aa/bb/cc] all-but-last [aa bb cc] ; work all-but-last path ; do not work I expected to get aa/bb
path is not even a path, but a block with a path..? Reversing one-element block is a no-op.set syntax and can't understand where is error:data: [ foo: [name: "aaa"] ] path: to-path [data foo] ; data/foo: tail data/foo ; this syntax works set reduce path tail reduce path
Script Error: invalid argument: "aaa"
remove find inp inp/4
remove find inp inp/6
inp: [5 3 8 1 2 1 12] probe remove at inp 6 ; == [12]
inp: [5 3 8 1 2 1 12] probe head remove at inp 6 ; == [5 3 8 1 2 12]
? remove in the console, and it's doc string describes its behavior.? While you're there, look at change and insert. Understanding series action/func behaviors helps enormously.read/write HTTP resources. Full I/O will come in 0.7 and then work on more protocols can begin in earnest.color-list: exclude extract load help-string tuple! 2 [glass set-color] Compilation Error: undefined word help-string
help-string is simply a console-only definition which compiler does not understand. [Here](https://gitter.im/red/help?at=5f1abb69cd7bed0e3789d6bb) is a workaround, you can also see other's solutions if you scroll the linked discussion. And besides — you are using an outdated build.save file: request-file/filter ["png" "*.png" "jpeg" "*.jpg" "gif" "*.gif"] draw (canvas/size) (canvas/draw) Compilation Error: undefined word draw
needs: View in your script's header, though on Windows here I get a different error for that. *** Compilation Error: Windows target requires View module (Needs: View in the header)about/debug in the console it will tell you what version you're running. moneydatatype or do I have to build it with a string?
>> USD$1'000'000 == USD$1000000.00
form will put separators for you](https://github.com/red/docs/blob/master/en/datatypes/money.adoc#formatting).>> form $1337 == "$1'337.00"
switch branch inside [console-edit](https://github.com/red/red/blob/df54dcdf65cdf9dd37590225ac51aaedcd065f9a/environment/console/CLI/input.red#L379). Sounds like a good first issue to me; GUI console should also be updated though.edit funcimage! is datatype for images, binary! can hold any binary data. image! has some metadata also, like image size, you can access individual pixels easily, etc.photo-album: object[
photo-id: integer!
photo-name: string!
photo-binary: binary!
]
OR
photo-album: object[
photo-id: integer!
photo-name: string!
photo-binary:image!
]photo-binary!. If it's image format Red can recognize, then image!. If it's raw data that you can't convert to an image!, then binary!words-of system/words returns me a lot of other elements. Also a way to get the words of VID dialect would be welcome.ins: collect [foreach word words-of system/words [if find [function! op! action! native!] type?/word get/any word [keep word]]]
x: words-of system/words forall x [ if value? first x [ if find [function! native! action! op! routine!] ty: to-word type? get first x [prin [first x " : " spec-of get first x] probe ty] ] ]
found? in Red. Why?Found? is nice for use with find (and easy to write if you want it), but it's also redundant in use, because you can say if find ..., where the only value found? adds is giving you a logic result which is helpful sometimes.forskip, which was not effectively replaced by planned fornor anything else.$ ./red --cli (console-2020-10-23-64733:2326): Gtk-WARNING **: 04:51:20.558: cannot open display: $ cat /etc/centos-release CentOS Linux release 7.8.2003 (Core)
--no-view option.forskip rarely, but some key old code of mine uses it, so I *do* miss it, and I've noted that forall is a special case of forskip so we get it almost for free and I personally don't see it as harmful. But forall is a native now, so it's more and deeper work to make that change. When they were mezzanines, it was easy. So comes the design question of whether forall needs the speed. Maybe @9214 or @hiiamboris have seen its use where the performance makes a difference.for out there, but the outcry hasn't been so great that it ever got pushed forward. It's good for people coming to Red, but I also think for other cases. Why I haven't pushed it myself has come to naming again and again. What do we call our loop constructs and how many do we need?format, CLI, etc. and there's just a lot to do. Bugs to fix, PRs to merge, 64-bit plans to make, blockchain work to prioritize, work that keeps us afloat, and more.foreach x [..] [..] is able to treat x as a word-literal instead of a value? I've created a function that accepts the same data types and the behavior of native foreach takes the word as-is, but a regular old func [word [word!.. ... results in type errors where foreach doesn't. >> my-foreach: func ['word [word!] series code] [?? word ?? series ?? code] == func ['word [word!] series code][?? word ?? series ?? code] >> my-foreach x [1 2 3] [blah blah] word: x series: [1 2 3] code: [blah blah]
money!, and also parse, which is critical. @tovim and others help with translations, which is also deeply appreciated. function! reference docs to include some more details that would be great.CALL rebol.exe myscript.r on a Rebol but it has not workedcall/show "rebol.exe file.r"quit and the consolle returns to the caller script. So, the caller one finds the file locked. I will investigate more on this topic.open is not supported on file!s in Red, yet, your file shouldn't be locked by Red. And write locks for a very short time, shouldn't be an issue, are you sure your Rebol script doesn't keep running in the background? Try also /wait with call.declare struct! syntax in the specification, but I can't get it to work >> s: declare struct! [i [integer!] b [byte!]] *** Script Error: declare has no value *** Where: s *** Stack: >> s!: alias struct! [i [integer!] b [byte!]] *** Script Error: alias has no value *** Where: s! *** Stack:
Red/System only?struct! in Red is not implemented yet, and will slightly differ in its semantics from a low-level counterpart.objects. I need to know from child who is it's parent. In my case I need to move have copy of number on name level.o: object [ number: 1 object [ name: "Apple" ] ]
o: object [ number: 1 object [ number: 1 name: "Apple" ] ]
o: object [ number: 1 object [ number: ../number ; link to parent name: "Apple" ] ]
self, e.g.:>> o: object [parent: self number: 1 c: object [number: parent/number name: "Apple"]]
== make object! [
parent: make object! [...]
number: 1
c: make object! [
number: 1
name: "Apple"
]...>> o: object [parent: self number: 1 set 'c object [number: parent/number name: "Apple"]]
== make object! [
parent: make object! [...]
number: 1
]
>> c
== make object! [
number: 1
name: "Apple"
]reactor:>> o: reactor [parent: self number: 1 set 'c object [number: is [parent/number] name: "Apple"]]
== make object! [
parent: make object! [...]
number: 1
]
>> o/number: 2
== 2
>> c
== make object! [
number: 2
name: "Apple"
]>> o: reactor [number: 1] c: object [number: is [o/number] name: "Apple"]
== make object! [
number: 1
name: "Apple"
]
>> o/number: 2
== 2
>> c
== make object! [
number: 2
name: "Apple"
]self, e.g.:> >> o: object [parent: self number: 1 c: object [number: parent/number name: "Apple"]] > == make object! [ > parent: make object! [...] > number: 1 > c: make object! [ > number: 1 > name: "Apple" > ]... >
> >> o: object [parent: self number: 1 set 'c object [number: parent/number name: "Apple"]] > == make object! [ > parent: make object! [...] > number: 1 > ] > >> c > == make object! [ > number: 1 > name: "Apple" > ] >
to-json on first example>> to-json o *** Internal Error: stack overflow
x: 2 object [x: x]
x: 2 object [x]
charset [#"A" - #"Z" #"a"-#"z"], but I want to cover all characters including with diacritics etc.>> x: 2 object compose [x: (x)]
== make object! [
x: 2
]object [
number: 1
object [
name: "Apple"
]
]object [
number: 1 ; !
object [
number: 1 ; ditto
name: "Apple"
]
]data and generate proper result. Or it's only way to write some iteratordata structure. All other tasks with your great help I did on itchar! is _not_ a part of it. OTOH, it largely depends on the specific problem that you are trying to solve. Password validation?object [ data: 1 print data ] and expect it to print 1a: object [ parent: return object [ set 'parent self num: 1 apple: object [ num: parent/num name: "manzana" ] ]]
incept: func [block][append/only insert/only block block block]
>> block: incept [we need to go deeper] == [[...] we need to go deeper [...]] >> block/1 == [[...] we need to go deeper [...]] >> block/1/7 == [[...] we need to go deeper [...]] >> block/1/7/1/7/7/7 == [[...] we need to go deeper [...]] >> block =? block/1/7/1/7/7/7/1/1/1 == true
object constructor. If you don't want evaluation, use construct.num: parent/num does not work here like it would in a "generic" block.object are peculiar, although necessary for what they actually are, compared to the far more general idea of a sequence. Further - until objects are extensible past creation, I'd say they're much less general than they _could_ be.example: object [ a: "hello" print example/a ]
`mypic: load %image.jpg connect the management object and run functions on it via path likemypic/size (to get size), mypic/resize 3000x2000, mypic/sharpen, mypic/blur 22. But if you want just to get or set the value you can use the standard single word Get/Set notation.eval-path function, which is how this works today. You can, of course, write your own system to do this with just a little extra syntax needed at the user level.as-obj: make op! func ['a b] [ set a object append copy [ set a self ] b ] parent: as-obj [ num: 1 child: as-obj [ num: parent/num name: "apple" ] ]
make object! [
num: 1
child: make object! [
num: 1
name: "apple"
]
]child actually becomes a member of the parent object. It's pretty interesting . . . And yes - I love Red :)eval-path function, which is how this works today. You can, of course, write your own system to do this with just a little extra syntax needed at the user level.;--------------------------------------------- SYMBOL | Value | Connected Object ;---------------------------------------------
mypic//sharpen notation (or any other usable one) to access the connected object. as-obj op is clever, but could lead to confusion with how as works since they share a base name. It's also a very general same with specific semantics. Then consider if we want to use ops with lit args and set-words on the left as standard. I like that there aren't many ops, they are generally clear by their distinct symbols, and are therefore more obvious in their effect on evaluation order.myval could be reserved to access the connected value from the connected object functions.struct by value from a function. I'm definately making some stupid mistake, that's why I need help.Red/System[]
Color!: alias struct! [
r [byte!]
g [byte!]
b [byte!]
a [byte!]
]
make-color: func [
r [integer!]
g [integer!]
b [integer!]
a [integer!]
return: [Color! value]
/local color
][
color: declare Color!
color/r: as byte! r
color/g: as byte! g
color/b: as byte! b
color/a: as byte! a
color
]
green: declare Color!
green: make-color 0 255 0 255
probe as integer! green/r
probe as integer! green/g
probe as integer! green/b
probe as integer! green/a
magenta: declare Color!
magenta: make-color 255 0 255 255
probe as integer! magenta/r
probe as integer! magenta/g
probe as integer! magenta/b
probe as integer! magenta/ared
RayColor!: alias struct! [
r [byte!]
g [byte!]
b [byte!]
a [byte!]
]
set-color: func [
color [RayColor!]
r g b a [integer!]
][
color/r: as-byte r
color/g: as-byte g
color/b: as-byte b
color/a: as-byte a
]
gray: declare RayColor! set-color gray 200 200 200 255make-color finished off and returned to the caller. What you are probing then is a random junk off the stack.Red [Note: "compile with -r -d flags"] #system [ color!: alias struct! [ r [byte!] g [byte!] b [byte!] a [byte!] ] make-color: func [ r [integer!] g [integer!] b [integer!] a [integer!] return: [color! value] /local color ][ color: declare Color! color/r: as byte! r color/g: as byte! g color/b: as byte! b color/a: as byte! a dump4 color color ] green: declare color! green: make-color 0 255 0 255 probe as integer! green/r probe as integer! green/g probe as integer! green/b probe as integer! green/a ]
Hex dump from: 004CE4ECh 004CE4EC: FF00FF00 00401003 0000004C 001D7CC0 .?.???@.L...?|?. 004CE4FC: 00401003 0000004C 001D7CC0 00401003 ??@.L...?|?.??@. 004CE50C: 0000004D 001D7CC0 00401003 0000004D M...?|?.??@.M... 004CE51C: 001D7CC0 00401003 0000004E 001D7CC0 ?|?.??@.N...?|?. 004CE52C: 00401003 0000004E 001D7CC0 00401003 ??@.N...?|?.??@. 004CE53C: 00000050 001D7CC0 00401003 00000050 P...?|?.??@.P... 004CE54C: 001D7CC0 00401003 00000052 001D7CC0 ?|?.??@.R...?|?. 004CE55C: 00401003 00000052 001D7CC0 00401003 ??@.R...?|?.??@. 0 0 0 0
FF00FF00 part? That's your struct.printout: function [
items
][
len: length? items
if not (len = 0) [
repeat i len [
case [
len = 1 [print items/1 return ""]
i < (len - 1) [prin rejoin [items/(i) ", "]]
if i = len [prin rejoin [items/(i - 1) " and " items/(i)]]
]
]
print []
]
]
printout ["1" "2" "3" "4" "5" "6"] ; 1, 2, 3, 4, 5 and 6
printout ["1" "2"] ; 1 and 2
printout ["1"] ; 1
printout [] ; no printoutprintout: func [series][
print rejoin collect [
forall series [
keep first series
keep case [
tail? next series [""]
tail? skip series 2 [" and "]
'else [", "]
]
]
]
]if empty? series [exit] or something like thattrue in the past but some people prefer 'else as it is probably more readable. You can put anything true-y there: >> case [make error! "error is fine" [print "ok"]] ok >> case [make logic! 'false [print "ok"]] ok >> case ['switch-to-this-branch-and-shoggoth-will-eat-your-soul [print "ok"]] ok
text enlist: function [list [block!]][ forall list [ this: make integer! head? list that: make integer! tail? next list flag: 1 + or~ this that << 1 prin [pick ["," "^/" " and" "just"] flag :list/1] ] ]
enlist ["1" "2" "3" "4" "5" "6"] enlist ["1" "2"] enlist ["1"] enlist []
"^/just".enlist2: function [series][ out: clear "" unless empty? series [ forall series [ append out first series append out case [ tail? next series [ "" ] tail? skip series 2 [" and "] 'else [ ", " ] ] ] ] copy out ]
just and none:enlist3: function [series][ if empty? series [print none exit] if tail? next series [prin "just "] forall series [ prin first series prin case [ tail? next series ["" ] tail? skip series 2 [" and "] 'else [", " ] ] ] prin lf ]
enlist4: function [series][ if empty? series [return copy "none"] out: clear "" if tail? next series [append out "just "] forall series [ append append out first series switch/default length? series [ 1 ["" ] 2 [" and "] ][ ", " ] ] copy out ]
enlist5: function [series][ if empty? series [return copy "none"] out: clear "" if tail? next series [append out "just "] copy forall series [ append append out series/1 switch/default length? series [ 1 ["" ] 2 [" and "] ][", "] ] ]
collect, I would not use it in functions where performance is appreciated.enlist: function [x] [
n: ["None" ["Just" x/1] [x/1 "And" x/2] [ loop l - 1 [ append x reduce [take x ","] ] "and" take x ] ]
print n/(min 4 1 + l: length? x)
]1 , 2 , and 3x in-place.append append bit. enlist: function [x] [
cases:[ "None" ["Just" x/1] [(
prin take x: copy x
loop len - 2 [prin["," take x]]
prin [" and" x/1]
)]]
print cases/(min 3 1 + len: length? x)
]
; tests
enlist x: [] loop 5 [ enlist append x length? x ]len is set and the calc to their index for dispatching is non-obvious. Comments would help. ;^)enlist: function [block] [
switch/default length? block [
0 [form none]
1 [rejoin ["just " first block]]
2 [rejoin ["" first block " and " last block]]
] [
output: copy ""
append output first block
last-value: take/last block
foreach value next block [
repend output [", " :value]
]
repend output [" and " :last-value]
]
]enlist: function [block] [
block: copy block
switch/default length? block [
0 [form none]
1 [rejoin ["just " first block]]
2 [rejoin ["" first block " and " last block]]
] [
output: copy ""
append output first block
last-value: take/last block
foreach value next block [
repend output [", " :value]
]
repend output [" and " :last-value]
]
]
b: [1 2 3]
enlist benlist: function [block] [
switch/default length? block [
0 [form none]
1 [rejoin ["just " first block]]
] [
output: clear ""
forall block [
append output block/1
if 2 = length? block [
return copy append append output " and " block/2
]
append output ", "
]
]
]delta-profile function in Red like in Rebol3 to play this game;-)dtenlist: function [block] [
switch/default length? block [
0 [form none]
1 [rejoin ["just " first block]]
;2 [rejoin ["" first block " and " last block]]
] [
output: copy ""
append output first block
last-value: last block
foreach value copy/part next block back tail block [
repend output [", " :value]
]
repend output [" and " :last-value]
]
]while for eg., or forall and breaking out before the tailenlist: function [x] [
print pick [
"None"
["Just" x/1]
[(repeat i l - 2[prin x/:i prin ", "] x/(l - 1)) "and" x/:l]
] (min 3 l: length? x)
]printout: func [items][ forall items [ switch/default length? items [ 0 [exit] 1 [print first items] 2 [print [first items "and" last items] exit] ] [prin first items prin ", "] ] ] printout ["1" "2" "3"] printout ["1" "2"] printout ["1"] printout []
l as a variable name, as it can look a lot like 1 or I, depending on the font.print "line 1.^/line2" ? Or how to print ^/? (which would be print "^^/"). . . l :) print "^(13)" ?^(#) syntax seems to print out based on character code in thereCRLF is built in as standard, or you can include just the CR, but print is a native, so not easy to patch. Easy to wrap though.#"^M" is CR.#"^(D)"? char! will show you all the built-in char values.enlist: function [block] [
switch/default length? block [
0 [form none]
1 [rejoin ["just " first block]]
][
block: reverse copy block
output: rejoin [block/1 " dna " block/2]
foreach value skip block 2 [repend output [" ," :value]]
reverse output
]
]
print enlist []
print enlist [1]
print enlist [1 2]
print enlist [1 2 3]
print enlist [1 2 3 4 5 6]reverse trick to make certain processing easier. The fact that this has a couple subtle gotchas makes it fun.insert. That would be another approach.enlist: func [list /local position element] [ parse list [ any [position: any-type! ( element: first position case [ head? position [prin [element]] last? position [print [" and" element]] true [prin ["," element]] ] ) ] ] ]
parse in place of foreach/forall for row-oriented structures. The advantage is you can easily parse and identify elements in complex field/row structures and execute code, either at element (field) level and/or row level. It's a nice journey.foralland with no /localenlist: func [list] [ forall list [ prin rejoin [ first list case [ (length? list) > 2 [", "] last? next list [" and "] last? list [lf] ] ] ] ] ;----------- TESTS ------------------------------------------ enlist ["1" "2" "3" "4" "5" "6"] ; 1, 2, 3, 4, 5 and 6 enlist ["1" "2"] ; 1 and 2 enlist ["1"] ; 1 enlist [] ; no printout
forall vs foreach vs repeat.LF to OFfor 2 times! )rejoin inside the loop, so it's a heavier on allocations.prinenlist: func [list] [
forall list [
prin first list
prin [
case [
(length? list) > 2 [", "]
last? next list [" and "]
last? list [lf]
]
]
]
]prin.forall:enlist: func [list][ switch/default length? list [ 0 ["None"] 1 [append "Just " list] ][ list: next list forall list [ list: insert list pick [" and " ", "] last? list ] rejoin head list ] ]
enlist: func [list][ case [ empty? list ["None"] single? list [append "Just " list] 'else [ list: next list rejoin head forall list [ list: insert list pick [" and " ", "] last? list ]]]]
>> enlist [%a %b %c] == %"a, b and c" >> enlist [<a> <b> <c>] == <a, <b> and <c>> >> enlist [#a #b #c] == "a, b and c" >> enlist [a b c] *** Script Error: a has no value
enlist: func [list][ switch/default length? list [ 0 ["None"] 1 [rejoin ["Just `" mold first list "`"]] ][ out: head clear at "`" 2 append out mold first list list: next list forall list [ append out pick ["` and `" "`, `"] last? list append out mold first list ] append out "`" ] ]
>> enlist [%a %b %c] == "`%a`, `%b` and `%c`" >> enlist [<a> <b> <c>] == "`<a>`, `<b>` and `<c>`" >> enlist [#a #b #c] == "`#a`, `#b` and `#c`" >> enlist [a b c] == "`a`, `b` and `c`"
foo!: alias struct! [bar [bar!]] bar!: alias struct! [foo [foo!]]
MYSQL_RES!: alias struct! [
row_count [integer!]
fields [integer!]... and inside the #import block and the dll block I get no errors. It happens when I try to declare the routine and use the MYSQL_RES! red_mysql_store_result: routine [
MYSQL [integer!]
return: [MYSQL_RES!]
/local
res [MYSQL_RES!]
][
res: mysql_store_result MYSQL
res
]mysql_res! datatype. Keep in mind that routine has spec of Red (like any other function definition) but body of Red/System.res content to some existing Red value, say, a block of integers, one per field (if they are all integer!s), or a raw binary! dump.Red [] #system [ foo!: alias struct! [ a [integer!] b [integer!] c [integer!] ] ] bar: routine [return: [binary!] /local foo][ foo: declare foo! foo/a: DEADBEEFh foo/b: FACEFEEDh foo/c: CAFEBABEh binary/load as byte-ptr! foo size? foo ] probe reverse bar ; little-endian order
$ example
#{CAFEBABEFACEFEEDDEADBEEF}set-word! was used to receive the handle of specified type, which was linked with internal resources.do function.set-word from inside the dialect to store results.enlist function, optimized for values without spaces :) enlist: func [list /local pos] [either pos: find/last form list { } [head replace pos { } { and }] [form list] ]
>> enlist ["1" "2" "3"]
== "1 2 and 3"
>> enlist ["1" "2"]
== "1 and 2"
>> enlist ["1"]
== "1"
>> enlist []
== ""
>> enlist ["1" "2" "3 or 4"]
== "1 2 3 or and 4" ;)mysql_store_result()
MYSQL_RES *mysql_store_result(MYSQL *mysql)typedef struct MYSQL_RES {
my_ulonglong row_count;
MYSQL_FIELD *fields;
struct MYSQL_DATA *data;
MYSQL_ROWS *data_cursor;
unsigned long *lengths; /* column lengths of current row */
MYSQL *handle; /* for unbuffered reads */
const struct MYSQL_METHODS *methods;
MYSQL_ROW row; /* If unbuffered read */
MYSQL_ROW current_row; /* buffer to current row */
struct MEM_ROOT *field_alloc;
unsigned int field_count, current_field;
bool eof; /* Used by mysql_fetch_row */
/* mysql_stmt_close() had to cancel this result */
bool unbuffered_fetch_cancelled;
enum enum_resultset_metadata metadata;
void *extension;
} MYSQL_RES;MYSQL_ROWS and peek at its content.mysql_res! struct), call mysql_fetch_row on it within a loop until it returns a null, and within the body of that loop iterate over row's fields and pretty-print them.mysql_store_result returns you a struct, or rather a pointer to it, which is the same. From when on you can do whatever you want with it.integer!, then what? There's nothing meaningful you can do with that value, except calling other MySQL function on it that expect mysql_res! as an argument.return: spec is malformed. Try:red_mysql_store_result: routine [ MYSQL [integer!] /local res [MYSQL_RES!] ][ res: mysql_store_result MYSQL res ]
return: [integer!] if you want. Although I'm not sure if res pointer will be automagically converted to it.return: [integer!] because the #import declares it as returning MYSQL_RES! and complains it's not the right return type. Can I make the assumption that I am now getting closer and if I could only figure out what to do with the pointer, I'm golden?as integer! res, or as integer! :res if that doesn't work.as integer! res, it says that I am attempting to change the type of variable: res from : [struct! [ ...] to: [integer!] so I think I'm getting what I want but again, I don't know what to do with a pointer to a struct assuming that is what is being returned. And why does the mysql_num_rows not work when it did before. Perhaps I was getting the correct result using the return: [integer!] in the place? @9214 Thanks for your help. Let me fool around with it a bit more and perhaps someone can chime in with some help with the struct! issue.c-string! to string! (assuming you have string data in the fields and not binary) and accruing them in a block.routine!'s task to connect them.if find "asdf" "a" [result: 'aaa] if find "asdf" "b" [result: 'bbb ] if find "asdf" "c" [result: 'ccc ] ; if not all [ .... ] [] ; some logic if not all are true
result: case [ find "asdf" "a" ['aaa] find "asdf" "b" ['aaa] find "asdf" "c" ['aaa] ] print result
foo: function [string][ index: find string charset "abc" either index [ result: select [#"a" 'aaa #"b" 'bbb #"c" 'ccc] index/1 ][ ; some logic if none were found ] ]
select [...] for switch index/1 [#"a" ['aaa] ...] if you want. I'd also inlined charset "abc" result instead of creating it on each function call.Switch matches values. What you want is case.switch is preferably when there is maybe one or more true conditions, while case when only one?switch evaluates the first true branch, so as case, but case/all evaluates all of them (if any).to-decimal "123.45" ;== 123.45 to-decimal 123 ;== 123 to-decimal [-123 45] ;== -1.23E+47 to-decimal [123 -45] ;== 1.23E-43 to-decimal -123.8 ;== -123.8 to-decimal 12.3 ;==12.3
decimal! type is not yet implemented in Red. number? checks typeset, but there are no to- functions, only to-. Same for to .to-decimal: function [v][
v: to-float v
w: to-integer v
either (remainder v w) = 0 [to-integer v][v]
]
; examples of using to-decimal
print to-decimal "123.45" ;== 123.45
print to-decimal "123" ;== 123
print to-decimal 123 ;== 123
print to-decimal 123.45 ;== 123.45to; it will either give you a value of a datatype that you asked for or error-out if conversion is impossible.to-decimal: func [value][
case [
number? value [value]
find number! scan value [transcode/one value]
'nope [make error! "can't do this"]
]
]numeric?: func [
"String to number" string
][
number? attempt [load string]]find number! scan value part does.print (to-decimal "2.3") + (to-decimal "3.7") ;== 6.0
syms: #(prod: * wedge: ^ dot: | ldot: _| rdot: |_ vee: &)
perp: func [ "Project component of v1 perpendicular to v2" v1 [vector! object!] "Vector or object projected" v2 [vector!] "Blade from which it is rejected" ][v1 ^ v2 * v2]
wedge). Its body is defined in [algebra.red](https://github.com/toomasv/GA/blob/master/algebra.red#L431). Defined as op on line [474](https://github.com/toomasv/GA/blob/master/algebra.red#L474). I have no problem with it, but @TimeSlip gets errors. We are both on W10. @TimeSlip, would you please paste here some errors you are getting. Any ideas?PROBE which is able to print words and log them. I have called this function PLOG: as *program log* PLOG/L value works passing as is, with no reduction. PLOG/LL name value as before but preceding the print with the provided namePLOG/L/G value and PLOG/LL/G name value get the value VALUE if the argument is a word.PLOG/R value and PLOG/RR name value, works as regular PROBE but you can provide a name which is printed.PLOG: func [
"Debug words, print their values "
/l "Print next the value and return it as is, with no reductions"
'l-value "The word name or any other text"
/ll "Print the provided string and the next value and return it as is, with no reductions"
ll-name "The word name or any other text"
'll-value "The value"
/g "If the argument is a WORD Performs a GET WORD. Also print the word name without having to provide it"
/r {Print a value but let Red/Rebol reduce it before passing a argument
Use this if you want to print functions result}
r-value "The value"
/rr {Print a value but let Red/Rebol reduce it before passing a argument
Use this if you want to print functions result
Prints the word name you provide
}
rr-name [String! word!] "The word name or any other text"
rr-value "The value"
/sep "Print a separator"
sep-text [String! word!] "The separator text"
/format ;To be implemented
style
out-data
pre-string
name
value
to-get
] [
if not value? 'plog-data [set 'plog-data copy []] ;For future use
pre-string: "LOG>>>"
case [
l [value: :l-value if all [g word? l-value] [to-get: true]]
ll [name: ll-name value: :ll-value if all [g word? ll-value] [to-get: true]]
r [value: :r-value]
rr [name: rr-name value: :rr-value]
]
case [
sep [print [pre-string "----------------" sep-text]]
true [
print [
pre-string
case [
name [rejoin [name " "]]
to-get [rejoin [value " "]]
true [rejoin ["xNO-NAMEx" " "]]
]
":-: "
mold out-data: either to-get [get value] [value]
]
]
]
out-data
];-------------- EXAMPLES --------------------------------- x: 22 plog/l x ;LOG>>> xNO-NAMEx :-: x x: 22 plog/ll 'x x ;LOG>>> x :-: x plog/ll "Value of argument X is:" x ;LOG>>> Value of argument X is: :-: x x: 33 plog/l/g x ;LOG>>> x :-: 33 x: 33 plog/ll/g 'x x ;LOG>>> x :-: 33 plog/ll/g "Value of argument X is:" x ;LOG>>> Value of argument X is: :-: 33 x: 44 plog/r x ;LOG>>> xNO-NAMEx :-: 44 x: 44 plog/rr 'x x ;LOG>>> x :-: 44 plog/rr "Value of argument X is:" x ;LOG>>> Value of argument X is: :-: 44
PLOG/L/G version with a function, get it, run it with the following arguments like PLOG/L/G func arg arg. To do this I have to get its arguments and reduce them inside my function. I need this to print the function name with the /g option , so I can remove the /r and /rr refinements. I see no option than putting the function and its arg inside a block and getting its first word and running the block with do . The whole syntax would be.PLOG/L/G [myfunc arg arg] decimal!, we plan to have an accurate decimal type, as money is but with more precision available. [my-func ...] ; reduced[:my-func] ; get['my-func ...] ; print name only["extra text" my-func] lit-word! args and a number of refinements. /selected value or it's better so save all object of drop-list and than load it's at start? drop-list is static or not. If it is, then saving selected index is enough.do %algebra.red *** Syntax Error: invalid issue! at "s: #(prod: * wedge: ^^ dot: | ldot: _| rd" *** Where: do *** Stack: do-file expand-directives load
>> s: #(prod: * wedge: ^ dot: | ldot: _|)
== #(
prod: *
wedge: ^
dot: |
ldot: _|
)
>> s/wedge
== ^
>> s/prod
== *
>> s/dot
== |^ is escape in strings/chars, but valid word. If we have to avoid some characters for esoteric reasons, it makes Red more fragile and unpredictable IMO.( ) [ ] , $ and few others, like, curiously, \. Does it make Red fragile and unpredictable? IMO no, I believe it's otherwise, it makes Red less fragile and more predictable. Is ^ such an important character to support it in words? I don't believe so. I may be wrong, e.g. 2 ^ 3 is of course simpler to write than 2 ** 3, but I can live with such limitation.^ is valid character for word and it is not clear why it causes problem in this case.s: #(prod: * wedge: ^ dot: | ldot: _|) *** Syntax Error: invalid issue! at "s: #(prod: * wedge: ^^ dot: | ldot: _|)" *** Where: do *** Stack: load
* and other symbols could not be used alone.block: [hello word]
block: [ hello word word some ];
block: [ hello [word] word [some] ]
block: [ hello: word word: some ]
map!? It's designed exactly for this use case.select/skip blk 2 for that, or a map! as @rebolek suggests. Enforcing key-value semantics on blocks is a bit more work, and many of us have written wrappers to do it. Maps solve it natively, but have other limitations as well.set-key: func [ ; put-key change-key?
{Updates a named value in a series of key-value pairs, appending the
key and value if it doesn't already exist; returns the series head.}
series [series!]
key
value
/local pos
][
either pos: find/only/skip series key 2 [
head change/only next pos value
][
repend series [:key :value]
]
]
get-key: func [ ; select-key ?
{Gets a named value in a series of key-value pairs, or NONE if the
key doesn't already exist.}
series [series!]
key
][
; Auto-create a "slot" for the key
if not find/only/skip series key 2 [repend series [:key none]]
; Have to get the first item, because /skip causes SELECT to
; return a block.
first select/only/skip series key 2
]
has-key?: func [ ; found-key?
{Returns true if key exists in the series of key-value pairs; false otherwise}
series [series!]
key
][
found? find/only/skip series key 2
]
remove-key: func [
{Removes a named value in a series of key-value pairs, or NONE if the
key doesn't already exist.}
series [series!]
key
/local res
][
; What should this func return? REMOVE result, series head, the value
; at the key, or item removed--key+value?
res: get-key series key
remove/part find/only/skip series key 2 2
:res
]
incr-key: func [
{Increments a named value in a series of key-value pairs, appending the
key and value if it doesn't already exist; returns the series head.}
series [series!]
key
][
set-key series key add 1 any [get-key series key 0]
]incr-receive function.build-buttons: func [idx [integer!] b-lab [string!] b-val [integer!]][ the-set-word: rejoin ["a" idx "-r" b-lab] the-btn-word: rejoin ["btn-r" b-lab] ?? the-set-word ?? the-btn-word append stats-layout compose[ (to set-word! the-set-word) ; the reference to the button (to word! the-btn-word) [incr-receive idx b-val] ; assign to the set-word, the appropriate button style ] ]
*** Script Error: context for idx is not available *** Where: act *** Stack: do-file view do-events do-actor do-safe
incr-receive 10 3
incr-receive: func[inc-idx inc-scr][
idx word in [incr-receive idx b-val] is bound to a context of build-buttons function, ditto b-val; when you compose and append your result, this block becomes a part of the layout that you form, and so is idx word, which is _still_ bound to a context of the function. But once function has finished evaluation and returned to the caller, its context disappears. Hence the error message: idx no longer has any value associated with it.append stats-layout compose/deep [
(to set-word! the-set-word) ; the reference to the button
(to word! the-btn-word) [incr-receive (idx) (b-val)] ; assign to the set-word, the appropriate button style
]idx and b-val for the values that you pass to build-buttons.idx word and a value that you pass as a parameter to build-buttons exists only during build-buttons evaluation — once the function returns to the caller, this relation gets broken. At the same time, idx word nested within the block that you compose _persists_ long after this relation is broken, and still "points" to a place where its value is supposed to be found. But when you press a button, incr-receive is called, it evaluates idx as one of its arguments... and cannot find anything.word! syntax. It also doesn't solve the problem completely, as your alias could still only reference another word in a single context (likely global, but wouldn't have to be). What do you do if 2 modules use the same word and you want to alias it?closure! is for.closure! but never connected it to this purpose. Red[Needs: View]
data: [
18 red
22 blue
15 green
20 yellow
10 purple
]
sum: 0
foreach [val color] data [sum: sum + val]
plot: copy [
canvas: base 200x200 silver
;box snow 200x200
draw[
pen black
circle 100x100 90
line 100x100 100x10
]
]
total: 0
foreach [val color] data [
angle: 360 * val / sum
total: total + angle
xy: 100x100 + as-pair 90 * sine total -90 * cosine total
repend plot/draw ['line 100x100 xy]
append plot/draw reduce [
'fill-pen color
'flood 100x100 +
100x100 + (as-pair
90 * sine total - (angle / 2)
-90 * cosine total - (angle / 2)
) / 2
]
]
view plotflood command — try to play around with [fill-pen](https://github.com/red/docs/blob/master/en/draw.adoc#fill-pen) instead.? (draw 100x100 [fill-pen red circle 50x50 20])
pie is interesting exercise. You'll need rainbow.png (below) to use the above pie.red. There is also [pie-style](https://gist.github.com/toomasv/8de193279fe556b6bb4f7b67c7e18c22) and [sectors](https://gist.github.com/toomasv/a122fa00305d3f2290a3b952d0c84c2d).start: -90
lay: foreach [color angle text][
61.160.255 110 "First"
99.212.212 70 "Second"
80.202.115 40 "Third"
250.212.57 40 "Fourth"
242.97.123 50 "Fifth"
150.90.228 50 "Sixth"
][
append [] compose/deep [
at 0x0 box 400x400 draw [
fill-pen (color) pen white line-width 2
arc 200x200 100x100 (start0: also start start: start + angle) (angle) closed
pen black rotate (start0 + start / 2) 200x200 [text 325x190 (text)]
] on-over [
face/draw/9: either event/away? [100x100][120x120]
]
]
]
view/tight append lay [
box 400x400 draw [
fill-pen white pen white circle 200x200 40
]
]pie-style. Try first example. app.red -fooprint system/options/argssystem/script/args has them too__name__ == "main" analogue from Python in Red? I have a window.red, and I want to debug a specific window, without having to start the whole application and click through each time to open that window, so I wanted to check in the window.red file if it's being called directly or being included from the main file?if find system/options/script "script-name.red" [...]system/options/script gives the name of the currently running script?split-path:>> second split-path %/some/very/long/path/to/script.red == %script.red
C:\ProgramData\Red folder and re-download latest Red binary but GUI Console still not working. Do you know there are any other caches about Red I should delete...?C:\\AppData\Roaming\Red .any-word! but also all-word!. I understand difference, but is there any real usage of the second one?ret: send-request/data/auth https://fax.twilio.com/v1/Faxes 'POST [
From: "+1234567891"
To: to_number
MediaUrl: https://www.twilio.com/docs/documents/25/justthefaxmaam.pdf
]'basic [
"MyID" "MyPassCode"
]ret: send-request/data/auth https://fax.twilio.com/v1/Faxes 'POST compose [
From: "+123456789"
To: (to_number)
...
]reduce or your preferred method, nothing special there.reduce/no-set in Rebol, it's much harder with reduce, you would need to set-word! 'something for every set-word!. compose is much cleaner currently.doc: read/lines file
foreach line doc [
parsed-line: parse-abc-line line false
switch/default (copy/part parsed-line 2) [
"A:" [
tune-list/(length? tune-list)/A: parsed-line
]
"B:" [
tune-list/(length? tune-list)/B: parsed-line
]
"C:" [
tune-list/(length? tune-list)/C: parsed-line
;-- and so onfile or parse-abc-function I just made up simplistic ones:tune-list: [#()]
letter: charset [#"A" - #"Z"]
trash: clear []
doc: {1 A: "Red"
2 B: "Blue"
3 C: "Green"
4 D: "Yellow"}
parse doc [some [
to [" " letter ": "] skip
copy line to [newline | end] (
either find/case "ABC" first line [
l: copy/part line 2
tune-list/(length? tune-list)/:l: line
][append trash line]
)
]]>> tune-list
== [#(
"A:" {A: "Red"}
"B:" {B: "Blue"}
"C:" {C: "Green"}
)]
>> trash
== [
{D: "Yellow"}
]tune: object [
; field name header corps other util Sample and notes
; ============ ====== ==== ========= ======= ==================
A: "" ; region yes A:Normandie A:Bretagne
B: "" ; source yes yes archive B:O'Neills
C: "" ; composer yes C:Trad.
D: "" ; discographie yes archive D:Chieftans IV
E: "" ; espacement yes yes I don't use
F: "" ; Field name yes I don't use
G: "" ; instrument yes yes archive G:flute
H: "" ; history yes yes archive H:composé en…
I: "" ; information yes yes playabc
K: "" ; key Last yes K:G, K:Dm, K:AMix
L: "" ; default value yes yes L:1/4, L:1/8
M: "" ; mesure yes yes yes M:3/4, M:4/4
N: "" ; notes yes N:voir O'Neills 234
O: "" ; from yes oui index O:I, O:France,
P: "" ; parts yes oui P:ABAC, P:A, P:B
Q: "" ; tempo yes oui Q:200, Q:C2=200
R: "" ; rythm yes oui index R:R, R:valse
S: "" ; source yes S:collected in cork
T: "" ; title second yes W:rat's in the river
X: "" ; index number First yes X:1, X:2
Z: "" ; transcription yes Z: from a paper
melodie: [] ;-- the melody part of the ABC tune ...
;-- a simple liste of lines at this time
]parse-abc-line: function [ line incipit
/local
tmp-line
/extern
pass
last-to-get
][
{ parameters
line : line of abc : doc for ABC in %doc/abcplus_en.pdf or _fr.pdf chapter II for idea of
what whe have to do for a complete parser
incipit: boolean true if we want only the 2 first bars of the tune
Here whe parse-abc-line is used for one abc line and in a loop whe have to pay attention
on 2 extern vars
pass: is set to true when one complete tune is processed and to false when the "X:" is encountered
to know that a new tune is in processing
last-to-get: is used when whe are processing lines with incipit set to true. it is set to true when the
the first line of melodie is get.
}
tmp-line: to-string rejoin [line/1 Line/2]
;-- headers
either (parse tmp-line
[some["A:" | "B:" | "C:" | "D:" | "E:" | "F:" |
"G:" | "H:" | "I:" |"K:" |"L:"|"M:"|"N:"|"O:"|"P:"|"Q:"|"R:"|"S:"|"T:"|"W:"|
"w:"|"$ "|"X:"|"Z:"]])[
if ( all [ incipit parse tmp-line ["X:"] ]) [
last-to-get: false
pass: false
]
rejoin [line "^(line)"]
][
;-- Melodie
either incipit [
either all [not pass not last-to-get][
last-to-get: true
rejoin [ tmp-line/1 "|" tmp-line/2 "|" tmp-line/3]
][
pass: true
]
][
if (not incipit) [
rejoin [line "^(line)"]
]
]
]
]load-abc-list-from-file: function [ file /extern tune-list tune ][
;-- load tune-list [] from a file
tune-list: []
doc: read/lines file
foreach line doc [
parsed-line: parse-abc-line line false
switch/default (copy/part parsed-line 2) [
"A:" [
tune-list/(length? tune-list)/A: parsed-line
]
"B:" [
tune-list/(length? tune-list)/B: parsed-line
]
"C:" [
tune-list/(length? tune-list)/C: parsed-line
]
"D:" [
tune-list/(length? tune-list)/D: parsed-line
]
"E:" [
tune-list/(length? tune-list)/E: parsed-line
]
"F:" [
tune-list/(length? tune-list)/F: parsed-line
]
"G:" [
tune-list/(length? tune-list)/G: parsed-line
]
"H:" [
tune-list/(length? tune-list)/H: parsed-line
]
"I:" [
tune-list/(length? tune-list)/I: parsed-line
]
"K:" [
tune-list/(length? tune-list)/K: parsed-line
]
"L:" [
tune-list/(length? tune-list)/L: parsed-line
]
"M:" [
tune-list/(length? tune-list)/M: parsed-line
]
"N:" [
tune-list/(length? tune-list)/N: parsed-line
]
"O:" [
tune-list/(length? tune-list)/O: parsed-line
]
"P:" [
tune-list/(length? tune-list)/P: parsed-line
]
"Q:" [
tune-list/(length? tune-list)/Q: parsed-line
]
"R:" [
tune-list/(length? tune-list)/R: parsed-line
]
"S:" [
tune-list/(length? tune-list)/S: parsed-line
]
"T:" [
tune-list/(length? tune-list)/T: parsed-line
]
"W:" [
tune-list/(length? tune-list)/W: parsed-line
]
"X:" [
append tune-list copy tune
tune-list/(length? tune-list)/X: parsed-line
]
"Z:" [
tune-list/(length? tune-list)/Z: parsed-line
]
] [
append tune-list/(length? tune-list)/melodie parsed-line
]
]
tune-list
]X: 1 T: 1-1 Lucy Farr's R: barndance M: 4/4 L: 1/8 K: Gmaj |:DE/2F/2|G2 G2 G2 G2|GABG E2 D2|B2 B2 B2 B2|BcdB A3 A| BcdB G2 G2|GABG E2D2|DEGA BddB|A2 G2 G2 :|| |:A2|BcdB G2 G2|GABG E2 D2|DEGA BddB|B2 A2 A3 A| BcdB G2 G2|GABG E2 D2|DEGA BddB|A2 G2 G2 :|| X: 2 T: 1-2 Gypsy Princess R: barndance M: 4/4 L: 1/8 K: Gmaj (B2 B)B B2B2|ABAG E2 D2|(G2G)B d2 Bd|e2 dB A2 GA| (B2 B)B B2B2|ABAG E2 D2|(G2G)A BddB|A2 G2 G2 z2:| (d2 d)d d2 d2 |B2 BA G2 Bd|(e2e)e e2 e2|B2 BA G2 zB| (d2 d)d d2 d2 |B2 BA G2 Bd|(g2 g)e dBGA|B2 A2 G2 z2:| X:3 T:2-1 Ar Thoir An Donn R:Reel M:C| L:1/8 K:Emix AFFE ~F2 EF | AF~F2 Acec | BG~G2 EFGB | c/2d/2e fe ecBG | AFFE ~F2EF | AF~F2 Acec | BG~G2 EFGB |1ceBG AFFE | |2 ceBG AF~F2 || c/2d/2e fga2 ga | fe~e2 cBAc | BG~G2 EFGB | c/2d/2e fe ecBd | c/2d/2e fg a2 ga | fe~e2 cBAc | BG~G2 EFGB | |1ceBG AF~F2 :|2 ceBG AFFE |]
>> load-abc-list-from-file %./data/sources/SV-DG-DN.abc
== [{|:DE/2F/2|G2 G2 G2 G2|GABG E2 D2|B2 B2 B2 B2|BcdB A3 A|^/} "BcdB G2 G2|GABG E2D2|DEGA BddB|A2 G2 G2 :||^/" "|:A2|BcdB G...
>> tune-list/1/L
== "L: 1/8^/"
>> tune-list/1/K
== "K: Gmaj^/"
>> tune-list/1/T
== "T: 1-1 Lucy Farr's^/"
>>load-abc-list-from-file: function [ file /extern tune-list tune ][
tune-list: []
doc: read/lines file
attrs: charset [#"A" - #"T" #"X" #"Z"]
foreach line doc [
parsed-line: parse-abc-line line false
if find/match parsed-line "X:" [
current: length? append tune-list copy/deep tune
]
either parse/part parsed-line [attrs #":"] 2 [
attr: to-word first parsed-line
tune-list/:current/:attr: parsed-line
][
append tune-list/:current/melodie parsed-line
]
]
tune-list
]if not find block value [append block value]
alter which does something similar.set! type would solve it properly :-)extend, but that is only for key/value pairs.set! type work?nipend :)append-if-new, but then came up with just perfectly valid new imo .... append, if not already there. But newgenerally could be used to instantiate new objects, etc., so maybe not so great naming suggestion ....new block value
if found? find target value []old Rebol memes :-) Should I post a wish ticket? :-)found?. Or true?, whater the name, I don't care. But it's so useful I have to add it manually to almost any big enough codebase.if find target valuegood enough?value: either something [x][y] and want to use value: pick [x y] true? something. You may use value: pick [x y] not not something, but that looks crazy.appendand insertcould have just new refinement. But I think it is going to be rejected, as any new addition to those two will slow them down a little append/new. This one would be used much more frequently, than append/dupimo ....set!. New refinement would slow down actions, new datatype would be optimized for this kind of usage.set* function(s)?map! type and hypothetical map function, but I don't think it would be such a problem.setsupposed to do on block values? Set an element at index position?set [a b c] 1I have realised, it sets each word to a given value. That is something I would expect from mapor each function maybe ....extend allowing block! as a first argument and any-type! as second. set! type is still my preferred one.unless find block value [append block value].extendword is self explanatory. But my feeling is, that we have started to remove polymorphism from Redbol by having all those set, put, get,poke, pick etc. :-) putdoes "new" implicitly .... it replaces the key/value if found, or adds itput still requires a key.putis very useful.extend block value, not requiring mine proposed new block valueblock! I mean.) spec [block! hash! map!]block! and for map! / object! but that's not unseen in Red, for example foreach also has special case for map!.append/only block value could work with such a check.. if value would not be block... because the /only is now ignored if value is not block!unless find...append...openhad too many refinements already, but append and insert are branching their code anyway, no? Would there be any speed penalty by just adding /new refinement?union so maybe it's not reasonable at all)set! type)set!.. I will use the union with my value inside a block.set! so I'm not the only one who wants it :) But I understand there are more important things to do.set! implementation done using reactors, let me find it...>> do %set.red
== func [/local value][
value: make sorted-set! []
value/data
]
>> s: make-set
== []
>> append s 1
== [1]
>> append s 2
== [1 2]
>> append s 1
== [2 1]union is much slower...:>> dt [loop 10000 [b: [a b c d] v: 'e union b reduce [v]]] == 0:00:00.0219467 >> dt [loop 10000 [b: [a b c d] v: 'e unless find b v [append b v]]] == 0:00:00.0089654
set!type would help to add a non-existent element to a block?New, append/new, etc. don't work from a naming perspective. The basic words have to clearly imply the logic involved. Extend is the closest, but then we run up against the issue that blocks are *not* key-value pairs. We do want to use them that way, a lot sometimes, hence things like set/key/has-key wrappers. If we say that extend *treats* blocks that way (and we can), then it needs to work like it does for maps and objects, with key-value pairs, and so doesn't match what @Oldes needs in this case. It really is set logic as @rebolek says, but that's a much larger task, as we have all the other series types to consider. e.g. we have charset to wrap bitsets, which covers string types, but is set! simply a block with added logic, or do we have any-set! which could also be a hash! or other block type (and also a bitset)?Union and other set ops are not complex today in how they're dispatched, because the types have to be compatible. Even if you bring type coercion in, you still have the overhead of creating a compatible type internally. Or complicating the set op code in each type.append-new myself at one point. I also did this:inset: func [ ;!! too close to INSERT "Append value to series if not present; otherwise return location where value was found." series [series!] value ][ any [find series value append series value] ]
set! gives you, of course, is the confidence that nobody (like you on another day) can go behind your back and treat the block as a non-set and mess things up. Same issue as with alter and the design question of removing all occurrences or just one.Include is a nice name, and carries semantics with it, that we expect it to be idempotent. But probably too confusing to mix with the preprocessor, which is also (generally) location dependent. expand but that's currently used by expand-directives which I don't think is a good choice.newis eventually a bad name. It stems down from things like append-if-new, where Carl suggested to not make a long names. For me, /onlyis one of the worst naming decisions in Redbol and users absolutly can't have any clue, unless they become familiar with what it represents. And yes, it would work for the above discussed scheme, but is naturally taken to prevent inlining of blocks.insertand appendand overloading those things is not user's business, but a designer's one :-) So - I am not sure I want to have yet another function to remember, expand, keeping in mind what datatype it works for and for what it does not.insert is enough as it was in earlier Rebol versions ;-) I don't think that having more functions is a bad think and you don't have to remember them, just remember those which you useextend feels kind of superfluous, we have insert and append and also put which takes key and value as args. The only difference between extend and put is that extend can put more keys at once, but I believe put can be extended to support this also.extendis nice and self explanatory word ...if not find block value [append block value]supplement.set! on the roadmap: https://trello.com/c/O2upNkDQ/47-datatypessupplementsounds good to me.find and select... one never knows which equality type should be supported :/supplement: func [
"Append value if not yet found."
series [block!] {(modified)}
value
/case "Case-sensitive comparison"
/local result
][
result: series ; to return series at same position if value is found
any[
either case [
find/case series :value
][ find series :value ]
append series :value
]
result
]new is so semantically loaded from OO that it could easily be confused with meaning make or copy the value. I agree that /only is one of those things you have to learn, but to replace it we need a better suggestion. I don't have one, and I've tried. :^)Extend was added to R3, and Red took it from there. It's always a balance between too many functions to remember, and too few that are heavily overloaded. I won't vote for supplement as a standard name, but am happy if others like it for their own use. We also have join/combine which I played with as wrappers to reduce the number of funcs to remember, if the behavior isn't too confusing.value: either something [x][y] and want to use value: pick [x y] true? something. You may use value: pick [x y] not not something, but that looks crazy.value: pick [x y] true = something - that's just one more char (space) to type ;)nones, not for series..to logic! worksto yes something :D (but I wouldn't prefer this one)union converts blocks to hashes and then back. But if you use a hash in the first place, it should be faster than find on blocks, esp. when your hash grows.unique call to remove duplicates. But the supplement thing is more for user friendly tasks of type: _append directory to this list, if there is not yet_ and do other job.r: to-hash ["one" "two"] save %htest1 r save/all %htest2 r
probe load mold true probe load mold/all true
>> type? load mold true == word! >> type? load mold/all true == logic!
mold (or save) is not enough and you need to use the /all variant. I wouldn't compare it to parse, where /all refinement does different thing and while parse/all is better as default, there are situations where I miss the Rebol-like parse with its whitespace auto-skipping./all output is less readable, so if you want something that should be human accessible, better not use itredbin.>> f: func [/local a] [probe words-of context? 'a] == func [/local a][probe words-of context? 'a] >> f *** Internal Error: reserved for future use (or not yet implemented) *** Where: reflect *** Stack: f probe words-of
system/words words-of works but not on functions.lent: [
"Pride and Prejudice" ["Alice"]
"Wuthering Heights" [""]
"Great Expectations" ["John"]
]probe select lent "Pride and Prejudice" ;== ["Alice"] change "Alice" to "Susan" ; pseudocode probe lent
probe select lent "Great Expectations" ;== ["John"] change "John" to "Alan" ; pseudocode probe lent
cclone: func [ "Make a new context with the same values of another one" ctx [object! word!] "The starting context: context or context of a bound word" /local wrds ;Block used to build the new object prototype out-data ;The returned element ] [ ;Mettere il GET if word? ctx [ctx: bound? ctx] wrds: words-of ctx forall wrds [ if word? first wrds [ change wrds to-set-word first wrds ] ] append wrds none wrds: head wrds out-data: make object! wrds set out-data values-of ctx out-data ]
words-of is missing on Red but I will try to part it with spec-of and parse.lent: [
"Pride and Prejudice" ["Alice"]
"Wuthering Heights" [""]
"Great Expectations" ["John"]
]
lent/("Pride and Prejudice"): "Susan"probe lent
== [
"Pride and Prejudice" "Susan" <-- not ["Susan"]
"Wuthering Heights" [""]
"Great Expectations" ["John"]
]lent: [
"Pride and Prejudice" ["Alice"]
"Wuthering Heights" [""]
"Great Expectations" ["John"]
]
lent/("Pride and Prejudice")/1: "Susan"lent: [
"Pride and Prejudice" ["Alice"]
"Wuthering Heights" [""]
"Great Expectations" ["John"]
]
change find lent/("Pride and Prejudice") "Alice" "Susan"[["Alice" "Kathy"]
"Wuthering Heights" [""]
"Great Expectations" ["John"]
]Select returns the value following the key.remove lent find lent/("Pride and Prejudice")
probe lentremove lent removes the first element in lent. Try step by step. e.g.select lent <key> find lent <key> remove ... <one more step for key-value handling>
lent if you've modified it while playing.lent: [
"Pride and Prejudice" ["Alice" "Kathy"]
"Wuthering Heights" [""]
"Great Expectations" ["John"]
]
remove/key lent "Pride and Prejudice"
remove/key lent "Great Expectations"
; == [
"Wuthering Heights" [""]
]change/key. :^)/skip 2 for remove/key on a block.cclone function will have a limit once ported to Red. Even if I parse the function specs object, when cloning the context, if values have words bound to the cloned one, it won't work. Until the day we will have closures, we could not pass blocks and structures born inside a function to another one. All operations must happen under the function umbrella. make will correctly bind the word to the new context. Just too late to think on this topic, I have to sleep ;-)words-of returns a block of words but some of them are of refinement type, even if they have the visual aspect of a word. How do I create a context where some words are refinements and not simple words, and how do I set them to true? bl: [a: 0 b: 10 c: 20 d: 30] save/all %test.red bl do load %test.red probe b ;== 10 save %test.red bl ;<-- NO /ALL do load %test.red probe b ;== 10 save %test.red bl ;<-- NO /ALL do load/all %test.red ;<-- NO /ALL probe b ;== 10 save %test.red bl do %test.red ;<-- NO LOAD probe b ;== 10
== [a: 0 b: 10 c: 20 d: 30] >> save/all %test.red bl >> b: load %test.red == [a: 0 b: 10 c: 20 d: 30] >> probe b [a: 0 b: 10 c: 20 d: 30] == [a: 0 b: 10 c: 20 d: 30] >>
/all isn't in place for all other values as well. The reason for that is finalizing decisions on the serialized syntax. That may move forward now, as the redbin work is wrapping up, and /all is another piece of the serialization puzzle.unview quit and window close, not sure I've seen example that catches them all. no luck for terminate or something like reboot right now without wrapping OS librarieson-close? It should work fine, but as @ne1uno says, there are many ways a window can be closed.on-close in the end of VID block. Window options and actors are in the beginning of VID.view/options/flags [
title "APP_TITLE"
;-- etc...
] [
menu: [
"Files" [
;--Etc...
]
---
"Quit" kwit
]
]
actors: make object! [
on-close: func [face [object!] event [event!]][ write F_TUNES_LIST tunes-list]
on-menu: func [ face [object!] event [event!]][
;-- Etc...
if event/picked = 'kwit [
write F_TUNES_LIST tunes-list
quit]
]
]
][resize]3.33x33.3 or 3.33x33.3x333. To me, that's not really readable. And even 3x3 is the way I write 3*3 on paper.(3.33 ; 33.3 ; 333.). I guess that wouldn't work. Maybe 3.33|33.3|333. ?(3,33 ; 33,3 ; 333)3.33|33.3|333. ? I personally like 3|3 more than 3x3, but I don't know Red enough to be objective.(1.2, 3.4, 5.6) could be ambiguous3.33x33.3x333. That is, how important is the literal form really? (1.2, 3.4, 5.6) was what Nenad considered at one point, but ambiguity (in 2 ways) makes it a tough call. to-triple [3.33____33.3____333]image! then no, if it's a Draw block then yes.draw facet.view [base 500x500 draw [fill-pen red] on-down [append face/draw reduce ['circle event/offset 10]]]
context?, bind and other functions to access the codecs' inner context for a while but not succeeded...replace-unicode-escapes: get in context? first find body-of :load-json 'json-value 'replace-unicode-escapes
sequence: "\u304a\u306f\u3088\u3046" ; "おはよう" is descaped string
json: rejoin ["{^"value^":^"" sequence "^"}"]
result: load/as json 'json
;== #(
; value: "おはよう"
;)>> load/as rejoin [{"} "\u304a\u306f\u3088\u3046" {"}] 'json
== "おはよう">> load/as {null} 'json
== none
>> load/as {true} 'json
== trueview [box 100x100 draw [fill-pen red circle 50x50 30] on-down [probe "Circle"]]
on-over processes mouse movement only if it is over transparent area, e.g.view [box 100x100 draw [fill-pen red circle 50x50 30] on-over [if event/away? [probe event/offset]]]
view [box 100x100 draw [circle 50x50 30] on-down [probe "Circle"]]
loop 10 [ask "Give some input:"]
print [] <--- arrrgh why??? loop 10 [ask "Give some input:"]
prin + input combo not working properly ;) loop 10 [print "test" wait 0.5]. It will wait till the loop is finished and then prints at once. It drives me crazy, but it is supposed to be fixed with proper IO?loop 10 [print "test" do-events/no-wait wait 0.5]wait is blocking and simple atmwait mezz that does do-events/no-wait every 5ms or so.Android target ➜ tmp ~/src/red-latest -t Android hello.red
-=== Red Compiler 0.6.4 ===-
Compiling /home/marko/tmp/hello.red ...
...compilation time : 761 ms
Target: Android
Compiling to native code...
*** Warning: OS_TYPE macro in R/S is redefined
*** Compilation Error: invalid path value: image/extract-data
*** in file: %/home/marko/tmp/datatypes/binary.reds
*** in function: red/binary/to
*** at line: 1
*** near: [1030x7
proto: image/extract-data as red-image! spec EXTRACT_ARGB
]
➜ tmp more hello.red
Red [ needs: View ]
view [ text "Hello World" ]wait is there only to slow down a loop, forget it then and just print in a longer loop. The result is going to be buffered anyway and not printed unless the loop ends iirc ...needs gui to text console you build yourself. the old gui console doesn't block but seems to wait also. but has a few other exit quirksralf@ralf-Lenovo-Yoga-2-13:~/Desktop$ sudo apt-get install libc6:i386 libcurl4:i386 libgdk-pixbuf2.0-0:i386 Reading package lists... Done Building dependency tree Reading state information... Done libgdk-pixbuf2.0-0:i386 is already the newest version (2.40.0+dfsg-3). libc6:i386 is already the newest version (2.31-0ubuntu9.1). libcurl4:i386 is already the newest version (7.68.0-1ubuntu2.2). 0 to upgrade, 0 to newly install, 0 to remove and 0 not to upgrade. ralf@ralf-Lenovo-Yoga-2-13:~/Desktop$ ./red-08dec20-1c5880827 Compiling compression library... Compiling Red console... /home/ralf/.red/console-2020-12-8-28365: error while loading shared libraries: libgtk-3.so.0: cannot open shared object file: No such file or directory
www.redlang.org/p/download.html say:(*) For Linux 64-bit distros, you need to install 32-bit supporting libraries.
If you are using an Ubuntu 18.04+ version, you should use libcurl4 with multiarch:
dpkg --add-architecture i386
apt-get update
apt-get install libc6:i386 libcurl4:i386 libgdk-pixbuf2.0-0:i386sudo apt-get install libgtk-3-dev to no avail... - I mean installation was successful yet red still complains about missing libgtk-3.so.0sudo apt install libgtk-3-0:i386 ... ralf@ralf-Lenovo-Yoga-2-13:~/Desktop$ ./red-08dec20-1c5880827 --== Red 0.6.4 ==-- Type HELP for starting information.
view/options [area 100x30 button "ok" [unview]][offset: 100x100] plases it just in regards to one of my displays. Both Red and R2 seem to see only one of my monitors ....view/options [area 100x30 button "ok" [unview]][offset: -2560x0]get-screen-size 0 returns size of the main screen... if you have 2 screens you can use get-screen-size 1 to get screen size of the second oneget-screen-count which will return number of screens available.get-screen-size as a [template](https://github.com/red/red/blob/master/modules/view/backends/platform.red#L541-L548)get-screen-size 1 will not work, as the id is not used. You would have to go deeper the [rabbit hole](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors).on-change* and on-deep-change* most likely.Needs: View into the header.o: make object! [
label: 'object
]
label: 'local
a: make o [ label: label ] probe a/label ; (1) NOK - object
l: :label b: make o [ label: l ] probe b/label ; (2) OK - local
c: make o [] c/label: label probe c/label ; (3) OK - local
d: make o reduce [ to-set-word 'label to-lit-word label ] probe d/label ; (4) OK - local
e: make o compose [ label: (to-lit-word label) ] probe e/label ; (5) OK - localcompose is my favorite way for thatobject [ x: 1 y: x * 2 ;) uses 'x' from the same object f: does [x * y] ;) uses 'x' and 'y' from the same object ?? x ?? y ;) debugging ]
o: make object! [
label: 'object
create: function [
label [word!]
return: [object!]
] [
n: make self []
n/label: label
return n
]
]
o1: o/create 'o1
o2: o/create 'o2expr: [ any val ]
val: [ digit | "(" s: expr ")" e: (print [index? s index? e]) ]
digit: charset [ #"0" - #"9" ]
parse "1(2(3))4" expr ; (1)str: copy "" collect: [ collect into str test ] test: [ ab | ac ] ab: [ a b ] ac: [ a c ] a: [ keep "a" ] b: [ keep "b" ] c: [ keep "c" ] parse "ac" collect probe str
str: copy "" enter: func [] [ append str "-" ] success: func [] [ remove find/last str "-" ] failure: func [] [ clear find/last str "-" ] keep: func [ v [string!] ] [ append str v ] test: [ ab | ac ] ab: [ (enter) a b (success) | (failure) fail ] ac: [ (enter) a c (success) | (failure) fail ] a: [ copy v "a" (keep v) ] b: [ copy v "b" (keep v) ] c: [ copy v "c" (keep v) ] parse-trace "ac" test probe str
memory: clear []
expr: [any val]
val: [digit | "(" s: (append memory index? s) expr ")" e: (print [take memory index? e])]
digit: charset [ #"0" - #"9" ]
parse "1(2(3))4" expr
3 7
5 8collect parse keyword. And the interplay with keep function (which does not currently sync with parse's keep, but should). And with manual modification of the collected into series (with append/remove etc). And scenarios when you don't want to backtrack - how you handle this. And evaluate the performance cost. I'm sure the team will gladly weigh your design and if it will be beneficial, I don't see why it shouldn't be used.c:\Users\YOURLOGIN\AppData\Roaming\Microsoft\Windows\SendTo\ then right click sendto will make the filename[s] available on the commandlinemake works one way doesn't mean it has to be the *only* way. You could write a dialect to match the semantics you prefer. I often suggest that people do things at the mezz level, because it's easy to play that way, show others something that they can touch and play with, and also gives us a written history of ideas.img: draw 76x25 [pen off fill-pen red box 0x0 75x24 pen violet text 5x3 "Img-button"] view [button with [image: img][probe "hi"]]
system/view/screens/1/size == 1706x960 as Red now reports, but 2560x1440 (because I have scaling 150% not to have everything too small)2560x1440 resolution, but set to FullHD 1920x1080and 125%scaling. Red reports my screen as being of 1536x864 ....1536x864 is strange. I would expect 2048x1152 for 125%slash is way to not depend on / or \>> first split last split "F:\zak_data\notifications\test\fcsNotificationEA44_03731_318.txt" slash "_" == "F:\zak" >> >> first split last split "F:/zak_data/notifications/test/fcsNotificationEA44_03731_318.txt" slash "_" == "fcsNotificationEA44"
;; A pattern for handling lots of objects
obj: context [
; data object
data: make object! [
_ctx: none
x: y: none
]
_check: function [o [object!]] [
if not in o '_ctx [
make error! "Expecting self/data object"
]
if not same? o/_ctx self [
make error! "This obj does not belong to me !"
]
]
create: function [x [integer!] y [integer!] return: [object!]] [
o: make data compose [_ctx: (self) x: (x) y: (y)]
return o
]
show: function [o [object!]] [
_check o
print [ o/x o/y ]
]
;; the rest of the code
]
myo: obj/create 1 2
obj/show myobind is another. But you got it right: code should stay in a shared context rather than be duplicated.obj: context [
x: none
show: function [] [
print x
]
]
ob1: make obj [x: 1]
ob2: make obj [x: 2]
ob1/show ; shows 1
ob2/show ; shows 2x: "global"
obj: context [
show: function [] [ print x ]
]
ob1: make obj [x: 1]
ob1/show ; show globalprint x was a working function, with x: 1 it may be broken, so why break it? (but even this logic doesn't apply in some cases, sadly)make creates the object (and before evaluating the spec). But my point was that you can use bind to rebind words after they were made. Remember: word is a symbol+context reference. That reference is yours to change as you see fit.myprint1: function [o [object!]] [ ; (1)
code: bind [ print [x y] ] o
do code
]
myprint2: function [o [object!]] [ ; (2)
print [o/x o/y]
]
myobj: make object! [x: 1 y: 2]
myprint1 myobj
myprint2 myobjmyprint3: function [o [object!]] [
with o [
print [x y]
]
]with was in R3, I believe it was just a mezzanine function, basicaly like this: with: func [ctx code][do bind code ctx]with is trivial to add, but, performance is going to be bad in the interpreter, and the compiler won't know what to do with it. Which is why it's not there and generally people are encouraged to do things differently.bind/copy, but other than that it's just what @rebolek posted)FF: Func [ /local arg base-obj proto final-obj] [
arg: 22
base-obj: make object! [arg: none]
proto: [arg: arg]
final-obj: make base-obj proto
final-obj
]
probe ff>> probe ff
make object! [
arg: none
]Obj: make object! [a: b: c: none] C: 33 B: 44 Words: [b c] Forall words [ Set in obj first words get first words ]
WORDS-OF reflector to work on Red function context, could someone tell me why WORDS-OF is stealing words in Rebol:a: func [arg arg2][probe words-of bound? 'arg] >> a 1 2 == [arg2]
values-of suffers from this problem.>> a: 1 type? bound? 'a == object! >> do has [arg] [type? bound? 'arg] == logic!
bind? in function context could return function itself instead of true.. that could help you achieve what you are trying to do. >> f: func[arg1 arg2][type? context? 'arg1] f 1 2 == function! >> f: func[arg1 arg2][spec-of context? 'arg1] f 1 2 == [arg1 arg2]
f: func[arg1 arg2][
reduce bind spec-of context? 'arg1 'arg1
] f 1 2
== [1 2]>> reduce spec-of :f *** Script Error: context for arg2 is not available *** Where: reduce *** Stack:
ARG2 before than ARG1!?spec and body of the function.. which may lead to situations like:>> f: func[a][probe a] change spec-of :f 'b source f f: func [b][probe a]
spec-of is used.. not just context?.. and it's not just words.. it's function's spec block!>> f: func["Test" arg /ref][spec-of context? 'arg] f 1 == ["Test" arg /ref]
f: func["Test" arg1 arg2 arg3 /local w spec][ print ["arg1:" arg1 "arg2:" arg2 "arg3:" arg3] spec: spec-of context? 'arg1 parse bind spec 'arg1 [any [ set w word! ( print [w "=" mold try [get :w]] ) | /local to end | 1 skip ]] ] f 1 2 3
daniel@daniel-Lenovo-ideapad-500-15ISK:~/Apps/red/red_projets/dn-abc-tools$ red-lastest -c -r -o bin/load-abc load_abc.red
-=== Red Compiler 0.6.4 ===-
Compiling /home/daniel/Apps/red/red_projets/dn-abc-tools/load_abc.red ...
...compilation time : 1901 ms
Target: Linux
Compiling to native code...
*** Compilation Error: argument type mismatch on calling: red/natives/repeat-init*
*** expected: [struct! [
header [integer!]
data1 [integer!]
data2 [integer!]
data3 [integer!]
]], found: [struct! [
header [integer!]
ctx [pointer! [integer!]]
symbol [integer!]
index [integer!]
]]
*** in file: %/home/daniel/Apps/red/red_projets/dn-abc-tools/load_abc.red
*** in function: exec/f_ctx||394~value-path?
*** at line: 1
*** near: [
r3: 0
stack/reset integer/push 0
stack/mark-loop ~repeat
while
]Red [] thread_number: to-integer take second split system/script/args "=" print thread_number
>> do/args %test1.red "-a=9" 57
-u as well, it seems to be in the runtime compilation. You know your code, so it would help if you can pare it down to an absolute minimal example that produces the problem.needs: 'view 'util isn't correct, as it won't see the second value. Unless you've done some deep work, there is no util module I know of.tunes-list: copy [] sets-list: copy [] tune: object [ A: B: C: D: E: F: G: H: I: K: L: M: N: O: P: Q: R: S: T: X: Z: "" melodie: [] ]
tune: object [
A: B: C: D: E: F: G: H: I: K: L: M: N: O: P: Q: R: S: T: X: Z: ""
melodie: []
]
import-abc-list-from-file: function [ file /extern tunes-list tune ][
doc: read/lines file
attrs: charset [#"A" - #"T" #"X" #"Z"]
foreach line doc [
parsed-line: parse-abc-line line false
if find/match parsed-line "X:" [
current: length? append tunes-list copy/deep tune
]
either parse/part parsed-line [attrs #":"] 2 [
attr: to-word first parsed-line
tunes-list/:current/:attr: parsed-line
][
append tunes-list/:current/melodie parsed-line
]
]
]
either exists? F_TUNES_LIST [
tunes-list: load F_TUNES_LIST
][
import-abc-list-from-file request-file/title/file/filter
"Select ABC Files "
"%./data/sources"
["ABC Files " "*.abc"]
save-data
]#system directive?#call directive in an example how to use call. but nothing about it in the red docs in the github repo.Red [] ; Error ;A: B: C: D: E: F: G: H: I: K: L: M: N: O: P: Q: R: S: T: X: Z: "" ;A: B: C: D: E: F: G: H: I: K: L: M: N: O: P: Q: R: S: T: X: Z: none ;A: B: C: D: E: F: G: H: I: K: none ;A: B: C: D: E: F: G: H: I: none ; 9 Items I: is a trigger ;A: B: C: D: E: F: G: I: none ;A: B: C: D: I: none ;A: I: none I: none ; minimial example. It's case sensitive. ; OK ;A: B: C: D: E: none ;A: B: C: D: E: F: G: H: none ;A: B: C: D: E: F: G: H: K: none ; 9 Items ;i: none
I: none is the culprit. Gives the same repeat-init* error. Please open a ticket for that. tune: object [
A: B: C: ""
]
append tune/a "AAA"
append tune/b "BBB"
print tune/c>> length? tunes-list
== 75
>> tunes-list/75/melodie
== [{|:DE/2F/2|G2 G2 G2 G2|GABG E2 D2|B2 B2 B2 B2|BcdB A3 A|^/} "BcdB G2 G2|GABG E2D2|DEGA BddB|A2 G2 G2 :||^/" "|:A2|BcdB ...
>> tunes-list/75/T
== "T: 29-3 Drunken Piper (jig)^/"
>>-=== Red Compiler 0.6.4 ===- Compiling /home/daniel/Apps/red/red_projets/dn-abc-tools/test.red ... ...using libRedRT built on 18-Dec-2020/23:22:11 *** Compilation Error: load has no refinement called binary *** in file: /home/daniel/Apps/red/red_projets/dn-abc-tools/test.red *** near: []
I: in there, which I deduced was the source of the compilation problem.load/binary from anyway?foo: 3
bar: [30. 60.]
parents-data: #(
factor: 'foo
vector: 'bar
)
code: [ ; block I want to compose
(vector/1 * scaling-factor)
(vector/2 * scaling-factor)
]parents-data: #(
factor: foo
vector: bar
)
code: [
(pick get parents-data/vector 1) * scaling-factor
(pick get parents-data/vector 2) * scaling-factor
]
;>> [30.0 * scaling-factor 60.0 * scaling-factor]I: issue is a bug, please report it.save and load. If you have objects, you need to reduce the loaded data so they are constructed. Redbin should only be needed (and it's new-ish so report errors there) if you have cycles in your data structures.code has no idea where to look for vector without that. mold/all support for all types, it's needed much more often ;)'scale1/scaling-factor that turns into 'graph/nodes/scale1/data/scaling-factor as intended.; process the path to have the actual path
edge-path-to-actual-path: func [path] [
; this works as intended
;return 'graph/nodes/scale1/data/scaling-factor
rejoin ['graph/nodes path/1 'data (next path)]
]
to-path: edge-path-to-actual-path 'scale1/scaling-factor
; separates after 'data
probe parse to-path [collect [keep thru 'data keep [some word!]]]rejoin ['graph 'nodes .. I guess next path part is wrong insteadkeep pick else you get a path within a path. Using blocks for visualization:>> probe parse as [] to-path [collect [keep thru 'data keep some skip]] [[graph nodes scale1 data] scaling-factor] == [[graph nodes scale1 data] scaling-factor] >> probe parse as [] to-path [collect [keep pick thru 'data keep some skip]] [graph nodes scale1 data scaling-factor] == [graph nodes scale1 data scaling-factor]
to-path. It's a builtin function, never know what may break.>> compose [('a/b)]
== [a/b]
>> compose [(as [] 'a/b)]
== [a b]#define CURLOPT_SSL_VERIFYPEER 64 #define CURLOPT_SSL_VERIFYHOST 81 request-http: func [ ... curl_easy_setopt curl CURLOPT_SSL_VERIFYPEER 0 curl_easy_setopt curl CURLOPT_SSL_VERIFYHOST 0 ...
read function :-)data . But if I have few millions of elements in data like:number: none
objects: [
name: none
]data: [
regNum: none
maxPrice: none
lots: [
number: none
objects: [
name: none
]
number: none
objects: [
name: none
]
number: none
objects: [
name: none
]
number: none
objects: [
name: none
]
number: none
objects: [
name: none
]
]
]
data-walk: function[data tag value] [
changed?: false
fill-data: func[data] [
forall data [
either block? data/2 [
fill-data data/2
] [
if equal? to-string data/1 to-string tag [
if (changed? = false) [
if none? reduce data/2 [
data/2: value
changed?: true
break
]
]
]
]
]
]
fill-data data ; filling
]
list: ["regNum" 777 "maxPrice" 950 "number" "1" "number" "2" "name" "Apples" "name" "Bananas"]
foreach [a b] list [data-walk data a b]
probe datafill-data for each pair of elements in list.data: [
regNum: none
maxPrice: none
lots: []
]
list: ["regNum" 777 "maxPrice" 950 "number" "1" "number" "2" "name" "Apples" "name" "Bananas"]
numbers: clear []
names: clear []
fill-data: function [tag value] [
switch tag [
"number" [append numbers value]
"name" [append names value]
"regNum" [data/regnum: value]
"maxPrice" [data/maxPrice: value]
]
]
foreach [a b] list [fill-data a b]
n1: length? numbers
n2: length? names
either n1 >= n2 [
forall numbers [
append data/lots compose/deep [
number: (numbers/1)
objects: [name: (names/(index? numbers))]
]
]
][
forall names [
append data/lots compose/deep [
number: (numbers/(index? names))
objects: [name: (names/1)]
]
]
]
probe dataon-change* gets copied as any other function, because it *has* to be *bound* to new objectmold/all outputcopy only copies a set of *copyable* types - not including inner objects, mapsmake objects with this spec> data: [ > regNum: none > maxPrice: none > lots: [] > ] > list: ["regNum" 777 "maxPrice" 950 "number" "1" "number" "2" "name" "Apples" "name" "Bananas"] > > numbers: clear [] > names: clear [] > fill-data: function [tag value] [ > switch tag [ > "number" [append numbers value] > "name" [append names value] > "regNum" [data/regnum: value] > "maxPrice" [data/maxPrice: value] > ] > ] > > foreach [a b] list [fill-data a b] > > n1: length? numbers > n2: length? names > either n1 >= n2 [ > forall numbers [ > append data/lots compose/deep [ > number: (numbers/1) > objects: [name: (names/(index? numbers))] > ] > ] > ][ > forall names [ > append data/lots compose/deep [ > number: (numbers/(index? names)) > objects: [name: (names/1)] > ] > ] > ] > probe data >
>> gg: make ff[
[ on-change*: func [word old new][
[ if word = 'a [
[ if new > 0 [
[ a: new * 2
[ b: a
[ ]
[ ]
[ ]
[ ]
>> mold gg
== {make object! [^/ a: -1200^/ b: 100^/ test: func [][^/ self/a + self/b^/ ]^/ autre-chose*: func [essai][^/ rejoin ["ceci est un" essai]^/ ]^/]}print mold/allWHERE IN (1,2)
1,2 in correct form?>> second split "-a=1,2" "=" == "1,2"
WHERE IN >> "1,2"
== "1,2"
>> {1,2}
== "1,2"
>> {"1,2"} ; here the braces are the string end markers, and the quotes are part of the string.
== {"1,2"}
>> "^"1,2^"" ; so you don't have to do this
== {"1,2"}a: ["one" "two" "three"]
vid-block: collect [
keep [
some VID elements
panel 200x200 [;<----------- opening it here
]
foreach [a b] data [
keep collect [button 30x20 (a) []]
]
keep [
some vid elements
] ;Closing panel bracket
]
]
view VID-BLOCKdata: ["one" [probe face/text] "two" [probe event/offset] "three" [ep/text: "Epilogue"]] vid-block: collect [ keep [ below text "Example:" ;some VID elements panel white 200x200 ;<----------- opening it here ] keep/only collect [ ;<-------- collect into panel foreach [a b] data [ keep compose/only [button 40x20 (a) (b)] ] ] keep [ep: text ""] ;some vid elements ] view vid-block
keep/only as only does not appear in the HELP of the collect function?? collect
...
keep: func [v /only] [either only [append/only collected v] [append collected v] v]
...collect [? keep]keep is visible only inside collect...