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] ] ? i
a: [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 ]
clear
instead of a copy
in @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-linercopy
ing, 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. apply
was 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!dir
dir
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-each
function, 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-each
function, 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 print
ing, 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 xyz
do
?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 == #{}
to
commandto 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-list
would 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" abbcddeff
1
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: 78x27
b: 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? value
is 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
.checksum
style 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 w
Red [ 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 w
text: {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 thisfind
find 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 == false
function? :foo
load
returns *data*do load %file
?:foo
to get valuefunction? :foo
foo
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 argument
type? rule/foo
rule
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 'func
do
) 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]]]
compose
view 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/offset
do 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 Windows
function1: 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.git
cd red
git checkout GTK
do/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 Hello
do 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"]
Hello
library/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 'x
reduce
pose some limits into code sequences stored in blocks?x: load %code.red do x
probe
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.red
MyProgram.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>] re
into
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 newblk
as-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/data
face
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 == 2663158
gzip
(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! :filter
filter
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 put
ting 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 pi
s 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:\red
set
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
x
s 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-change
view
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.red
do
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 resources
t
?x: [1 2 3 4 5]
x: [1 3 4 5]
remove at x 2
x: 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-each
is a native and as I remember from R2, it was also nicely fast. I really like the function and wished to have a keep-each
counterpart, 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] 7079847965846976731951378232749711097327797114107111118195161
prin 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\A1
parse 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 true
false
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/text
data/data
instead, dunno.f-data/text = f-rule/text
?test1file:
Red[] total: 1 + 2 print ["total: " total]
a: "" call/shell/output {./test1} a print a
totalas 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 v
probe v
to see what it isv: [] append v collect [ loop 5 [ keep [ b: button "hi" ] ] ] probe v/3: "aaa" view v
a: "test1" b: "test2" form reduce [a {"} b {"}]
== {test1 " test2 "}
{test1 "test2"}
Red[] total: 1 + 2 print total
a: "" call/shell/output {./test1} a print a
ashould 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} a
call/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 name
either
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! none
offset
face
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?compose
xml-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.txt
find
but I can't think of any variants how to mix it with skip
or second
(I think I thould use them)find/last
twice? ? 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 mold
f: 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 block
recdir: 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? 'word
unset? 'word
f-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" ]
? extract
x: [ 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.red
if democracy [ vote: vote + 1 ]
~/.Red-Console/
or somewherexubuntu
git pull
ed 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"
cd
ed 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
.cd
ed 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.red
result: [ ; 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.red
Red [] 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.red
result, 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-query
make-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?LOAD
load/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 a
check-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 win
i: 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 win
node1\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: ...
base
object!
, 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/free
result: 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)call
and 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 breakfind
return 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! :append
make op! :find
find
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 LOAD
ing of face/text
. It even converts to block!
. I have enter (a)/b
and found: [(a) /b]
in face/data
first 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 thirdline
read/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]] 'resize
on-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 'a
bind
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 bind
ing 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 self
self
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
:a
form 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]] 'resize
off
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 dd
insert 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/1
word [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 -d
recycle/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/b
red 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 argument
unset 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 ? quit
print
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 cases
help 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 = 206ms
mold/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 link
xde-open
progress
. 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/time
random
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."call
interface), 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-data
send-request/auth/data server method auth-type auth-data content
send-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-reply
curl -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]), pick
returns 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 ;]
copy
copies 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/words
f1
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"
form
ed 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 Windows
rcvGetSystemColors: 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 #4d864b1
fill-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/text
set-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.compose
ing 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 lay
repend
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 c
to-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.png
compose
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 repend
is 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*/if
take?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
0
either
?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 0
either
.>> 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 argument
x: copy system/words/x
func
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 ] f
f: function[/extern x] [ ... ]
would also work.x: "hello" f: function ['word] [ s: copy get word append s " world" print s ] f x
a/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.set
to 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]]
false
s 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: 2
tags: [ ["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 a
is 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] ] == 2
mapping
, 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] ] == 4
mapping
? 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.red
data: [ 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 ar
ar
is top-level, rest are inside block. There are no hardcoded words in walk-data
walk-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! 30
Who 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 out
append
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 data2
code: 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 lot
s and obj
s. 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 data
copy/deep
and copy/deep
?copy []
:either block? v [ append list-of-words reduce [k copy []] ;<-- here
objs:
. 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-5
f/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 ; ] ] ] ]
field
s 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 compos
ing 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? recycle
recycle
free memory>> f: func [] [ [ print "aa" [ return [ print "bb" [ ] == func [][ print "aa" return print "bb" ] >> f aa bb
return
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] 2
remove
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-events
do-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 do
ing and reduce
ing, 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 catch
ing 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 ;-- ???
n2
date!
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 == none
stack/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 == 7
bind
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! 3
do
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.red
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
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.red
Red [] #include %foo.red view [panel foo]
Red [] foo: [button]
red.exe -r -e D:\test\app.red
Script Error: view has no value
Needs: 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/xyz
function [/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).[]
data
data: [] 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/as
load/as
works fine, I use it all the timeread/as
is 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]
forskip
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]
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 for
nor 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.object
s. 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/a
red 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 255
make-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 printout
printout: 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 3
x
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 b
enlist: 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;-)dt
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: 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.forall
and with no /local
enlist: 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 OF
for 2 times! )rejoin
inside the loop, so it's a heavier on allocations.prin
enlist: 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.45
to
; 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 plot
flood
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 -foo
print system/options/args
system/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 on
file
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 new
generally 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 value
good 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.append
and insert
could 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/dup
imo ....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.set
supposed to do on block values? Set an element at index position?set [a b c] 1
I have realised, it sets each word to a given value. That is something I would expect from map
or 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]
.extend
word 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. :-) put
does "new" implicitly .... it replaces the key/value if found, or adds itput
still requires a key.put
is very useful.extend block value
, not requiring mine proposed new block value
block!
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...
open
had 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.new
is eventually a bad name. It stems down from things like append-if-new
, where Carl suggested to not make a long names. For me, /only
is 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.insert
and append
and 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.extend
is nice and self explanatory word ...if not find block value [append block value]
supplement
.set!
on the roadmap: https://trello.com/c/O2upNkDQ/47-datatypessupplement
sounds 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 ;)none
s, 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 lent
remove 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 == true
view [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:i386
sudo 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 - local
compose
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 'o2
expr: [ 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 8
collect
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 1920x1080
and 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 myo
bind
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 2
x: "global" obj: context [ show: function [] [ print x ] ] ob1: make obj [x: 1] ob1/show ; show global
print 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 myobj
myprint3: 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 data
fill-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 data
on-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/all
WHERE 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-BLOCK
data: ["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...