serie-to-sort: [ "c" "5" "a" "b" "4" "z" "b" "2" "r" "a" "7" "w" "b" "9" "h" "a" "3" "h" "c" "2" "g" ]
x: sort/skip/compare serie-to-sort 3 3 1 probe sort/skip x 3 == [ "a" "7" "w" "a" "3" "h" "b" "9" "h" "b" "2" "r" "b" "4" "z" "c" "5" "a" "c" "2" "g" ]
serie-to-sort: [ ["c" "5" "a"] ["b" "4" "z"] ["b" "2" "r"] ["a" "7" "w"] ["b" "9" "h"] ["a" "3" "h"] ["c" "2" "g"] ]
>> probe sort/skip/compare/all serie-to-sort 3 func [a b][any [a/1 < b/1 all [a/1 = b/1 a/3 <= b/3]]] [ "a" "3" "h" "a" "7" "w" "b" "9" "h" "b" "2" "r" "b" "4" "z" "c" "5" "a" "c" "2" "g" ]
serie-to-sort: [ ["c" "5" "a"] ["b" "4" "z"] ["b" "2" "r"] ["a" "7" "w"] ["b" "9" "h"] ["a" "3" "h"] ["c" "2" "g"] ] probe sort/compare serie-to-sort func [a b][any [a/1 < b/1 all [a/1 = b/1 a/3 <= b/3]]]
serie-to-sort: [ ["c" "5" "a"] ["b" "4" "z"] ["b" "2" "r"] ["a" "7" "w"] ["b" "9" "h"] ["a" "3" "h"] ["c" "2" "g"] ] probe sort/compare serie-to-sort func [a b][ print [a/1 b/1 a/3 b/3] ] == [ a b w z a c w g a a w h a b w h a c w a a b w r a b w z b a z w b a r w b b r z c a a w c b a z c b a r b a h w b b h z b b h r b c h a a a h w a b h z a b h r a c h a a b h h c a g w c b g z c b g r c c g a c b g h c a g h ]
sort
uses internally.No Author Title -------------------------------------------------------------------------------------- 033 Anita Notaro - Achter de schermen 043 Arianna Stassinopoulus - Maria Callas een biografie 089 Arthur Graaf, Roland Jonkers & Fokke Wierda - gezinsencyclopedie 030 Astrid Harrewijn - Ja kun je krijgen 056 Avery Corman - Kramer versus Kramer 106 B.G. van Wijckmade - Wipneus en Pim bij de knuppelmannetjes 108 B.G. van Wijckmade - Wipneus en Pim bij de rovers 103 B.G. van Wijckmade - Wipneus en Pim en de gestolen kroon 107 B.G. van Wijckmade - Wipneus en Pim en de oude paraplu 104 B.G. van Wijckmade - Wipneus en Pim en het plaagmannetje 105 B.G. van Wijckmade - Wipneus en Pim op muggeneiland 066 Bernlef - De pianoman 061 Cathy Kelly - Echt verliefd! 036 Chantal van Gastel - Zwaar Beproefd! 037 Chantal van Gastel - Zwaar verliefd! 080 Charles Williams / Nancy Price - Windstil / Fatale ontmoeting 068 Cheryl Strayed - Wild 072 Chr. van Abkoude - Kruimeltje 100 Chris van Abkoude - De vlegeljaren van Pietje bell 102 Chris van Abkoude - De zonen van pietje bell 097 Chris van Abkoude - Nieuwe avonturen van Pietje bell 095 Chris van Abkoude - Pietje bell 099 Chris van Abkoude - Pietje bell gaat vliegen 096 Chris van Abkoude - Pietje Bell Goocheltoeren 101 Chris van Abkoude - Pietje bell in Amerika 098 Chris van Abkoude - Pietje bell is weer aan de gang 064 Christine Nöstlinger - Het huis in Niemandsland 092 Ciara Geraghty - Verdronken in jou / Trouw aan mij 060 Colleen McCullough - De Doornvogels 055 Danielle Steel - Prijs der Liefde 026 Daphne Deckers - Alles is zoals het zou moeten zijn 081 David Alderton - Hamsters en Gerbils 084 David Barnouw & Gerold van der Stroom - De dagboeken van Anne Frank 111 Dijkstra's Uitgeverij Zeist N.V. - Ikke pikke porretje 110 Dijkstra's Uitgeverij Zeist N.V. - Olleke bolleke 113 Dijkstra's Uitgeverij Zeist N.V. - Op weg door de wereld 5 109 Dijkstra's Uitgeverij Zeist N.V. - Piep zei de muis 112 Dijkstra's Uitgeverij Zeist N.V. - Wie woont er in dat huis 091 Diverse Auteurs - De grote VARA atlas 090 Diverse Auteurs - De kleine bosatlas 076 Diverse Auteurs - En dat van ónze centen! 082 Diverse auteurs - Lef 083 Diverse auteurs - Onverwachte liefde - Een nieuw begin - Geluk bij een ongeluk 094 Donna Tartt - De kleine vriend 016 E.L. James - Vijftig tinten donkerder 015 E.L. James - Vijftig tinten grijs 017 E.L. James - Vijftig tinten vrij ...
Sophie Kinsella Roman Slapeloze nachten & Dubbel feest 2x 560 Jill Mansell Roman De prins op het verkeerde paard Misschien heeft Mady iets met Kerr McKinnon... 335 Tina Turner & Kurt Loder Biografie Ik, Tina Nu schitterend verfilmd als 'What's love got to do with it.' 265 ...
rcvResizeImage: routine [ "Resizes image" src [image!] iSize [pair!] return: [image!] ][ as red-image! stack/set-last as cell! image/resize src iSize/x iSize/y ]
panel/image: my-image
doesn't work for you?myimage: load %tuxrebol3.gif new-size: make pair! reduce [ (make integer! (myimage/size/x / 100) * 50) (make integer! (myimage/size/y / 100) * 50) ] view layout [ image new-size myimage ]
OBJ-A = OBJ-B
like way?equal? a b
I thinkstrict-equal?
>> o-1: object [a: 1 b: 2] == ... >> o-2: object [a: 1 b: 2] == ... >> o-1 = o-2 == true >> o-3: object [a: 1 b: 2 c: object [d: "3" e: @4]] == ... >> o-4: object [a: 1 b: 2 c: object [d: "3" e: @4]] == ... >> o-3 = o-4 == true >> o-5: object [a: 1 b: 2 c: object [d: "Ummm" e: @4]] == ... >> o-3 = o-5 == false
`>> o: object [a: 1 b: 2] o/b: o == make object! [ a: 1 b: make object! [...] ] >> o = o/b == true
>> o-1: make object! [a: 1 b: 2] >> o-2: make object! [a: 1 b: 2] >> o-1 = o-2 == false >>
>> o-1: make object! [a: 1 b: 2] >> o-2: make object! [a: 1 b: 2] >> o-1 = o-2 == true
all [(sort keys-of o1) = (sort keys-of o2) (sort values-of o1) = (sort values-of o2)] ; == true
o1
should not be same like o2
, because in OOP the order have a meaning.same?
is helpful. REBOL is a trademark of REBOL Technologies. WWW.REBOL.COM >> M: 22 == 22 >> reduce m == 22 >> reduce [m] == [22] >> reduce first [m] == m >>
--== Red 0.6.4 ==-- Type HELP for starting information. >> M: 22 == 22 >> reduce m == 22 >> reduce [m] == [22] >> reduce first [m] == 22 >>
M
returned by FIRST
m: 1 reduce 'm
get first [m]
first [m]
is word!
, why you say that it is lit-word?
If I perform on Rebol:>> type? first [m] == word!
word!
!word!
, question is same... the doc string for reduce
is: {Returns a copy of a block, evaluating all expressions}
get
in such a situation, which is more clear to me.M: 1 FIRST [M] -> M REDUCE M == 1
/only -- Only evaluate words and paths, not functions words -- Optional words that are not evaluated (keywords) (Type: block none)
reduce first blk
(I never used it) and if it's really worth to add at least 2 datatype checks with evaluation branches (don't know how it's done in Red, but that is what would be needed to do in R3).. into frequently used function.reduce first b
(at least for my tired mental sequence)-c
or -r
. If you aren't already, use -r
(or -u`) to make sure it's not a runtime issue with an old build, and also use the automated build rather than the (very old) stable build of Red.system
object. You probably should make a wish./proc/
dir on Linux.lay: layout [ origin 10x10 space 1x1 style b: button 72x38 font-size 12 ; default space of 1 turns as 3 pixels high in my display b "1" b "2" b "3" b "4" return ; twice high is 38*2 + 3 = b "5" b "6" b "7" b "8" 72x79 return ; (1) this row should be shifted to the top from 38 + 3 (button height + space height) pad 0x-41 b "1" b "2" b "3" return ; lets add a full width field - width is 72*4 + 3*3 = 297 ; (2) correct field row that is one pixel to the left compared with buttons pad 1x0 field 297x38 orange font-size 16 "F1" return ; (3) correct further gap between field widget and text widget that is 2 pixels high and not 3 pad 1x1 text 297x38 green "F2" return ] view/no-wait lay ; for a dump of the window ; img: to-image lay ; save/as %layout.png img 'png
/proc/
dir on Linux.Kernel32.dll
on Windows.Kernel32.dll
on Windows.Red [] #import [ "kernel32.dll" stdcall [ process-id?: "GetCurrentProcessId" [ return: [integer!] ] get-env: "GetEnvironmentVariableA" [ name [c-string!] buffer [c-string!] size [integer!] return: [integer!] ] ] ] pid: process-id?
undefined word process-id?
Red [] #system [ #import [ "kernel32.dll" stdcall [ process-id?: "GetCurrentProcessId" [ return: [integer!] ] ] ] _pid: func[return: [integer!]] [return process-id?] ] get-pid: routine [/local pid [integer!] ] [ pid: _pid print pid ] get-pid
text
and it was causing an error.keys: #( k1: ['k1 'Key1] k2: ['k2 'Key2] ) rule: compose [ (keys/k1/1) keep ( to-paren keys/k1/2 ) | (keys/k2/1) keep ( to-paren keys/k2/2 ) ] s: copy [] parse [k1 k1 k2] [collect into s [any rule]] probe s
keys: #( k1: ['k1 'Key1] k2: ['k2 'Key2] ) rule: do [ b: copy [] foreach v values-of keys [ append b reduce [v/1 'keep to-paren v/2 '| ] ] take/last b b ] s: copy [] parse [k1 k1 k2] [collect into s [any rule]] probe s
keys: #( k1: ['k1 'Key1] k2: ['k2 'Key2] ) rule: [ <keys/k1/1> keep ( <keys/k1/2> ) | <keys/k2/1> keep ( <keys/k2/2> ) ] ; meta-parse the rule meta: [ any [ item ] ] item: [ s: tag! ( change s reduce load to-string s/1 ) | ahead [ block! | paren! ] into meta | skip ] parse rule [ meta ] probe rule ; parse s: copy [] parse [k1 k1 k2] [collect into s [any rule]] probe s
form reshape [ !(pname) !(ver) @(desc) "by" /if author @(author) #"^/"]
reshape
. And it should be invariant towards new-lines in this case.a + b
is an "expression" with 3 values, while a+b
is a word.*** Red/System Compiler Internal Error: Internal Error : No more global variable space
do
s. Are there any other ways to help with this problem? Or perhaps my code is poorly written, are there any practices that especially lead to this error? I think I don't have anywhere in my code what @hiiamboris did in #4361 :-)do/args %path-to-source/red/red.r "-c %<your top file here>.red"
REBOL/Core 2.7.8.4.3
. Do you have any explanation for that, or you just tried random solutions? Do you think it will work with rebol fired from commandline like echo 'Rebol [] .... ' | rebol +q -s
?REBOL [] ...
). And release mode too.>> repeat i 100000 [if error? try [to word! join "w" i][ print i break ]] 29530 ;<--- this number depends on number of already defined words >> length? words-of system/words == 32893
do %tmp.red
in console, and it prints "compiled" if called on OS after compilation.write %tmp.red {Red [] #either get in system 'state [print "console"][print "compiled"] }
>> do %tmp.red console >> call/output "tmp" out: "" out == "compiled^/"
system 'state
#do [compiled: to logic! rebol] #either compiled [ #include %compiled.red ] [ #include %not-compiled.red ]
#either
needs 2 blocks, I see only one there. And if you use get in system 'state
then first block is for interpreter, second for compiler. But if you use to logic! rebol
then *vice versa*.>> find any-function! native! == true >> b: [one two three] == [one two three] >> find b 'two == [two three]
>> view [t: title "hello" size 600x333 button [append t/text " world"]] *** Script Error: VID - invalid syntax at: [title "hello" size]
view/options [..] [text: "hello"]
view/flags [ title "Hi" button "Change title" [ view/flags [ title "Change window title" below text "New title:" title: field 150 focus across button "OK" [system/view/screens/1/pane/1/text: title/text unview] button "Cancel" [unview] ] 'no-buttons ] ][no-min no-max]
faced
?title
but text
, if you access it programmatically. title
is dialected marker for window's text
facet.title
is special, and not a face in the layout that you can reference. So you can't have a set-word before it in VID. But you could do it this way, in addition to @toomasv's example:t: "Hello" view [title t size 600x333 button [append t " world"]]
load
and save
I can get a static image saved, the first frame maybe, but not the whole animation. I'm calling curl as a workaround, but I'm curious if there's a way using only Red.> my-gif: read/binary https://bestanimations.com/Nature/Water/wave-ocean-animated-gif-14.gif == #{ 4749463839619301E300F7FF00124559296577A3AAAD65727A77A9B536778777 95991A6F... >> write/binary %purty my-gif
my-gif: read/binary https://bestanimations.com/Nature/Water/wave-ocean-animated-gif-14.gif write/binary %purty.gif my-gif ; <----
suffix?
on the link and rejoined it to the name my script wanted to save the image as. I was playing around with an idea for an offline rss reader, and that would require handling many different image types. But my script is too complicated and doesn't handle edge cases well. Yesterday I saw an example of an xml parser in Rebol using parse
so now I'm studying parse
before I start over again. :)Red [ needs 'view ] h: ["one" "two" "three"] c: [] repeat x length? h [ append c [ button 180x30 h/:x [ either face/color = papaya [ face/color: gray ] [ face/color: papaya ] ] return ] ] view [ panel [ do c ] ]
text: ["one" "two" "three"] code: [] foreach label text [ append code compose [ button 180x30 (label) [print face/text] return ] ] view code
Red [ needs 'view ] h: ["one" "two" "three"] c: [] repeat x length? h [ append c compose [ button 180x30 (h/:x) [ either face/color = papaya [ face/color: gray ] [ face/color: papaya ] ] return ] ] view [ panel [ ] c ]
win: layout code foreach face win/pane [ if face/type = 'button [ face/enabled?: false ] ] view win
on-button: func[face][ face/selected: not to logic! face/selected either face/selected [ uppercase face/text ][lowercase face/text] ] foreach label text [ append code compose [ button 180x30 (label) [on-button face] return ] ] view code
win: layout code
red >> layout [button "aha"] == make object! [ type: 'window offset: none size: 82x47 text: none image: none color: none ...
layout
is responsible for conversion of the DSL into tree of faces, which you can view using view
win: make face! [type: 'window size: 600x600 text: "My application"] btn: make face! [type: 'button size: 180x20 text: "Some button" offset: 10x10] win/pane: reduce [btn] view win
Red [ needs 'view ] h: ["one" "two" "three"] c: [] win: make face! [type: 'window size: 400x400 text: "win"] repeat x length? h [ append c compose/deep [ make face! [type: 'base size: 80x30 color: gray text:(h/:x) on-up: btoggle] ] ] probe c win/pane: reduce c btoggle: function [] [ foreach face win/pane [ probe face if face/type = 'base [ face/color: gray ] ] ] view win
labels: ["one" "two" "three"] btn-actors: object [ ; shared for all buttons on-up: function [face event] [ probe face/text face/color: random 255.255.255 ] ] win: make face! [ type: 'window text: "win" pane: copy [] ] pos: 10x10 foreach txt labels [ append win/pane make face! [ type: 'base size: 100x30 offset: pos color: gray text: txt actors: btn-actors ] pos/y: pos/y + 40 ] win/size: as-pair 120 pos/y view win
foreach-face
which can be a very handy iterator.foreach-face
does it thanks!Red [ needs 'view ] h: ["one" "two" "three"] c: [] repeat x length? h [ append c compose/deep [ base 180x30 (h/:x) [ foreach-face v [ if face/type = 'base [ face/color: gray ] ] face/color:papaya ] return ] ] v: layout [ panel [ ] c ] view v
labels: ["one" "two" "three"] code: [] selected: none on-button: func[face][ if selected [selected/color: gray] face/color: red selected: face ] foreach label labels [ append code compose [ base 180x30 (label) :on-button return ] ] view code
text: ["one" "two" "three"] code: [] selected: none on-button: func[face event][ either event/type = 'down [ face/color: pink ][ if selected [selected/color: gray] face/color: red selected: face ] ] foreach label text [ append code compose [ base 180x30 (label) on-up :on-button on-down :on-button return ] ] view code
repeat x length? h
and use foreach
instead!foreach
is better in this case, there are certainly times where repeat
is a better choice.foreach
that iterates over multiple series in parallel.function
placed in context/object are working, but words in system content not. I expected that I would not be able to change object from function
. It's bug or future?x: none a: [ y: none ] f: function[] [ a/y: "foo" x: "bar" ] f probe a ; was setted probe x ; still none
function
collects set-words (but not set-paths) in its body and makes these local by default (unless /extern
refinement is used for any of these). Use func
, then only args and words declared /local
are made local.response: try [send-request/data/with middleware-url-full 'POST parser-status [#("Content-Type" "application/json")] ]
/with "Headers to send with request" args [block! map!]
map!
or block!
:#("Content-Type" "application/json") or ["Content-Type" "application/json"]
parser-status
is a map!
or an object!
, it gets converted into JSON and Content-Type
is set automatically, so you do not set headers manually.call/wait/output
you mean?write/append %debug-log.txt "debug message"
print*: :print print: func [x][print* :x do-events/no-wait]
"[1,2,3,4]"
arr: [] foreach el split "[1,2,3,4]" "," [append arr el]
either error? response: try [send-request/data middleware-url-full 'POST parser-status ] [ print "baaaad" ] [ print "gooood" ]
not error?
but I am not sure that it's good ideathrow
inside lib it's user-defined? >> catch [if error? try [send-request/data middleware-url-full 'POST parser-status] [throw 'baaad] ] == baaad
attempt
? Is it suitable for it?throw
n? error!
, e.g.>> catch [if error? err: try [send-request/data middleware-url-full 'POST parser-status] [throw err/code] ] == 300
text-someting
or button-count
view [ do [ print "Start" return 1 print "End" ] ]
Start Start
return 1
, but there is some function that return valueview/no-wait [t: text "hello"] t/font/size *** Script Error: path t/font/size is not valid for none! type
? system/view/fonts
system/view/fonts/size: 20 view/no-wait [t: text "A"] ;; rendered as 9-point t/font ;; No value system/view/fonts/size ;; misleadingly says 20
gtk_text_view_set_tabs
[gtk-docs](https://developer.gnome.org/gtk3/stable/GtkTextView.html#gtk-text-view-set-tabs)str: {ok * just some str * yes*ok! test*ok} rule: [ not "*" keep to ["*" | " " | end] skip | thru "*" keep to "*" skip] probe result: parse str [collect[any rule]]
but I'd like:== ["ok" " just some str " "yes" "ok! test" "ok"]
`["ok" " just some str " "yes" "ok!" "test" "ok"]
"just some str"
).str: {ok * just some str * yes*ok! test*ok} rule: [ not asx keep to asx asx] asx: [any " " "*" any " " | end] result: parse str [collect[any rule]] ;== ["ok" "just some str" "yes" "ok! test" "ok"]
str: {ok * just some str * yes*ok! test*ok} rule: [ "*" keep to ["*" | end] e: opt [if (e/2 = #" ") skip] | keep to ["*" | " " | end] e: opt [if (e/1 = #" ") skip]] result: parse str [collect [any rule]] ;= ["ok" " just some str " "yes" "ok! test" "ok"]
str: { ok* just some str * yes*ok! test*ok ok } rule: [ "*" keep to ["*" | end] e: opt [if (e/2 = #" ") skip] | keep to ["*" | " " | end] e: opt [if (e/1 = #" ") skip]] result: parse str [collect [any rule]] == ["ok" " just some str " "yes" "ok! test" "ok ok "]
str: {ok * just some str * yes*ok! test*ok ok} rule: [ "*" keep to "*" skip | keep to ["*" | " " | end] e: opt [if (e/1 = #" ") skip]] result: parse str [collect [any rule]] ;== ["ok" " just some str " "yes" "ok! test" "ok" "ok"]
a
, but the button can't see b
after its set in the event. It seems like anything set in the event is a copy.Red [ needs 'view ] a: "aye" b: "bee" v: layout [ panel 400x70 [ f: field 180x30 a button 180x30 "check b" [ f/text: b ] ] ] view/options v [ menu: [ "change it" [ "change b" changeit "change back to a" changeitback ] ] actors: object [ on-menu: function [face event] [ switch event/picked [ changeit [ b: "buh" f/text: b ] changeitback [ f/text: a ] ] ] ] ]
sum
missing in very old builds, if unset? get/any 'sum [...]
might check how transcode
worked differently in older buildsabout
introspects for build information.system/build/date
should be enough.f: func[] [print "hello"] view [ do [f] ]
f
infinity times every 5 seconds? view
?forever [wait 5 print "hello"]
wait
does not work currently in gui-consoleRed [ needs 'view ] node: context [ name: "one" ui: [ panel 120x50 50.50.55 loose [ t: field 60x30 name ] ] ] n: [] ;; nodes nl: [] ;; instances of node ui to display view [ below p: panel 40.40.45 [ ] button "make node" [ append n copy node append nl n/(length? n)/ui ;; this seems to copy ui not instance it p/pane: layout/only nl ] button "change text" [ probe n/1/ui n/1/name: "two" ] ]
button "change text" [ probe n/1/ui append clear n/1/name "two" ]
button "change text" [ probe n/1/ui change/part n/1/name "two" 3]
0:00:00.0129937
to float!
. Seconds are the integer part, so less than that truncates when converted.Red [ needs 'view ] node: context [ name: "one" ] view [ field options [text: node/name] on-change [ probe node/name ] button "change node name" [ node/name: "two" probe node/name ] ]
node: reactor [name: "one"] view [ field with [text: node/name] react [face/text: node/name] button "change node name" [node/name: "two" probe node/name] ]
Options
doesn't work the way you think it does. See https://github.com/red/docs/blob/master/en/view.adoc#options-facetRed [ needs 'view ] node: reactor [ name: "one" idx: "100" ] view [ field with [ text: node/name ] on-change [ print [ "node/name after name on-change: " node/name ] ] react [ face/text: node/name print [ "node/name after name react: " node/name ] ] field with [ text: node/idx ] on-change [ print [ "node/idx after idx on-change: " node/idx ] ] react [ face/text: node/idx print [ "node/idx after idx react: " node/idx ] ] button "reset" [ node/name: "one" print [ "reset: " node/name ] node/idx: "100" print [ "reset: " node/idx ] ] ]
Red [ ] n: [ "one""two" ] u: compose [ n/(length? n) ] probe u
compose
. Try instead reducing, or put parens around n/(...)
.n/2
, i.e. intermediate result. You need to use to path!
. (Can’t try, on phone.)n: ["one" "two"] u: reduce [to-path reduce ['n length? n]] ;== [n/2] get first u ;== "two"
pic: make image! [94x178 #{ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF..... goes on forever
#include
the giant block ;)png
format to make it smaller#macro [#embed-image file!] func [s e] [compose [load/as (read/binary s/2) (select [%.jpeg 'jpeg %.jpg 'jpeg %.png 'png %.gif 'gif] suffix? s/2)]] img: #embed-image %/file/path.ext
Red [ needs 'view ] node: reactor [ color: 50.50.50 name: "one" ] view [ below field 200x30 with [ text: node/name ] on-change [ print [ "is text>text changing node?" node/name ] ] react [ face/text: node/name ] c: base 200x200 with [ color: node/color ] react [ face/color: node/color print [ "basecolor reacts to change in node: " node/color ] ] across slider 140x30 with [ data: node/color/1 / 255.0 ] on-change [ print [ "is float>tuple-component changing node?" node/color ] ] react [ face/data: node/color/1 / 255.0 ] field 50x30 with [ text: to-string node/color/1 ] on-change [ print [ "is text>tuple-component changing node?" node/color ] ] react [ face/text: to-string node/color/1 ] ]
node/color
so I don't know what reactions you expect. https://www.red-lang.org/2016/06/061-reactive-programming.html has a slider example. Here I just added a timer to change the node color, and you can see the other faces update as it does.Red [ needs 'view ] node: reactor [ color: 50.50.50 name: "one" ] view [ below field 200x30 with [ text: node/name ] on-change [print [ "is text>text changing node?" node/name ]] react [ face/text: node/name] c: base 200x200 rate 0:0:2 with [ color: node/color ] react [ face/color: node/color print [ "basecolor reacts to change in node: " node/color ] ] on-time [node/color: random 255.255.255] across slider 140x30 with [ data: node/color/1 / 255.0 ] on-change [ print [ "is float>tuple-component changing node?" node/color ] ] react [ face/data: node/color/1 / 255.0 ] field 50x30 with [ text: to-string node/color/1 ] on-change [ print [ "is text>tuple-component changing node?" node/color ] ] react [ face/text: to-string node/color/1 ] ]
Red [ needs 'view ] node: reactor [ name: "one" idx: "100" ] view [ field with [ text: node/name ] on-change [ print [ "node/name after name on-change:^/" node ] ] react [ face/text: node/name print [ "node/name after name react: " node/name ] ] field with [ text: node/idx ] on-change [ print [ "node/idx after idx on-change:^/" node ] ] react [ face/text: node/idx print [ "node/idx after idx react: " node/idx ] ] button "reset" [ node/name: "one" print [ "reset: " node/name ] node/idx: "100" print [ "reset: " node/idx ] ] ]
Red [ needs 'view ] node: reactor [ color: [80 50 50] name: "one" ] view [ below field 200x30 with [ text: node/name ] on-change [ print [ "is text>text changing node?" node/name ] ] react [ face/text: node/name ] c: base 200x200 with [ color: to-tuple node/color ] react [ face/color: to-tuple node/color print [ "basecolor reacts to change in node: " node/color ] ] across slider 140x30 with [ data: node/color/1 / 255.0 ] on-change [ print [ "is float>tuple-component changing node?" node/color ] ] react [ face/data: node/color/1 / 255.0 ] field 50x30 with [ text: to-string node/color/1 ] on-change [ print [ "is text>tuple-component changing node?" node/color ] ] react [ face/text: to-string node/color/1 ] ]
node/color/1
doesn't, and confusing changes to a series vs a non-series value. That is text
is a series, and the field
refs the same string series as the name
in node
. But when you say data: node/color/1
you are *not* ref'ing node/color
(the block), but the single integer value. And that won't trigger reactions. You need to do something like node/color/1: to integer! 255 * face/data
in slider on-change
.clear-reactions node: deep-reactor [ color: 80.50.50 name: "one" ] view [ below field 200x30 with [text: node/name] on-enter [ print [ "is text>text changing node?" node/name ] ] c: base 200x200 react [ print [ "basecolor reacts to change in node: " face/color: node/color ] ] across slider 140x30 on-change [ node/color/1: to-integer face/data * 255 print [ "is float>tuple-component changing node?" node/color] ] react [ face/data: node/color/1 / 255.0 ] field 50x30 on-enter [ node/color/1: face/data print [ "is text>tuple-component changing node?" node/color ] ] react [ face/text: to-string node/color/1 ] ]
basecolor reacts to change in node: 200.50.50 (base reaction)
is float>tuple-component changing node? 200.50.50 (slider on-change)
slider reacts to node change: 200.50.50 (slider reaction)
number field reacts to node change: 200.50.50 (field reaction)
basecolor reacts to change in node: 200.50.50 (base reaction, again)
number field reacts to node change: 200.50.50 (field reaction, again)
is text>tuple-component changing node? 200.50.50 (field on-change)
basecolor reacts to change in node: 80.50.50
basecolor reacts to change in node: 180.50.50 is text>tuple-component changing node? 180.50.50
basecolor reacts to change in node: 180.50.50 Slider reacted Field2 reacted is text>tuple-component changing node? 180.50.50
transcode/scan
not catching \
in this app?scan: func [fld][ either error! = transcode/scan fld/text [fetch-txt/data: "doh!"][fetch-txt/data: copy ""] ]
view [ below f1: field 200 "Very long string" f2: field 200 focus data [change "Very" ("Not so") | change "Not so" ("Very")] on-enter [parse f1/text face/data] ]
view [ button "Menu" with [ menu: ["Test" test]] [ ;; trigger menu ? ] on-menu [ if event/picked = 'test [ print "Test" ] ] ]
X
and Y
, which are slow, than to use [A B V D E ...]
in order of performance. This is a *great* topic for a wiki page, because we can collect information and easily annotate and update it as people explore.do load face/text
means any text is a live wire.Do
is unsafe with untrusted data, but if you need to evaluate any legal Red, then you have no choice. The alternative is to write a dialect and make sure it conforms to that (limited and safe) content.#include %caddy.png
`include
had a binary option, which would be nice. Even nicer would be a smart include, since we have codecs that *do* understand image files. For some reason I thought that might work. include
worked with codecs, it would turn relatively small PNG into a huge uncompressed bitmap which is not desirable IMO.include
worked with codecs, it would turn relatively small PNG into a huge uncompressed bitmap which is not desirable IMO.to-image read/binary ...
, but I agree with rebolek, that it is not a good idea.save/jpeg
thereparent
in the node?node
is like a transistor, you can model everything with it in theory. Node has 3 connections. Join 2 nodes and you get 4 connections. Join 3 and you get 5, etc.data-payload
would have a link to parent node.'Sometext'
situations. I'd speculate that any solution would need to scan well within such a function (as it stands, I have trouble unpicking my code there which is why it's still in the experimental bucket)object [a: b: c:]
= 470 bytes vs node = 16 bytes (probably 32 if we embrace the 64-bit addressing everyone is so obsessed with).#macro [#embed-image file!] func [s e] [ compose [ load/as (read/binary either rebol [s/2][system/options/path/(s/2)]) (select [%.jpeg 'jpeg %.jpg 'jpeg %.png 'png %.gif 'gif] suffix? s/2) ] ] img: #embed-image %file.ext
#macro [#embed-image file!] func [s e /local p x] [ p: s/2 if #"/" <> p/1 [insert p either rebol [first split-path to-rebol-file last system/options/args][system/options/path]] x: select [%.jpeg 'jpeg %.jpg 'jpeg %.png 'png %.gif 'gif] suffix? s/2 compose [load/as (read/binary p) (:x)] ]
#resource
is an interesting idea @loza:matrix.org.Red [] #do [? system/options ? system/script]
Red [ needs 'view ] aa: make font! [ name: "consolas" color: 30.30.40 size: 12 style: 'bold ] bb: make font! [ name: "consolas" color: 255.180.80 size: 10 style: 'bold ] m: 10x10 label: compose/deep [text (m) "title" font (aa)] redraw: func [] [ n/draw: label probe label ] view [ below n: base 300x100 draw [] button "change font" [ label/font: bb redraw ] do [ redraw ] ]
#! /usr/local/bin/red Red [ Needs: 'View ;' ] txt: {A key problem of software development today is software bloat, where huge toolchains and development environments are needed in software coding and deployment. Red significantly reduces this bloat by offering a minimalist but complete toolchain. This is the first introductory book about it, and it will get you up and running with Red as quickly as possible (Ivo Balbaert).} win: layout [title "System Fonts" button "Fonts"[ ft: request-font ar/font/name: ft/name ar/font/size: ft/size ar/font/style: ft/style sb/text: ft/name f/text: form ft/size sl/data: to-percent (ft/size / 100.0) ] text 40 "Size" sl: slider 70 [sz: to-integer 1 + (face/data * 99) f/text: form sz ar/font/size: sz ] f: field 40 drop-list 70 data ["black" "blue" "green" "yellow" "red"] react [ar/font/color: reduce to-word pick face/data any [face/selected 1]] select 1 button "Quit" [Quit] return ar: area white 400x400 txt font [name: "Arial" size: 12 color: black] return sb: base 400x20 white "Arial" do [sl/data: 0.12 f/text: "12"] ] view win
tail
but it need so specify size>> stack: [a b с d] == [a b с d] >> skip tail stack -2
copy series
^take/last
from a copy of the series?all-but-last: func [s] [copy/part back tail s -99999999]
init: func [blk][unless empty? blk [difference blk to-block last blk]]
difference
is a set operation, so you'll lose any duplicate values.Parse
version:tv-all-but-last: func [series][head clear back tail copy series] gi-all-but-last: function[series][new-s: copy series take/last new-s new-s] bm-all-but-last: func [s] [copy/part back tail s -99999999] gt-all-but-last: func[series][parse series[copy s to[skip end]]s] tv: [tv-all-but-last blk-1 tv-all-but-last blk-2] gi: [gi-all-but-last blk-1 gi-all-but-last blk-2] bm: [bm-all-but-last blk-1 bm-all-but-last blk-2] gt: [gt-all-but-last blk-1 gt-all-but-last blk-2] blk-1: [1 2 3 4 5 6 7 8 9 10] blk-2: head insert/dup copy [] 0 1'000 profile/count/show [tv gi bm gt] 1'000
Time | Time (Per) | Memory | Code 0:00:00.006 | 0:00:00 | 16304608 | gi 0:00:00.007 | 0:00:00 | 16184856 | bm 0:00:00.008 | 0:00:00 | 16216596 | tv 0:00:00.168 | 0:00:00 | 16184440 | gt
parse
stay constant as the series size grows, as expected. Parse
slows down, but is the most straightforward to read. to [skip end]
may take a second to understand, it's nice and concise.>> all-but-last: func [series] [copy/part series back tail series] == func [series][copy/part series back tail series] >> all-but-last [1 2 3 4 5 6] == [1 2 3 4 5]
func [s] [reverse remove reverse copy s]
(recalled an old Toomas' trick ;)(to-integer a/2)
intacta: [ "1" "2" "3" ] b: compose [ (to-integer a/2) + 1 ] do b
list: [lots: []]
list: [] stack: [lots] append list reduce [to-set-path stack [] ] probe list [lots: []]
>> list/lots == none
list/1 = 'lots
is false>> probe list [lots: []] == [lots: []] >> >> type? list/1 == set-path! >> >> list/1 == lots:
append list reduce [to-set-path stack [] ] ---------------------------^
layout
. If flowing, @hiiamboris has worked on it. My old little experiments are [here](https://github.com/toomasv/learning/tree/master/styles).panel 2 [button button field field]
value: copy []
>> d: [] >> append d compose [values: (copy []) ] == [values:] >> append d reduce [values: copy [] ] == [[]]
? compose
>> list: [] == [] >> >> append reduce to-path compose [list] [values: copy [] ] == [values: copy []] >> list == [values: copy []]
>> append reduce to-path compose [list] [values: [] ] == [values: [] values: []] >> append list/values 'aa == [aa] >> >> list == [values: [aa] values: []]
copy
? compose
syntax>> compose [list] == [list]
compose
here. There's no paren!
so compose
has no job here. Just slows things down a bit.append reduce to-path compose [list (word-parent-name)] [values: [] ]
>> list == [lots: [values: [] columns: []] lot: [values: [] columns: []] ob: [values: [] columns: []]] >> >> list/lots == [values: [] columns: []] >> >> append list/lots/values 'aaa == [aaa] >> >> list == [lots: [values: [aaa] columns: []] lot: [values: [aaa] columns: []] ob: [values: [aaa] columns: []]]
copy/deep
copy/deep [values: []]
("aa", "bb", "cc", "aa")
join
-like function. As it's not still part of Red, you need to write one yourself. Here's one example:join: function [series delimiter][collect/into [keep first series foreach value next series [keep delimiter keep value]] copy ""]
join
function to add parens automatically>> replace/all mold to-paren ["aa" "bb" "cc"] " " ", " == {("aa", "bb", "cc")}
to-paren
too.["a a" "b b" "c c"]
? :-D["a a" "b b" "c c"]
? :-D>> replace/all mold to-paren ["a a" "b b" "c c"] {" "} {", "} == {("a a", "b b", "c c")}
replace/all mold to-paren ["a a" "but this text will confuse your solution again, so what now?" "c c"] {" "} {", "}
rule: [["}" | {"}] " " ["{" | {"}]] replace/all mold to-paren ["a a" "but this text will confuse your solution again, so what now?" "c c"] rule {", "} == {("a a", "but this text will confuse your solution again, so what now?", "c c")}
>> replace/all mold to-paren ["a a" {boom, "boom", "boom"} "c c"] rule {", "} == {("a a", "boom, "boom", "boom"", "c c")}
rule: [collect any [s: skip keep (mold s/1) [end | keep (", ")]]] head insert next "()" rejoin parse ["a a" {boom, "boom", "boom"} "c c"] rule == {("a a", {boom, "boom", "boom"}, "c c")}
> >> replace/all mold to-paren ["a a" {boom, "boom", "boom"} "c c"] rule {", "} > == {("a a", "boom, "boom", "boom"", "c c")} >
>> replace/all mold to-paren ["a a" {boom, "boom", "boom"} "c c"] rule {", "} *** Script Error: rule has no value *** Where: replace *** Stack: replace
rule
defined above> tv-all-but-last: func [series][head clear back tail copy series] > gi-all-but-last: function[series][new-s: copy series take/last new-s new-s] > bm-all-but-last: func [s] [copy/part back tail s -99999999] > gt-all-but-last: func[series][parse series[copy s to[skip end]]s] > > tv: [tv-all-but-last blk-1 tv-all-but-last blk-2] > gi: [gi-all-but-last blk-1 gi-all-but-last blk-2] > bm: [bm-all-but-last blk-1 bm-all-but-last blk-2] > gt: [gt-all-but-last blk-1 gt-all-but-last blk-2] > > blk-1: [1 2 3 4 5 6 7 8 9 10] > blk-2: head insert/dup copy [] 0 1'000 > profile/count/show [tv gi bm gt] 1'000 > >
init: func [blk][reverse next reverse copy blk]
>> res: init [1 2 3 4 5] == [1 2 3 4] >> head res == [5 1 2 3 4]
copy
.copy
even when not needed, to be safe from mutations, then remove them as @giesse noted. From there you can look at things like /into
or using clear
instead of copy
for local series in func that may benefit. Preallocating a series can make a *huge* difference. I don't know what other langs let you do that if they're based on immutability.block: ["comedy" "romance" "romantic comedy"]
res: {Comedy - Romance - Romantic comedy}
res: copy "" block: ["comedy" "romance" "romantic comedy"] repeat i length? block [ either i <> length? block [ append res rejoin [uppercase/part block/(i) 1 { - }] ][ append res rejoin [uppercase/part block/(i) 1] ] ] probe res
map-each
it's useful other places.map-each: function [ "Evaluates body for each value(s) in a series, returning all results." 'word [word! block!] "Word, or words, to set on each iteration" data [series! map!] body [block!] ] [ collect [ foreach :word data [ if not unset? set/any 'tmp do body [keep/only :tmp] ] ] ] block: ["comedy" "romance" "romantic comedy"] block: map-each str block [uppercase/part str 1] res: first block collect/into [ foreach val next block [ keep " - " keep val ] ] res
uppercase
part), and a delimiter, and you have a generic modifier+combiner.delimit
func for R2 that did one step, so then you could rejoin
or reform
your block easily. But it used forskip
which we don't have in Red. Forskip
was handy, but not heavily used, so we have to decide if it's worth including in Red.res: copy "" block: ["comedy" "romance" "romantic comedy"] repeat i length? block [ append res rejoin either i <> length? block [ [uppercase/part block/(i) 1 { - }] ][ [uppercase/part block/(i) 1] ] ] probe res
uppercase/part block/(i)
is repeated, and try to eliminate that duplication.res: copy "" block: ["comedy" "romance" "romantic comedy"] repeat i length? block [ append res uppercase/part block/(i) 1 if i < length? block [append res { - }] ] probe res
append res
calls. It eliminates rejoin
though, which is a win because now you're not allocating a block and throwing it away every time.res: ... append res
dance and see if collect
is a good fit.block: ["comedy" "romance" "romantic comedy"] res: collect/into [ repeat i length? block [ keep uppercase/part block/(i) 1 if i < length? block [keep { - }] ] ] copy "" probe res
append res
is just keep
so not as bad when used more than once.rejoin parse block [collect some [set s skip keep (change s uppercase s/1 s) [end | keep (" - ")]]] == "Comedy - Romance - Romantic comedy"
join
. It's different than join
in Rebol, but that one wasn't very useful.altjoin: function [block delim /alter fn][ rejoin parse block [collect some [set s skip keep (if :fn [s: fn s] s) [end | keep (delim)]]] ] altjoin/alter ["comedy" "romance" "romantic comedy"] " - " :uppercase ;== "COMEDY - ROMANCE - ROMANTIC COMEDY" altjoin/alter ["comedy" "romance" "romantic comedy"] " - " func [s][change s uppercase s/1 s] ;== "Comedy - Romance - Romantic comedy" altjoin/alter [<comedy> "romance" %romantic-comedy] " - " func [s [any-string!]][change s uppercase first s s] ;== <Comedy - Romance - Romantic-comedy>
if
>> a: "text" == "text" >> >> if (type? a = block!) [print "a is block"] a is block
()
are evaluated to true not depend of it's type? "?"
in console.res: copy block/1 foreach item next block [append res rejoin [" - " item]]
copy/part mark: skip replace/all mold block {" "} { - } 2 skip tail mark -2
form load replace/all mold block {" "} { - }
;----------------------------------------------------------------------- ; PERMUTATIONS (No duplicates per group. The groups are 1234 1234 1234) ;----------------------------------------------------------------------- permutationsblock: copy [] permutations: 0 repeat a 4 [ repeat b 4 [if (a = b) [continue] repeat c 4 [if (c = b) or (c = a) [continue] repeat d 4 [if (d = c) or (d = b) or (d = a) [continue] repeat e 4 [ repeat f 4 [if (f = e) [continue] repeat g 4 [if (g = f) or (g = e) [continue] repeat h 4 [if (h = g) or (h = f) or (h = e) [continue] repeat i 4 [ repeat j 4 [if (j = i) [continue] repeat k 4 [if (k = j) or (k = i) [continue] repeat l 4 [if (l = k) or (l = j) or (l = i) [continue] rec: copy "" append rec reduce [a b c d e f g h i j k l] append/only permutationsblock rec ;probe permutationsblock ; DO NOT USE THIS! BECAUSE OF PRINTING THIS LASTS FOREVER! permutations: permutations + 1 ]]]] ]]]] ]]]] ;----------------------------------------------------------------------- ; print ["Permutations - no repetitions:" permutations] ;----------------------------------------------------------------------- write/lines %permutations-no-repetitions-4x3.txt permutationsblock ;----------------------------------------------------------------------- ; wait 3 ; is this needed? (because i think that a slower systems needs time to write a file ;----------------------------------------------------------------------- call "start notepad permutations-no-repetitions-4x3.txt"
The number of permutations is: (4*3*2*1) * (4*3*2*1) * (4*3*2*1) = 13824
wait
. OS does everything for you.product A product A A
, just instead of making 2-tuples (A,1)
you concat values into a string ;)if key not in my-map: my-map[key] = []
if not select my-map key [ extend my-map [key []]]
but I can not seem to get the code to evaluate key
. Instead the map ends up with a key that is literally key
(I believe as a symbol?).not select
isn't the way: not find
is:>> m: #(key #[none]) == #( key: none ) >> not select m 'key == true >> not find m 'key == false
my-map/:key: []
is your assignmentmy-map/(key): []
put my-map key []
probe
to check intermediate resultsith-perm: function [a i] [ also a: copy a forall a [ swap a skip a i // n: length? a i: to 1 i / n ] ] fac: function [n][m: #(0 1) any [m/:n m/:n: n * fac n - 1]] all-perms: function [a] [ also r: make [] n: fac length? a repeat i n [append/only r ith-perm a i - 1] ] a: all-perms [1 2 3 4] b: all-perms [1 2 3 4] c: all-perms [1 2 3 4] permutations: 0 res: copy [] forall c [ forall b [ forall a [ append/only res rejoin [to-string c/1 to-string b/1 to-string a/1] permutations: permutations + 1 ] ] ] print ["Permutations:" permutations] repeat i permutations [ print res/(i) do-events/no-wait ]
record: function [mbytes exts] [ print ["magic-bytes" mbytes length? mbytes] print ["extensions" exts length? exts] foreach ext exts [ print ext if not find extensions-map ext [ extend extensions-map [ext []]] foreach mbyte mbytes [ print mbyte print extensions-map append select extensions-map ext mbyte ] ] ]
*** Script Error: append does not allow none! for its series argument *** Where: append *** Stack: record
ext
. I tried replacing extend with some of those ideas, and pulled out select
but. I'm messing something upselect
returns none when it does not find the key extend
?extend reduce [..]
to evaluate it manually but in your case it's an overkill)make-dlm-str
. Not very creative. recombine: cartesian-product: function [ "Returns the cartesian product of all sub-block combinations" blocks [block!] "Block of sub-blocks whose values you want to combine" /into "Collect into output accumulator" start [block!] "Output accumulator" /only "Keep block types as single values" ][ if not parse blocks [any block!][print "Not a spec block" halt] if none? start [start: copy []] collect [ either tail? blocks [keep/only start] [ foreach val first blocks [ either only [ keep recombine/into/only next blocks append/only copy start val ][ keep recombine/into next blocks append copy start val ] ] ] ] ]
pythagoras: function [ "Computes a side of a right triangle" a b c ; variables with each has a domain ][ ; Validate (counts how many none's there are) x: 0 if (a = none) [x: x + 1] if (b = none) [x: x + 1] if (c = none) [x: x + 1] either 1 <> x [ "ERROR: you need to define any of two non-negative variables" ][ ; Compute case [ a = none [ square-root ((c ** 2) - (b ** 2)) ; DOMAIN OF A ] b = none [ square-root ((c ** 2) - (a ** 2)) ; DOMAIN OF B ] c = none [ square-root ((a ** 2) + (b ** 2)) ; DOMAIN OF C ] ] ] ] print pythagoras 3 none none ; ERROR print pythagoras none none none ; ERROR print pythagoras none none 5 ; ERROR print pythagoras none 4 none ; ERROR print pythagoras 3 4 none ; 5.0 print pythagoras none 4 5 ; 3.0 print pythagoras 3 none 5 ; 4.0
,
from lisp when I should have been focused on what the specific functions were expecting and actually doing with their operands. Subtle differences but obviously important! Thus far I'm enjoying Red, though I'm pretty sure parse and I are destined for a love hate relationship.parse
you never go back. :^)backtrack
. solvable: func [ mx my ][ either ((gcd mx my) = 1) [ return true ][ return false ] ]
dirty-file
without having to split & reconstruct an absolute path?absfile: %/home/user/path/to/this/script/test.txt sp: split-path absfile relativefile: to-file rejoin [ "./" sp/2 ]
def findcombinations(array,n,sol,tt=[]): if (n== 0): tt.append(sol[:]) return for x in array: sol.append(x) findcombinations(array,n-1,sol,tt) del sol[-1] ; remove last item of a list? return tt To call the function use print(findcombinations([1,2],3,[]))
findcombinations: function [array n sol /with tt][ tt: any [tt []] either n = 0 [ append/only tt copy sol ][ foreach x array [ append sol x findcombinations/with array n - 1 sol tt clear back tail sol ] tt ] ] findcombinations [1 2] 3 [] ;== [[1 1 1] [1 1 2] [1 2 1] [1 2 2] [2 1 1] [2 1 2] [2 2 1] [2 2 2]]
findcombinations: func [array n sol] [ .... ] tt: copy [] findcombinations [1 2] 3 []
[:]
is copy
(slice with both start and end undefined) but I can't say at a glance why copying, if they're appending anywaymaxrows: 3 maxvalues: 3 display: ["1" "2" "3" "4" "5" "6" "7" "8" "9"] arrs: copy [] status: false repeat r maxrows [append arrs [1]] while [not status] [ total: 0 repeat r maxrows [total: total + arrs/(r)] if (total = (maxvalues * maxrows)) [status: true] repeat r maxrows[prin arrs/(r)] print [] ; printing change: true r: maxrows while [change and (r >= 1)] [ arrs/(r): arrs/(r) + 1 either (arrs/(r) > maxvalues ) [arrs/(r): 1 change: true][change: false] ; We can perform any inner loop calculation here arrs[r] r: r - 1 ] ]
glob
call/input
?nc -4kl 127.0.0.1 1212
on console 1 to listen to incoming connections.cmd_input: "FIRST line of input^/" call/input "nc 127.0.0.1 1212" cmd_input cmd_input: "SECOND line of input^/"
FIRST line of input
has appeared, but string SECOND line of input
never appears. Is there any way to feed input string after call to executable was made?call
function exits immediately after execution so second cmd_input
won't be ever passed to executable. call/wait
doesn't work either - it just blocks red script execution for some time and then call
returns zero exit code.a: {a list:^/* one^/* two^/* three^/end of * list^/another list^/* AAA^/* BBB^/end of the other list} parse a [ any [ to "^/* " change "^/* " "^/<li>" pre: [ to "^/" change "^/" "</li>^/" | to end change end "</li>" end ] :pre ] ] parse a [ any [ to "^/<li>" not "</li>^/<li>" change "^/<li>" "<ul>^/<li>" ] ]
s are allgood, but 2nd rule stops after 1st occurrencea list:<ul> <-------- allgood, found the ^/<li> <li>one</li> <li>two</li> <li>three</li> end of * list another list <------- but missing <ul> here <li>AAA</li> <li>BBB</li> end of the other list
p: (?? p)
into places where you think it failsnot "^/- "
always succeeds (or highlight rules that always fail)a list:<ul> <li>one</li><ul> <li>two</li><ul> <li>three</li> end of * list another list<ul> <li>AAA</li><ul> <li>BBB</li> end of the other list
Parse
is like PEG. Put your longest rules first.parse
, but it will be less frequent and more predictable. parse
. You'll get there. With many things in Red it is easier, and helps, to think through it like a human. e.g. you tell it to
and it dutifully and happily says "Got it". Then you say "but if you passed a newline, forget what I just told you and do this instead." "Whaaa. But I..."skip
)"ahead
sounds like your palto X
fails if the real match is the second+ X
in the filered/parse
room were gurus can chime in. copy/part skip my-series index size
is the right way to extract a subset of length size
starting at offset index
from my-series
, true?Skip
vs at
is often the question, which comes down to what intent you want to convey, based on how your index is used.>> blk: [1 2 3 4 5] == [1 2 3 4 5] >> skip blk 1 == [2 3 4 5] >> at blk 1 == [1 2 3 4 5]
at
is actually what I wanted. Skip eats a number of entries, meaning you need to skip 1 less than the index you want to start at. Subtle difference that would have taken me forever to figure out - thank you!space
to the rule field after the end of input is reached, to get it to work?on-changed
action from the other fields/controls tooreverse my-series remove my-series reverse my-series
the right way to remove the last item from my-series
?take/last series
:)text
areas data
updates right away.result-txt/data: mold parse/trace ... etc
> rule: [collect any [s: skip keep (mold s/1) [end | keep (", ")]]] > head insert next "()" rejoin parse ["a a" {boom, "boom", "boom"} "c c"] rule > == {("a a", {boom, "boom", "boom"}, "c c")} >
copy
happens: Look:f: function[str-blk] [ rule: [collect any [s: skip keep (mold s/1) [end | keep (", ")]]] str: head insert next "()" rejoin parse str-blk rule ] f [a b c] f [a b c]
== "(a, b, ca, b, c)"
f: function[str-blk] [ rule: [collect any [s: skip keep (mold s/1) [end | keep (", ")]]] str: head insert next copy "()" rejoin parse str-blk rule ]
parse ["aa" "bb" "cc"] [collect keep [some [ change {"} "'" | skip ] ] ]
f: function[str-blk] [ str: none rule: [collect any [s: skip keep (mold s/1) [end | keep (", ")]]] str: head insert next copy "()" rejoin parse str-blk rule ] f ["11.22.22" "some text here" "1.00" none]
"'data here'"
when you displayed it in the repl.>> data: ["aa" "bb" "cc"] == ["aa" "bb" "cc"] >> collect/into [keep "('" keep first data foreach value next data [keep "', '" keep value] keep "')"] copy "" == "('aa', 'bb', 'cc')"
system/view/metrics
that looks like it.hdiv/offset/y: (tabpanel/size/y - lowerpanel/offset/y) - (hdiv/height + tabpanel/tabheight)
39
for nowload
a script maintaining comments? I would like to access them while the script is a loaded Red block.
`makeRange: func [ a [number!] b [number!] step [number!]][ collect [i: a - step until [keep i: i + step i: b]] ]
dir
works great for just peeking). I finally found it in the rebol quickstart read %directory/
<- it's so direct and simple I just didn't even think to look there.read http://...
. It's the dictionary problem. If you don't know how to spell a word, how do you find it? If you only think of import net-lib
and make request ...
you can't see the road for the fog.help action!
you get a list, which is not organized if you don't know what to look for. But look at the code for a datatype and you'll see them broken out roughly by category: [general scalar bitwise series I/O]
. https://github.com/red/docs/blob/master/en/actions.adoc lists them by category.load %my-file.json
is hiding in plain sight.dir
works great for just peeking). I finally found it in the rebol quickstart read %directory/
<- it's so direct and simple I just didn't even think to look there.OGL (One Good Language)
. I stopped designing it when I found Rebol. Doesn't mean Red is your fit, but it will give you new tools for thinking no matter what.save %file.json obj
save
of course - I just.. love it :)write
.. we really do need a transition doc for we poor souls lolload-json %my-file.json
?help
doesn't have anything for json out of the box, maybe that's in a package?? save
needs an update to list JSON among codecs?>> extract system/codecs 2 == [png jpeg bmp gif json csv redbin]
>> save/as %test.json #(this: 2 that: 3) 'json *** Script Error: invalid /as argument: json *** Where: do *** Stack: save cause-error
save
applies right codec based on file extensions.about
output pls???
really give you the source code?!Red 0.6.4 for Windows built 21-Nov-2018/18:40:38-06:00 commit #755eb94
load
works, via the magic of codecs, but you can use load-json
as well if you prefer. Note that it works on strings, so you need to read
the file first to use it.system/args-list
would do this. First, is there a better way? Second, I can't seem to get that command to work. *** Script Error: cannot access args-list in path system/args-list
what am I messing up?system/options/args
(loaded) or system/script/args
(string). print mold words-of system
or try [this](https://gist.github.com/greggirwin/91dc1c3971998e0babeedba9f7e60bc5) for exploring.? system
, you'll get a nice overview.do/args
and you need to use system/script/args
in that scenario, which will then be just what you pass, string or block..\red.exe --no-console .\test.red testing this thing
with test.red ofRed [] print "why?" write %test.opt system/options/args
--no-console
?ls
or similar. For this particular guy I simply noticed that it was dropping me into a console and the why?
was appearing there. I mistakenly assumed the console was consuming args somehow. It didn't end up mattering but there's my story :).\red.exe test.red some different args
should work fine without ending up in a replwhy?
to appear in the console?--no-console
always drops me in a repl thoughprintf
or similar and just dump it to stdout - I was trying to debug why the file wasn't getting createdwrite
comes first. @qtxie, do you know what's happening inside with --no-console
? That is, why it doesn't write the file. --cli
interpreted, but if you haven't built the CLI console previously it will do that the first time.-c
and -r
. If you're not changing the runtime, -c
is fast because it doesn't have to recompile all that, only your script. -e
is also faster, and is useful with dynamic code that makes the compiler unhappy.read/as
supports? Specifically I have a file which violates the utf-8 spec, intentionally, and I'd really like to tell Red "just treat it like ascii and don't worry about it".read/binary
and then convert each byte to a char!
.difference
for series, very cool, but I'm wondering: is there a diff
like variation? These lines of this file are in this other file, these lines aren't, kind of thing? It would be great not to have to rely on diff itself, if possible.difference
might just do as strings are hashed by contentDifference
is a set operation. I did an LCS diffing+patch system long ago, and I think @toomasv has done one as well. It's not a quick or easy op, like sets, dynamic with high space complexity. But what I really got stuck on was performance (in R2) and then wanting to do more than strings. Same issue I have for AWK and such. I want to be able to work against blocks and structures. Diffing lines in Red is not nearly as powerful as diffing values could be.find
those in many cases. Interesting idea if diffing by lines is enough. Once you span lines all bets are off though.parse
appears to modify in place in the repl, is that not the case all the time? I have a while loop iterating over all of the parser rules I've made but when I print dirty-file
later there hasn't been a change (a couple parse rules do hit, proven by the print statement)foreach cleaner cleaners [ while [parse dirty-file do cleaner] [print cleaner] ]
split-shell: [to [begin-first: "error_reporting(0)" thru ; find the first error_reporting call where, "create_" thru "function';" end-first: ; both create_ and function follow to "$" begin-second: copy execute-var to equal-sign ; with the next variable thru "lave" thru [execute-var "();"] end-second: ; being executed after the string lave appears (change/part begin-first "" end-first) ; remove the first chunk (change/part begin-second "" end-second)] any skip] ; remove the second chunk cleaners: [... split-shell] clean-file: func [filename] [ dirty-file: read/binary to-file filename print [length? cleaners "cleaners loaded."] foreach cleaner cleaners [ while [parse dirty-file do cleaner] [print cleaner] ] dirty-file ]
change
command(change/part ...)
from parse's POV is "outside"change
and see if that helpsp: (?? p)
to see how far it getscleaned-file: clean-file rejoin [base-dir filename] print to-string cleaned-file
remove
need to be called during parsing? Before knowing where the beginning and end were?parse [.. remove rule..]
will be cleaner to look atclean-file
via a different function doesn't dereference the different cleaners. I can insert typos/invalid parse and it doesn't even blink. If I call clean-file
directly, things barf as expected.if true and parse "yes" ["yes"] [print "works"]
but,>> if parse "yes" ["yes"] and true [print "does not"] *** Script Error: and does not allow block! for its value1 argument *** Where: and *** Stack:
if (parse "yes" ["yes"]) and true [print "does"]
and
gets pulled out early during lexical parsing , I guess? Interesting piece of trivial :)help and
and
goes first. He looks and sees ["yes"] and says, "I can't have a block as my first argument"true
op!
has a higher precendence, thoughadd 1 2 * 3
is add 1 (2 * 3)
, not (add 1 2) * 3
.if and~ parse "yes" ["yes"] true [print "does"]
action!
so different precedence1
is an expression that evaluates to itself (so-called self-evaluating form, borrowing the terminology from Lisp), and 2 * 3
is a composite expression that evaluates to 6
, and the net result is 7
. That's quite straightforward.add 1 2 * 3
evaluates to 9
would violate applicative order, because, in such a case, the interpreter would only consider 2
as a sub-expression, disregarding 2 * 3
to which it belongs. There are some [evaluation modes](https://github.com/red/red/wiki/%5BDOC%5D-Guru-Meditations#literal-arguments-and-get-arguments) that functions support though. However, neither Rebol nor Red leverages them as much as they could.>> add*: func [x :y][add x y] == func [x :y][add x y] >> add* 1 2 * 3 ; could be 9 *** Script Error: * operator is missing an argument *** Where: catch *** Stack:
results-txt/data
in my little tool, and this delayed updating is driving me absolutely nuts...react
?#include
line and someone who wants to share my pain can run what I have right now.result-txt/data: append copy "Parse result: " mold parse/trace ... yadda yadda...
0.6.4
, on the first launch toolchain acts as an installer by doing the following:load/library
FFI.%AppData%
folder.red --help
output).--cli
) when you didn't even try it out yourself. Nor did you obviously try to read the --help
output which states the purpose pretty clearly: Run the command-line REPL instead of the graphical console.
I don't even know what to add to that phrase, it's so precisely written. I'm trying to direct you into more experimentation, because that's how people learn. And that just offends you instead. @9214 gave you an extensive answer, and you didn't bother to make the effort to understand it. That's not productive. Don't be afraid to ask, but have enough respect to do your own research first, and to consider what info we're offering instead of just dismissing it as too complex..\red.exe
, it will compile the GUI console. If you quit that new console, and type .\red.exe --cli
, it will compile the CLI console. From that point forward, the default console for the REPL for Windows is the GUI console. Interpreter will run through the CLI console with .\red --cli
--cli
option has no bearing on programs that you compile after the two consoles are built.*** stack smashing detected ***
mean?libc
bindings.map-each
, you can find it [here](https://gitlab.com/hiiamboris/red-mezz-warehouse/-/blob/master/map-each.red) along with some other experiments.print
uses while executing? I've noticed that when executing from the repl, nothing will be printed until control is returned to the repl :(print
-related, see https://github.com/red/red/issues/2627. Try CLI console instead.native-print: :print print: func [value [any-type!]] [native-print :value do-events/no-wait ()]
print
in the timer event)-d
) version of GUI console that prints both to the terminal and to it's GUI window.needs: view
then building cli console was described in red/bugs awhile agono-wait
the behavior has improved in some waysdo-events
loopprint
well enough. --cli
is your friend.print
with known caveats.dir-map: func [base-dir callback] [ foreach filename read to-file base-dir [ if ((back tail filename) = "/") [ dir-map rejoin [base-dir filename] :callback ] callback rejoin [base-dir filename] ] ]
dir-map: func [base-dir [file!] callback [any-function!]] [ foreach filename read base-dir [ file: rejoin [base-dir filename] if dir? file [ dir-map file :callback ] callback file ] ]
[file!]
after the first arg a type requirement @toomasv?? "dir"
help dir
unfortunately,>> ? dir USAGE: DIR 'dir DESCRIPTION: Display a directory listing, for the current dir if none is given. DIR is a function! value. ARGUMENTS: 'dir [any-type!]
help
was doinghelp help
to include a note about that?help
it tells you that you can do thathelp
and help help
help help
even come from? I never ever had the idea to type that inhelp 'word
gives me information about how to use that word. I wanted to know how to use help
so I asked for information about how to use that word. Not the expected thought process but seems a legitimate, and likely common enough to address, onehelp
would be about the system generally, not the specific command. Would be like print
without arguments showing help print
help
being an exception to the separation of command and help about it, it's obviously something people think differently about, but it is an oddity that wayfunction-spec: [into [opt legend any variable any refinement opt return opt locals-and-externs]] variable: [var opt type opt legend] var: [word! | lit-word! | get-word!] type: [ahead block! [into [ 'function! function-spec | some datatype-or-typeset ]]] datatype-or-typeset: [set typ word! if (find [datatype! typeset!] type?/word get typ)] legend: [string!] refinement: [not [quote /local | quote /extern] refinement! opt legend any variable] return: [quote return: type opt legend] locals-and-externs: [locals opt externs | externs opt locals] locals: [quote /local opt legend any variable] externs: [quote /extern opt legend any variable]
return
doesn't have to come in that order does it? any-word!
is the argument/local name, "string"
is for help
output of it, [typeset! datatype!..]
is what value types the argument accepts (defaults to default!
typeset).[string! | file!]
would not work, nor [string! file!]
. That said, I wanted to check: can you specify multiple allowable data types or is it a one vs everything choice?[string! | file!]
is a Parse syntax though, not for the function specfunction-spec: [opt legend any variable any refinement opt return opt locals-and-externs]
- I copy-pasted it from DiaGrammar and forgot to edit)spec: spec-of :find parse spec function-spec
find
because it has long spec.?
/ help
- do you know that pressing Tab
in the GUI console while you type gives you a list of all words starting with what you have typed? ? di
Tab
would give you difference dir dir? dirize distance? divide
- that way you wouldn't have missed dir?
help
notes :)help
itself. We could add real help to the GUI console menu as an option. That doesn't help the CLI console, but you can use one to learn for the other. We could also dump some top-line intro material on startup, but I think most people want a clean console after a very short time. That leads to things like --quiet
options, but that's more work for everyone after their bootstrap phase.console
function, it could have a help command, wrap the context, and let you do a few other things. Then the Help menu just calls console help
which dumps output; no fancy help dialog needed. Or we call the func console-help
so partial help
searches can find it for either word. dir?
as an example from one random newbie, knowing the difference between help dir
and help "dir"
would have been completely sufficient. In my opinion, how to use help
is probably the single most important piece of information you could convey to a new user. Having that presented in one form or another at all places a new user might look seems like the ideal way.help
as a component of information about how the repl itself works (or even just the sole piece of information), as that was something I ran very early in my use. I took it to mean "use help 'word
for all your needs" but clearly not everyone does. And in help help
as (for some at least) that was also a natural place to look.help
command as makes sense, imo. Just have to make sure to a) get the user there b) teach them how to use ithelp help
just pushes the problem around, and also becomes an exception to the behavior.help
command seems fairly small.Help
on any function shows the interface for that function, nothing more. If help help
reflects to show more usage information, that's an exception. If we do that, how do you see the spec for help
?>> ? help USAGE: HELP 'word DESCRIPTION: Displays information about functions, values, objects, and datatypes. HELP is a function! value. ARGUMENTS: 'word [any-type!] "Omit the word arg for HELP usage."
help 'word
at all. I thought it was "here is everything we think you should know about 'word
"Type HELP for starting information.
help
ENTERhelp "string"
and help "word"
)help
usage content as well, also easy.help()
it will show you a blurb about the repl and the help command (technically it drops you into a whole system and when you exit gives you the blurb about help). If you type help("a")
afterward, you'll see a short blurb helpfully indicating that you probably want help(str)
. When you run that you get a blurb about what it is, all the methods, usage information, etc.help string
offers what appears to be a list of functions which have string
in them. That's not the case but it was the assumption I took away when applying my experience with other help systems to what I initially experienced with Red's. help
: it's a mezzanine. You can see all the source, play, and create alternatives.help
is great, I don't see any need to change it. I simply wanted to advocate for a different perspective and a tweak in how one might stumble on proper usage based on pre-existing assumptions coming from other languages. I'm a newbie - one of the only things I can offer is a fresh perspective :)source
Source
doesn't return it for further use. It just prints it.source source
😉view compose [area (mold :rejoin)]
a: [ b: context [ bb: "one" ] c: context [ cc: "two" ] ] probe a/1/bb
compose
or reduce
to get a block with constructed objectsb: context [ bb: "one" ] c: context [ cc: "two" ] a: compose [ (b) (c) ] probe a/1/bb
a: context [ b: context [ mm: "one" ] c: context [ mm: "two" ] ] foreach n values-of a [ probe n/mm ]
help
- I just wanted to indicate that it's useful with help
too. I'm sorry if I've confused anyone.compose [ (b) (c) ]
is same like reduce [ b c ]
. Use compose
if you need to evaluate only some expressions or nested expressions (compose/deep
)>> a: #{} == #{} >> set a/this 1 *** Script Error: word! type is not allowed here *** Where: set *** Stack: >> put a "this" 1 *** Script Error: put does not allow binary! for its series argument *** Where: put *** Stack:
type? #{}
is your friendset a/this 1
would still be failing even though it's (now) a proper map?a/this
also doesn't work, returns none when "this" is set to 1set
native has arguments, one of em is called "word"none
to it, while it's typeset does not accept thatput
to get it in there>> a/this == 2 >> a == #( "this" 1 this: 2 ) >> a/this == 2 >> set a/this 2 *** Script Error: set does not allow integer! for its word argument *** Where: set *** Stack:
>> show-deep-trace [set a/this 2] a/this => 2 set 2 2 => *** Script Error: set does not allow integer! for its word argument *** Where: set *** Stack: show-deep-trace trace-deep rewrite rewrite-next
help help
come from?" it's the newbie docs! https://github.com/red/red/wiki/Beginner's-FAQglobal: "something"
and you're writing global: "other thing"
within a function
body? function/extern
remove the scoping affect of the function
declaration? Effectively making all references to variables, to include creations?, global in scope?usage
, description
, and arguments
for both /extern
and "normal" functions though/local
./local
comes right after the name of the argument I'm passing in. So that's a special case and everything else is global scope?function
collects set-words, there's another way to set global words (without writing set-words and then listing them in /extern) - can you guess what way is that? ;)/extern
refinement explicitly to enable writing to external scopes.function
definition and include /extern
after the specific variable you want to enable global scope for???
source as I expected/extern
refinement *in front* of the variable in a normal function definition. The ??
source didn't list it as a variable at all (all of the other variables, which read from global scope, were still listed). But it appears to have acted exactly as I expected: writing to it from the function did in fact affect the global scope variable./extern
refinement essentially a toggle saying "most variables are local or extern - I'll let you know the specific exceptions"?func
, then /extern
is just a refinement of your function (it only has a special meaning for function
native)function
words have local scope unless they follow /extern. func
words have global scope unless they follow /localhelp help
from wiki. It wasn't 100% clear.Function
's doc string gives you a clue, along with your earlier evaluation learning.scope
and variable
for comfort at times, and Rebol calls it "definitional scoping". What you have are words that refer to values in some context.func ['forced var]
the immediate next question is whether you can make that that 'forced word optional or not?global1: [] data: "a" a: func [data] [ global1: [] data: "b" ] b: func [tmp] [ append tmp "just one thing" print global1 a data ] b global1 b global1 b global1 b global1
b global1
calls result in that print
statement displaying first, two "just one things", then *one* "just one things", then two, then three.data
is "a"data: "b"
statement is doing?data
was initialized as a pointer to a block of memory wherein the string "b" was stored. Re-executing that command would either create a new string and change the pointer value or no-op depending on efficiency implementation behind the scenes. So, data: "a"
would absolutely result in a new string and a pointer update to data
for that new string.if condition [code]
or do [code]
or word: [data]
or word: "data"
, all the series here are treated equally, no exceptions[code]
block above every time it evaluates obviously, so it applies to what you consider "data" as well)char* s = "static data"
looks fine to most. meditate
is just fun syntactic candy around displaying an object.contexts:
creates what might be called namespaces in other languages. The concept is immediately stretched thin as the "namespaces" are literally stored in a block and bound to contexts
. In each, 'spoon
has been bound to a different string.shelf-with-spoon:
is a block of words. Each word assuming the current (global at this point) context and, as yet, entirely unbound.repeat i ...
is bonkers. A "namespace", context, is selected and forced onto a variable. A word, an unevaluated set of characters in a block, happen to have meaning in these different namespaces. When the word is evaluated, it is done so inside its (newly) assigned context.spoon
words are evaluated in that initial context? When the second gets its own context, the third is evaluated in it?append shelf-with-spoons [comma spoon]
global context spoon joined the gang but took his context with him. Except not quite because set 'spoon bind 'spoon copy third contexts
changes the context of the global spoon to be the third context. That context switch clobbers context for all references to the global spoon?bind back ...
is bonkers squared. This line is pulling apart the script itself, finding the binding, on line 57, to spoon in the global context, and binding that *context* to the last word in shelf-with-spoons?repeat i ...
binds, in each of their now independent contexts, a new meaning to each instance of the word spoon *and comma*. So now, in the.. third? context comma
is no longer ,
but instead RED
.; red' is a block of values, nothing more red': [ global1: [] ; global1 (red'/1) refers to red'/2 data: "a" ; data (red'/3) refers to red'/4 "A:" ; just a marker for output ( a: func [data] [ global1: [] ; global1 refers to this block after func a is evaluated. data: "b" ; data in this function is local, because it's an arg ; It doesn't change what red'/3 refers to ] ) "B:" ; just a marker for output ( b: func [tmp] [ append tmp "just one thing" print global1 a data ] ) probe reduce ["same? global1 red'/2 ?" same? global1 red'/2] b global1 probe reduce ["same? global1 red'/2 ?" same? global1 red'/2] b global1 b global1 b global1 ] print mold red' do red' print mold red' print mold :a
compose
on my first pass and thought they might help there. Same for the parens; not needed now.z: context [ b: true a: compose/deep [ d: (unless none? b [if b [ 'bold ]]) ] ] mold z
{make object! [^/ b: true^/ a: [d: bold]^/]}
{z: context [ b: true a: compose/deep [ d: (unless none? b [if b [ 'bold ]]) ] ]}
>> code: mold [ b: true a: compose/deep [ d: (unless none? b [if b [ 'bold ]]) ] ] == {[b: true a: compose/deep [d: (unless none? b [if b ['bold]])]]} >> z: context load code == make object! [ b: true a: [d: bold] ]
context
is evaluating)redbin
codec in Red, which should be more precise... but I have not tested it yet. red >> save/as bin: #{} code 'redbin == #{ 52454442494E020401000000D80000000A000000500000000000000008000000 100000001800000020000000280000003000000038000000400... >> load/as bin 'redbin == [b: true a: compose/deep [d: (unless none? b [if b ['bold]])]]
red >> code: reduce ['true true] == [true true] >> parse code [word! logic!] == true >> code2: load mold code == [true true] >> parse code2 [word! logic!] == false ;<--- because both are words! >> save/as bin: #{} code 'redbin == #{ 52454442494E0204010000002000000001000000080000000000000074727565 000000000500000000000000020000000F00000200000000D00... >> code3: load/as bin 'redbin == [true true] >> parse code3 [word! logic!] == true
mold/all
to prevent above.. but it's not fully implemented in Red yet.. and fails in cases like:>> mold/all next "aha" == {"ha"} ;<--- should be {#[string! "aha" 2]}
>> code: next "aha" == "ha" >> save/as bin: #{} code 'redbin == #{ 52454442494E0200010000001000000007010000010000000300000061686100 } >> code4: load/as bin 'redbin == "ha" >> head code4 == "aha"
object!
, error!
or function!
.[
and ]
instead of curly braces. This in turn makes them think that words are variables. And at this point, the learning curve turns into a roller coaster, and leads to an unsalvageable conceptual trainwreck.namespace1-yourvariablename
as it's explicit identifier. A variable can not exist without a namespace, nor can a variable exist in multiple namespaces. Shadowed variables are a result of compiler/interpreter's inability to guess which variable the programmer is referring to "by shorthand" ie - by what they think of as the variable's identifier. A context is not inexorably bound. It is, rather loosely, associated with a symbol.Contexts[particular-context][symbol-name] : value
. particular-context
being looked up for symbol-name
on every use (no model yet for how).particular-context
of any symbol in the system. As part of the language proper - no hacking needed.func
for example.Red [] dat: context [ cdx: 1 lst: [ "a" "list" "goes" "here" ] fnc: function [ ] [ print [ "my list is: " lst ] foreach l lst [ print [ "listitem =" l ] ] ] ] s: copy [] append s copy dat append s copy dat s/2/lst: [ "another" "list" "goes" "here" ] s/2/cdx: 2 foreach w s [ print [ "verifying original data"w/cdx":^/" w "^/" ] ] foreach w s [ print [ "verifying original func"w/cdx":" ] w/fnc print "^/" ] save/as bdat: #{} s 'redbin backwash: load/as bdat 'redbin foreach w backwash [ print [ "verifying restored data."w/cdx":^/" w "^/" ] ] foreach w backwash [ print [ "verifying resstored func"w/cdx":" ] w/fnc print "^/" ]
data: [ id: none lots: [ bar: none lot: [ name: none obj: [ price: none ] ] ] ]
data/(to-path [lots lot])
[lots lot]
) from outside and I want to prevent it from pollution. I tried also:stack: [ lots lot] to-path insert copy stack 'data
as path! compose [data (stack)]
find ["aabbccddee"] ["gg" "ee"]
true
find/any
was never implemented in Red, and it's for a different use caseFind/any
isn't the right solution anyway, as you're looking for multiple values, not wildcards.parse
? Difference from find
in loop is that with parse
you'll get whichever comes first, with find
the first one found, which might not be the same.I can read HTML headers in the REPL by doing:a: read/info http://rebol.com
`read/infofor reading the header
read/local/infoto read the beginning of the text of the page
a: { HTTP_REFERER=http://192.168.1.6/test.red HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 REMOTE_ADDR=192.168.1.251 }
z: load a
>> z: load a *** Syntax Error: (line 3) invalid word at html,application/xhtml+xml,app *** Where: catch *** Stack: load
get-headers
that will set global object http-headers
with parsed headers. It works both on POSIX (Linux, macos) and Windows. There are also other functions for working with Red as CGI, like process-input
that will parse both GET and POST data and convert them to Rebol values based on MIME type. And there are also functions for making response to the request you’ve received. If you look into the CASTR repository, there are other scripts, like [Mustache](https://mustache.github.io/) templating system and others."blah.blah"to
str
a: ["str" "blah.blah"] do rejoin [:a/1 {: } mold a/2] print str ==blah.blah
set load a/1 a/2
to word!
in place of load
, depending on how much you trust the first value being a good word. And if you don't need it to be a string, even better, e.g. a: [str "blah.blah"]
a: "test-123" b: split "test-123" "-" probe b == ["test" "123"]
a
is as close as you can get. Even if you use a space as your delimiter and load/to-block
instead of split
.>> f: func ['x [any-type!]][probe :x] == func ['x [any-type!]][probe :x] >> f unset >>
unset
here? As I know, unset
is native!
. Why here return a native!
? And Why not return unset!
?remove-each
and came up with this prime-sieve function:Red [ Title: "Prime-sieve using `remove-each`" Author: "Galen Ivanov" Date: 15-04-2021 Note: "Slow, impractical for real use, serves only as a demonstration of `remove-each`" ] prime-sieve: function [ "Finds the prime numbers less then or equal to n" n [integer!] "upper limit" ][ primes: make block! n / log-e n append primes 2 i: 1 odd-n: collect/into [ while [n >= i: i + 2] [keep i] ] make block! n / 2 while [not empty? odd-n] [ append primes prime: take odd-n remove-each odd odd-n [zero? odd % prime] ] primes ]
arity-of
https://gist.github.com/greggirwin/53ce7d1228422076e142fa5a061e7649 you can find quite a few versions packaged in various projects or in gist. arity-spec
which will loop through any refinements as well. https://github.com/rebolek/red-tools/blob/master/func-tools.red>> f: func [/local x /extern y /other z] [print [x y z]] == func [/local x /extern y /other z][print [x y z]] >> f/local/extern/other 1 2 3 1 2 3
function
:function
native treats /extern - externalizing everything after it[#MYTYPE DATA]
but I don't find anything about it. Is there such pseudo notation? >> start: now >> ? start START is a date! value: 19-Apr-2021/10:59:23-04:00 >> start/year 2021
? now
to get them, but I'm wondering if it's possible to get them from the variablesystem/catalog/accessors/date!
a: "testtest2"
? :)append a: "" "test2"
doesn't work for you?to-pair
. But what is the reverse? a pair to a block? to-block
does not give what I want.reduce [pair/x pair/y]
DO
on code block, I get error on functions like print
code: [print "x"] x: do code
>> code: [a: 2 + 2 b: 2 + 5] until [probe x: do/next code 'code tail? code] 4 7 == true
print
like function>> code: [a: 2 + 2 print "done"] until [probe x: do/next code 'code tail? code] 4 done *** Script Error: x: needs a value *** Where: x *** Stack: probe
X
to any returned value by the evaluation including unset!
?set/any
in that case.set/any
too >> a: make image! [2x2 #{D2417AFC71F15BA4FFFBB950}] == make image! [2x2 #{D2417AFC71F15BA4FFFBB950}] >> size? a *** Script Error: size? does not allow image! for its file argument *** Where: size? *** Stack:
a/size
?? a
? a
to viewlength? a
length? a/alpha
if you want *only* that channel.image!
.a: "01245678901234567890123456789" parse reverse reverse a [any [ 2 skip insert "," skip ]] print a ==01,245,678,901,234,567,890,123,456,789,
format
work [here](https://github.com/greggirwin/red-formatting). The func for what you want is this:set 'form-num-with-group-seps function [ "Insert group separators into a numeric string" num [number! any-string!] /with sep [string! char!] /every ct [integer!] ; /skip may be a better name, but conflicts with system/words/skip ][ num: form num ; Form strings, too, so they're not modified sep: any [sep #","] ct: negate abs any [ct 3] num: skip any [ find num deci-char num ; start at the decimal point, if there is one find/last/tail num digit ; or at the last digit (support, e.g., "123rd") tail num ; or at the end of the string ] ct while [not head? num] [ ; We want to catch cases where the preceding char is not a digit, ; and *not* insert a sep if that's the case. if find digit pick num -1 [ insert num sep ] num: skip num ct ] num ]
digit
is digit: charset "0123456789"
deci-char
is unfortunately more involved, as it sniffs for the char. You can simply use the known chars (.,
) directly though.to block!
is often used for that - to get a block with a single value. It's by design.parse reverse
.o: object [ name: 'foo ] data: [ id: 123 foo: [ bar: "hello" ] ] data/(o/name)
== [bar: "hello"]
data/(o/name)
data/foo
to-path
but I am getting wrong resultreduce
d:>> p: to path! reduce ['data o/name] == data/foo >> p == data/foo >> get p == [bar: "hello"]
reduce
d:> >> p: to path! reduce ['data o/name] > == data/foo > >> p > == data/foo > >> get p > == [bar: "hello"] >
parser-status: [ current-section: 'test ] data-templates: [ template-section-name: [ test: [ ; test section id: none lots: [ bar: none baz: none lot: [ name: none obj: [ price: none ] ] ] ;--------------------------------- ] ] ] p: to-path reduce [ 'data-templates data-templates/template-section-name/(:parser-status/current-section) ]
p: to-path reduce [ 'data-templates 'template-section-name parser-status/current-section ]
data-templates
point to data in data-templates2/template-section-name/'test_section_name/test_subsection
.reduce
it to get data to word from path
.data-templates
to needed path?parser-status: [ current-section: 'test_section_name ] sub_section_name: to-word 'test_subsection data-templates2: [ template-section-name: #( test_section_name: #( test_subsection: [ ; for test id: none lots: [ bar: none baz: none lot: [ name: none obj: [ price: none ] ] ] ;--------------------------------- ] ) ) ] data-templates: to-path compose [ data-templates2/template-section-name (parser-status/current-section) (sub_section_name) ] data-templates
>> do-clip == data-templates2/template-section-name/test_section_name/test_subsection >> data-templates data-templates2 >> do data-templates == [ id: none lots: [ bar: none baz: none lot: [ name: none ob... >> get data-templates == [ id: none lots: [ bar: none baz: none lot: [ name: none ob...
>> data-templates: do to-path compose [ data-templates2/template-section-name (parser-status/current-section) (sub_section_name) ] *** Script Error: path must start with a word: data-templates2/template-section-name/'test_section_name/test_subsection
red-14apr21-42d9d6a76
to-path
in my local setup.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 ]
to-word
here: sub_section_name: to-word 'test_subsection
but the lit-word in the path may be tripping things up. No time to dig in here, but if you can confirm that it would be great.to-path
uses clear
as an optimization, if you probe it, you'll see the last value in that '_/_
slot. e.g.>> ?? to-path to-path: func [spec][ load form append clear 'data-templates2/template-section-name/'test_section_name/test_subsection spec ]
clear
is a neat trick, this kind of thing can be *very* confusing to see, so I will probably change that.data-templates: do to-path compose [ data-templates2/template-section-name (parser-status/current-section) (sub_section_name) ]
sub_section_name: to-word 'test_subsection
to-word
isn't doing anything there.>> sub_section_name: to-word 'test_subsection == test_subsection >> sub_section_name: 'test_subsection == test_subsection
parser-status: [ current-section: 'test_section_name ] sub_section_name: 'test_subsection data-templates2: [ template-section-name: #( test_section_name: #( test_subsection: [ ; for test id: none lots: [ bar: none baz: none lot: [ name: none obj: [ price: none ] ] ] ;--------------------------------- ] ) ) ] data-templates: do to-path compose [ data-templates2/template-section-name (parser-status/current-section) (sub_section_name) ] data-templates
to-path
working, but I am afraid that later I will forget what problem it solve?to-path
at all, but you need to write more code to do that, so it's just a tradeoff. to-*
funcs are meant to be simple wrappers, so the behavior is consistent with the to
action for a type. If it is the lit-word value also causing a problem, here's what you can do to help us all. Document the types that cause issues with to path!
today. Then we can look at whether paths should be smarter about them, or if handling it at the mezzanine level is best.>> f: func [][print "hi"] >> set/any 'r f hi >> type? :r ** Script Error: r has no value ** Where: halt-view ** Near: type? :r >> type? 'r == word! >> type? r ** Script Error: r has no value ** Where: halt-view ** Near: type? r
>> f: func [][print "hi"] == func [][print "hi"] >> set/any 'r f hi >> type? :r == unset! >> type? 'r == word! >> type? r *** Script Error: r has no value *** Where: type? *** Stack:
value?
while the other option returns error. Red works better .UNSET!
from a function? I mean something like if true []
. Is there a way to say if true [unset!]
as the latter returns the datatype. UNSET!
as value? Let's say you want to transmit remotely the results of some functions, how do you send "there result of this function is no-result
/unset
"?()
make unset! []
unset!
into a function as a value, I would try to consider whether there is a better way, as it's a pretty volatile typea: read %/hd/loca/desktop
>> () >> if true [] >> either false ['yes!][]
none
instead.load
if it's a text file I have to use ```read```txt: read %./test.txt
`a: reverse "123456789012345678901234567890" parse a [any[3 skip insert ","]] print reverse a
,then remove it
a: reverse "123456789012345678901234567890" parse a [any[3 skip if not end (insert ",")]] print reverse a
a: reverse "123456789012345678901234567890" z: parse a [collect [any[copy a1 3 skip keep (a1) (append a1 ",") ]]] total: reverse rejoin z print total
z: parse a [collect [any[p: (d: min 3 length? p)copy a1 d skip e: (if not tail? e[append a1 ","]) keep (a1)]]]
a: reverse "123456789012345678901234567890" z: parse a [collect [any[copy a1 3 skip keep (a1) e: (if not tail? e[append a1 ","]) ]]] total: reverse rejoin z print total
a: reverse "123456789012345678901234567890" reverse rejoin parse a [collect any [keep 0 3 skip e: opt [if (not tail? e) keep (",")]]]
a: reverse "12345" reverse rejoin parse a [collect any [keep 3 skip [end | keep (",")]]] ;== ",345"
rejoin parse a[ collect [ (n: (d: length? a) / 3 - pick[1 0]d % 3 = 0) n [keep 3 skip keep (",")] keep to end ] ]
n: (length? a) - 1 / 3
?thousands: func [num [number! string!] /local int frac][ set [int frac] split form num dot parse reverse int [any [3 skip [end | insert ","]]] num: reverse int if frac [repend num [dot frac]] num ]
thousands: func [num][ parse reverse num: form num [opt thru "%" opt [thru dot] any [3 skip [end | insert ","]]] reverse num ]
num
happens to be percent...percent!
type>> round/to 0 0 *** Math Error: math or number overflow *** Where: round *** Stack:
>> round/to 0 1.#inf *** Math Error: math or number overflow *** Where: round *** Stack: >> round/to 0 -1.#inf *** Math Error: math or number overflow *** Where: round *** Stack: >> round/to 0 -1.#nan *** Math Error: math or number overflow *** Where: round *** Stack:
thousands
problem:thousands: func[num][ res: copy "" while [(length? num) > 3][insert res rejoin ["," take/last/part num 3]] head insert res num ]
>> thousands "123456789012345678901234567890" == "123,456,789,012,345,678,901,234,567,890" >> thousands "12345678901234567890123456789" == "12,345,678,901,234,567,890,123,456,789" >> thousands "1984" == "1,984" >> thousands "959" == "959" >> thousands "42" == "42"
reverse
at least :) round/to x 0
I encountered when formatting a number, so it's not a made up caseform
forms everything under 0.0001
in exponential mode, so I had to limit the rounding precision at that anywayround/to x 0
could return x
, round/to x inf or nan
- always nanround/to inf inf
may also return inf
... :/NaN
makes sense to return NaN
.Inf/-Inf
*could* return their respective values as pass-thru. What is the multiple of infinity? round/to non-inf-nan inf
should be nan, because we don't know which infinity is closerround/to x +inf
= +inf
, round/to x -inf
= -inf
by IEEE, if x is not nanround/to x 0
should return 0
, shouldn't it?x
, then a scale of 0 or 1 are equal. Also, the arg doc string says it must be a non-zero value. So they (you in this case) have at least been warned./to => Return the nearest multiple of the scale parameter. scale [number! money! time!] "Must be a non-zero value."
x
to me right now.0
as input -> log-10 0 = -inf
, so round/to 0 10 ** (-3 + to 1 log-10 0)
is same as round/to 0 0
... overflowx
. Time for me to make coffee. x
, correct?round
if needed. If Nenad still wants it to throw an error, with a good reason behind that choice, it's just a bit more work to check that case when we know it's possible because the scale is calculated.> >> () > >> if true [] > >> either false ['yes!][] >
none
instead.[ func1 none func2 1 func3 unset! ;Its a datatype! func4 "" func5 () ;It's empty parens func6 [] ;it's empty block ]
mold/all
->load do
does not return UNSET as value but as word:probe load mold/all ()
unset
as value.none
could be molded and later loaded, this is not possible for unset
.>> mold/all none == "#[none]" >> mold/all () == "unset" >>
>> save/as b: #{} () 'redbin == #{52454442494E0200010000000400000002000000} >> load/as b 'redbin
unset!
will have construction syntax, so mold/all
will support it.print
. x
to hold #[unset!]
, but than one day you will make in some huge code a bug, which could be simplified as f: does [x:] f
and without error you may end with several nice hours of debugging.system/ports
and a system/schemes
, I see that I can make port!, and I see a register-scheme
- but I'm not aware of any writings on ports[x: y: z:]
is even useful at object creation.>> b: copy/deep a: #(a: [1 2]) == #( a: [1 2] ) >> append a/a 3 == [1 2 3] >> b == #( a: [1 2] )
>> b: copy/deep a: #(a: "12") == #( a: "12" ) >> append a/a "3" == "123" >> b == #( a: "123" )
forall
, but why foreach do not set values?data: [ aa: none bb: none ] foreach [k v] data [ set 'v 123 ] probe data
; Keep used outside parse merges results as per default collect [ keep [x x] keep [y y] ] ; => [x x y y] ; With keep/only, elements are concatenated collect [ keep/only [x x] keep/only [y y] ] ; => [[x x][y y]] ; When used in parse dialect, it works like keep/only a: [x y] r: [ collect [ some [ copy v word! keep ( reduce [ v/1 v/1 ] ) ] ] ] parse a r ; => [[x x][y y]] ; Is there a way to have it merge elements instead ?
keep (v/1) keep (v/1)
for thata: [x 3] r: [ collect [ copy tag word! copy nb integer! keep ( res: copy [] append/dup res tag/1 nb/1 ) ] ] parse a r
a: [x 3] b: copy [] r: [ collect into b [ copy tag word! copy nb integer! ( res: copy [] append/dup res tag/1 nb/1 append b res ) ]] parse a r probe b
keep pick
would do that.make/copy
. Waiting for his thoughts.unset!
: http://www.rebol.net/r3blogs/0318.htmlstr: {dir:=/local~name:=/office.cvs~drawers:=/left-isle} print parse str [collect [some[copy a any to {:=} 2 skip copy b any to [{~} | end] skip keep (a) keep (b)]to end]] ==dir /local name /office.cvs
drawersand
left-isle
print parse str[collect[some[keep to ":=" 2 skip keep to ["~" | end] skip]]] dir /local name /office.cvs drawers /left-isle
str: {test:=123~atest:=545~testz:=098} parse str[collect[some[copy a to ":=" 2 skip copy b to ["~" | end] (set to-word a b) skip] ]] == test: 123 atest: 545 testz: 098
>> mark: [":=" | "~"] print parse str [collect any [keep to mark mark | keep to end]] dir /local name /office.cvs drawers /left-isle
case [ suffix = "txt" [ print "TXT" ] suffix = "csv" [ print "CSV" ] suffix = "html" [ print "HTML" ] suffix = ".DS_Store" [ print "SKIP IT..."] find name {/} [ print "DIR..." ] true [ print "unknown!!!"] ]
anyis better ?
case
is a good choice there.query_string: {test1:=ok1~test2:=ok2~test33:=yes} mark: [":=" | "~"] print parse query_string [collect any [copy a to mark mark | copy b to end] (set to-word (a b) ]
test1: "ok" test2: "ok2" test33: "yes"
set
.unset!
: http://www.rebol.net/r3blogs/0318.htmlset [a: b: c:] [1 2 3]
none
doesn't>> x: print now 23-Apr-2021/22:58:57+2:00 >> x ** Script error: x has no value
set/any
where you expect that #[unset!]
may appear? foreach
gladly sets anything to unsetget
behavior, not console behaviorforeach
gladly sets anything to unsetnone
>> foreach [a b c][1][reduce [a b c]] == [1 none none]
>> x
case, than you could write in the console whatever without such an error.foreach
does not throw an error>> set [x y z] reduce [() () ()] *** Script Error: x needs a value
>> x
case, than you could write in the console whatever without such an error.unset
is result from function like print
or from a word which has no value. unset!
in depth (which I'm sure you're all grateful for ;^), but it's an important design point to address clearly. I say this specifically with HOFs in mind.None!
propagates pretty far today IMO. It's confusing at times because it *is* a valid value.unset!
is dangerous if you don't know how it will be handled higher in the call chain.Unset!
is Red's NULL. How do people feel about NULL? We know what Hoare thinks.NULL
does not throw an errorunset
is result from function like print
or from a word which has no value. do/next
expressions in the input line and have a special case if it's last expression is word
none
is in default!
typeset, but not unset
)NULL
does not throw an errorunset!
. It's code that doesn't handle it which throws the error.none!
support was added to, as a convenience, because of things like select/find
and ordinals returning it rather than throwing an error as in R2. But in general, none!
is everywhere (which is OK, because that's part of its purpose). If we bless unset!
as equally valid, we don't know how widely it will end up being used, and for what purposes.>> rename %38.gif %39.gif *** Script Error: rename does not allow file! for its from argument *** Where: rename *** Stack:
UNSET
, here is a previous blog entry: http://www.rebol.net/cgi-bin/r3blog.r?view=0207unset!
is truthy.str: {te-st:=123~a-test-:=545~testz:=0-98} print parse str[collect[some[keep to ":=" 2 skip keep to ["~" | end] skip]]]
-
char in the entire string?replace/all
?UNSET
, here is a previous blog entry: http://www.rebol.net/cgi-bin/r3blog.r?view=0207>> there must be the error 1 == 1
value
instead of value?
)x: print y
these are the cases I'm encountering for real, and they're helping debug the program enormously. ERROR
macro, which simply expands to do make error! #composite
. Due to numerous #include bugs, macro may not get expanded, so I'm intentionally not naming it #ERROR
as I would name any other macro, but omit the shard. The issue #ERROR
will be silently skipped and I will never notice an error before it propagates very far where it's hard to deduce it's origin. While word ERROR
will tell me that it's undefined right away.get 'x
be silent (instead of get/any 'x
), but x
- throwing.get/any 'x
isn't a big issue, because we have :x
form, and get/any
in Red should only be used when we pass the word to a function as lit-arg or get-arg.set
should throw other than to catch unset coming as a function result during assignment. However what are the chances of one of us:x:
a result of a function returning unset? (print
and ??
are well-known, and there are only a few such functions)x
after that (which shows the error), but letting it propagate further somehow? (:x
would let it propagate but makes little sense when dealing with known data)replace/allthen
case [ suf = ["gif" | "jpeg" | "jpg" | "png" | "svg" | "bmp" | "webp" | "heif"] [print "img"] suf = "txt" [ print "txt" ] suf = "css" [ print "css" ] suf = "csv" [ print "csv" ] suf = "js" [ print "js" ] ]
find ["gif" "jpeg" "jpg" "png" "svg" "bmp" "webp" "heif"] suf [print "img"]
any
?suf = any ["gif" "jpeg" "jpg" "png"][print "img"]
parse suf [any ["gif" | "jpeg" | "jpg" | "png" | "svg" | "bmp" | "webp" | "heif"]] [print "img"]
types: clear #() total: 0 foreach file read %./ [ total: total + 1 suf: suffix? file case [ dir? file [types/dir: 1 + any [types/dir 0]] all [suf find ["gif" "jpeg" "jpg" "png" "svg" "bmp" "webp" "heif"] suf: form next suf] [types/img: 1 + any [types/img 0]] suf [t: to-word suf types/:t: 1 + any [types/:t 0]] 'else [types/none: 1 + any [types/none 0]] ] ] print types print ["TOTAL:" total]
view [f: field button [f/text: "123" set-focus f]]
. Action of the button make field f
show "123" as expected. Then I input "4" from keyboard, which make the field show "4123", not "1234". This is because the cursor is at the beginning of the former string in field, not at the ending. So how can I get "1234" in my case? Or, how to control the position of cursor in field
?either key[update key value][initialize key valye]
selected
facet. So routines only.txt: copy "" view [ f: field on-key[txt: rejoin [f/text do pick[event/key ""]char? event/key]] on-key-up[clear f/text f/text: txt] button [f/text: "123" set-focus f] ]
exclude a [%.test]
0! @#ok.pngin a directory called
testdir
0!%20%20@%23ok.png
file_names: read to-file {./testdir/}
0!%20%20@#ok.png
enhex
0%21%2520%2520%40%23ok.png
, though. I think. Anyway that's what enhex
should giveto file! enhex dehex "0!%20%20@#ok.png"
switch/default suf [ "gif" "jpeg" "jpg" "png" [print "img"] "txt" [print "text"] ][ print suf ]
>> m1 == #( a: 10 c: 30 ) >> m1/a: none == none >> m1 == #( c: 30 ) >> I typed "m1/2" instead of "m1/a" in the above little experment
none
)forall
, I ended up with a function for generating a list of the powers of 2 :smile:>> print powers-of-2 20 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576
powers-of-2b: func[n][ b: 2 + make vector! n + 1 forall b [b/1: b/1 ** ((index? b) - 1)] b ]
replace formed-number #"." #","
?for
loops?redin the terminal and I get:
--== Red 0.6.4 ==-- Type HELP for starting information. >>
red -c test.red
*** Access Error: cannot open: %-c *** Where: read *** Stack: --== Red 0.6.4 ==-- Type HELP for starting information. >>
red-064last stable as
rooton
Ubuntu 20.04.2 LTS
/usr/local/binand give
chmod 755
Nginxand
fcgiwrap
cgi-binfolder
/usr/local/bin
www-data
rootI can run Red but when
www-dataand I try this
www-data@ubuntu-nginx:~$ red *** Script Error: cause-error does not allow file! for its args argument *** Where: cause-error *** Stack: make-dir cause-error
www-datawith the stable version of Red I get
www-data@ubuntu-nginx:~$ red-064 *** Driver Internal Error: Access Error : Cannot make directory /var/www/.red/ *** Where: throw-on-error *** Near: [make-dir temp-dir]
do
calls load
on strings, load
produces a block bound to system/words
. Your c
is global there. bind
it if you want it local./var/www/
under that account maybe.www-data@ubuntu-nginx:~$ cd /var/www/ www-data@ubuntu-nginx:~$ touch test touch: cannot touch 'test': Permission denied www-data@ubuntu-nginx:~$
/var/www/
/var/www/when launched ?
echo $HOME
say?console
executable that it installed into /home/root/.red
somewhere and use it instead of R2 launcher? Unlikely you need to compile anything in your CGI anyway.root@ubuntu-nginx:/home# ls libRedRT-defs.r libRedRT-include.red libRedRT.so test4.red root@ubuntu-nginx:/home#
Use HELP or ? to view built-in docs for functions, values for contexts, or all values of a given datatype: help append ? system ? function!
load
and do
always use global context instead of local?load
has no idea about the context you invoke it in>> x: func [/s][probe in context? 's to-word 's] == func [/s][probe in context? 's to-word 's] >> x *** Script Error: in does not allow function! for its object argument *** Where: in *** Stack: x probe
context?
should accept refinements as argument>> x: func [/s][probe in context? /s to-word 's] == func [/s][probe in context? /s to-word 's] >> x *** Script Error: context? does not allow refinement! for its word argument *** Where: context? *** Stack: x probe
x: func [w /s r][print to-logic find/case spec-of context? 'w w]() x /s ;true x 's ;false x 'w ;true x 'r ;true x 'q ;false
in-func?: func [f [any-function!] w [all-word!] /case][to-logic either case [find/case spec-of :f w][find spec-of :f w]]() in-func? :find 'only ;== true in-func?/case :find 'only ;== false in-func?/case :find /only ;== true in-func? :in-func? 'w ;== true in-func? :in-func? /w ;== true in-func?/case :in-func? /w ;== false
x: func [/s][print in-func? :x 's]() x ;true x: func [/s][print in-func? :x /s]() x ;true x: func [/s][print in-func?/case :x 's]() x ;false x: func [/s][print in-func?/case :x /s]() x ;true
[""" Hello, "Mike" """]
[{ Hello, "Mike" }]
{}
is only red string representation. Is the only way to make it text and then replace with """
?{
is NOT part of the text, so you can’t replace itrejoin [{"""} { Hello, "Mike" } {"""}]
to-json
str: {a1|a2|432|test|last|} p: parse str[collect[some[keep to "|" skip]]]
["a1" "a2" "432" "test"]
ahead
and counting items (bars) ahead ... but it is waistful. Better use helper:chop: func [series [series!]][head remove back tail series] p: chop parse str[collect[some[keep to "|" skip]]] == ["a1" "a2" "432" "test"]
p: split str #"|" while ["" = last p][chop p] chop p ;== ["a1" "a2" "432" "test"] str: {a1|a2|432|test|last} p: split str #"|" while ["" = last p][chop p] chop p ;== ["a1" "a2" "432" "test"] str: {a1|a2|432|test|last|||} p: split str #"|" while ["" = last p][chop p] chop p ;== ["a1" "a2" "432" "test"]
ahead
, no counting is actually needed:p: parse str[collect[some[keep [to "|" not [#"|" end]] skip]]]
p: parse str[collect[some[keep [to ["|" not end]]] skip]]]
str
.to [some "|" ...]
.x>=
is a single word in Red. Spaces are importanta >= b and c >= d
is the same as ((a >= b) and c) >= d)
if and~ x >= 100 y >= 200 [print "Hurray!"] if (x >= 100) and (y >= 200) [print "Hurray!"] if not any [x < 100 y < 200] [print "Hurray!"] if not (x < 100) or (y < 200) [print "Hurray!"] if not or~ x < 100 y < 200 [print "Hurray!"]
either x < 100 [true block][false block]that may afford your specs.
dorc: does [do read-clipboard]
. Since I'm running a Red console day and night, I just enter dorc
in the console when I need to test copied text (:do
es a file on startup, so we have local environments with things we use commonly in the console.do-clip: does [do read-clipboard] load-clip: does [load read-clipboard] cc: func [value][write-clipboard mold value]
but when I use this it doesn't workcall/output {echo "test body" | mail -s "test!" "test@test.com"} a: ""
`/shell
|
token is not a program argument, it's a shell's operatorview [ text-list data [ "1" "2" ] ]
view/no-wait [ text-list data [ "1" "2" ] on-down [ print [ "Down" "face/selected:" face/selected "event/picked:" event/picked ] if face/selected == event/picked [ face/selected: none ] ] on-select [ print [ "Select" "face/selected:" face/selected "event/picked:" event/picked ] ] on-change [ print [ "Change" "face/selected:" face/selected "event/picked:" event/picked ] ] on-dbl-click [ print [ "Dbl click" "face/selected:" face/selected "event/picked:" event/picked ] ] on-focus [ print "Focus" ] on-unfocus [ print "Unfocus" ] ]
view/no-wait [ text-list data [ "1" "2" ""] ]
face/selected: none
should workselected: none
not workingunfocus
event; none a: [#[none] none] probe a ;= [none none] ;the same with true and probable other values b: [#[true] true] probe b ; [ true true ] ;it is especially important when using reduce/compose. For instance, c: compose [ a: none b: (none) ] probe c
print mold/all
dump-face
goes some way toward what you want. It's source might inspire you to do better :)v: view/no-wait [box box panel [box box panel [box] box]] dump-face v
part
function that complements other series functions. We also still haven't ruled out slice
. Fortunately, it's easy to prototype ideas at the mezz level to see how we like them, which you could do with a foreach-part
.outer/empty?
likely refers to a function inside the a
object, not to system/words/empty?
bind
weakens the design and *will* lead to horrible bugs and gotchasself
.self
, make object! doesouter
you would need the parent object to bind it (and even that will be tricky as you wish to refer to different contexts with it) but the inner one to not 'either
etc almost anything is a "true" value if it is not explicictly a logic! value of false, eg:foreach thing [ "" [] () ] [if thing [print "yes"]] yes yes yes
none
.o: make object! [ o1: make object! [a: 22] o2: make object! [f: does [probe a]] ] >> probe o/o2/f *** Script Error: a has no value *** Where: probe *** Stack: probe f probe
make object!
you're sort of saying "let's isolate these words", and then you're asking "what? I don't want to isolate these words"customer/add
is just as good as add-customer
, etc. Then you don't need sub contexts at all.;--Each pandore file uses at least this 36 bytes general header poHeader: object [ magic: "" ;--The magic number (12 bytes) @ref PO_MAGIC ptype: "" ;--The object type (4 bytes) ident: "" ;--The autor name (9 bytes + 1 complement) date: "" ;--The creation date (10 bytes) unused: "" ;--Unused (1 complement) ] ;--The common attributes structure ;--gathered all properties for any Pandore objects pobjectProps: object [ nbands: 0 ;--The number of bands nrow: 0 ;--The number of columns ncol: 0 ;--The number of rows ndep: 0 ;--The number of planes (depth) colorspace: 0 ;--The color space nlabels: 0 ;--The number of labels in a region map size: 0 ;--The number of nodes in a graph directed: 0 ;--if the graph is directed or undirected ] ;--Create a generic pandore object pobject: object [ potype: copy poHeader ;--Header poprop: copy pobjectProps ;--Properties data: copy #{} ;--Image values split: false ;--Flag ]
add-customer
is the actual way to have this but I am investigating into having this as sub contexts because they let me isolate functions groups. Also, a mechanism to selectively bind only some words via a rule would be nice. This is to fine tune the building of a global common vocabulary for a context and its elements.o1: make object! [a: 22] o2: make object! [f: does [probe a]] o: make object! [ x1: copy o1 x2: copy o2 ] >> probe first a *** Script Error: a has no value *** Where: first *** Stack: probe first probe o/x2/f
o1: make object! bo1: [a: 22] o2: make object! bo2: [f: func [] [probe a]] bind bo1 o2 bind bo2 o1 o: make object! [ x1: o1 x2: o2 ] >> probe o/x2/f *** Script Error: a has no value *** Where: probe *** Stack: probe f probe
bind body-of o2 o1
etc.context
, what does
is to function
?o1: make object! bo1: [a: 22 pf: func [] [f]] bo2: [f: func [] [probe a]] bind bo2 o1 o2: make object! bo2 o: make object! [ x1: o1 x2: o2 ] o/x2/f () >> 22
o1: make object! bo1: [a: 22] o2: make object! bo2: [f: func [] [probe a]] bind bo2 o1 >> o2/f *** Script Error: a has no value *** Where: probe *** Stack: f probe
Bind
should do its work on the proto block but it doesn't. It seems a separate entity.func
copies the body on creation:>> f: does b: [] == func [][] >> b =? body-of :f == false
bind body-of o2 o1
it does not work.o: make object! [ o1: make object! [a: 22] o2: make object! [f: does [probe a]] ] bind body-of o/o1 o/o2 bind body-of o/o2 o/o1 bind body-of :o/o2/f o/o1 o/o2/f >> 22
>> o1: make object! [a: 22] == make object! [ a: 22 ] >> o2: make object! bind [f: func [] [probe a]] o1 == make object! [ f: func [][probe a] ] >> o2/f 22 == 22
foreach
is still at your disposal, so doable.make/fcopy object! proto
option to bind fuction bodies.add
, next
because you loose the context relativeness information of them which is given by mag/add
, customers/add
or mag-add
, customers-add
. But if you adopt the second style, where words do not overlaps, you could create container objects with their functions cross-bound and working data private. So you have a very powerful and flexible vocabulary technology and It would be even more powerful if you add selective binding of words. o: make object! [ a: none o1: make object! [set 'a 22] o2: make object! [f: does [probe a]] ] probe o/o2/f
a: 2 b: case [ a == 1 [ "1" ] [] ] probe b ;= none
case []
matches R2/R3, which is likely the original design reasoning. But in @zwortex's example, Rebol sets b
to true
, where Red sets it to none
. However, Rebol returns none
for switch
when nothing matches. Here, Red and Rebol match. I think Red is an improvement over Rebol here, by not assuming that a missing value means true. I prefer sins of omission in general.conditionals
page as well. case
's code), we have consistency with any/all
but not if/unless
(which error in the case of a missing argument).case
, and just a bit more involved for switch
. Step 1) create a Conditionals
wiki page and note some of this. Step 2) create a ticket so Nenad can weigh in, and link to this chat.issues
, you can create a new issue there (a template will guide you), and include a link to your first message on the topic here.Conditionals
and start by including examples for case, any, all, if, unless, switch
with empty and missing conditions, so people can see the different behavior. You could also link to the other tickets, so it's clear that design considerations are at play.Internal Error: not enough memory
when saving a large block as redbin. Peak (total) memory use was only 5G of 62G. The block was loaded from a 180mb file. stats
return?1457976860
save
to eat another 2.5GBCompiling d:\test\script.red ... ...using libRedRT built on 14-May-2021/18:12:06 *** Red Compiler Internal Error: Script Error : Out of range or past end *** Where: percent-value? *** Near: [forall blk [ if multi-line? [nl?: new-line? blk] item: blk/1 either any-block? :item [ either with [ emit-block/sub/with :item main-ctx ] [ emit-block/sub :item ...
-e
to force interpretation, or wrap dynamic parts in do [...]
so they won't be compiled. For the real problem, do you have functions defined inside functions perchance? The compiler doesn't like those yet.all? [a b c d e f] [a f] >> true
find-all
built in.empty? exclude [a f] [a b c d e f]
subset?: func [ "Returns true if A is a subset of B; false otherwise." a [series! bitset!] b [series! bitset!] ][ empty? exclude a b ] superset?: func [ "Returns true if A is a superset of B; false otherwise." a [series! bitset!] b [series! bitset!] ][ subset? b a ]
subset-of: make op! :subset?
?
in the name because of the logic result in any case.offset?
gives me trouble oftenwithin?
(I always check this one)?
convention is a different topic. to-path
at all, but you need to write more code to do that, so it's just a tradeoff. to-*
funcs are meant to be simple wrappers, so the behavior is consistent with the to
action for a type. If it is the lit-word value also causing a problem, here's what you can do to help us all. Document the types that cause issues with to path!
today. Then we can look at whether paths should be smarter about them, or if handling it at the mezzanine level is best.Red [ needs: 'View ] f: function [return: [object!]][ context [ c: none ] ] a: make object! [ window: layout [ title "test" button "click-me" [ print "Hello" unview ] ] window/actors: context [ on-key: function [face [object!] event [event!]][ print ["Typed: " event/key] 'done ] ] ] view a/window
*** Red Compiler Internal Error: Script Error : Invalid path value: ctx||560 *** Where: get-prefix-func *** Near: [objects/a/ctx||560]
Red [ needs: 'View ] f: function [return: [object!]][ context [ c: none ] ] a: make object! [ window: layout [ title "test" button "click-me" [ print "Hello" unview ] ] do [ window/actors: context [ on-key: function [face [object!] event [event!]][ print ["Typed: " event/key] 'done ] ] ] ] view a/window
f
has to do with the rest of the code?image!
s are still not garbage collected, no? Red [ needs: 'View ] a: object [ window: layout [ title "test" button "click-me" [ print "Hello" unview ] ] do [ window/actors: object [ on-key: function [face [object!] event [event!]][ print ["Typed: " event/key] 'done ] ] ] ] view a/window
bin: img/rgb
, do something with the binary data and then update the image with img/rgb: bin
. So far so good. But when I use draw
function on the image, RAM is starting to leak (looking at the Windows Task Manager). Here's an example:Red[needs: view] W: 500 H: 500 bin: #{00} loop W * H * 4[append bin 150 + random 105] img: make image! compose [(as-pair W H) 0.0.0] img/rgb: bin update-img: does[ bin: img/rgb ; do something with the image data (in R/S. let's say blur) ... img/rgb: bin draw img compose[circle 250x250 200] ] view compose/deep[ base (as-pair W H) draw[image (img)] rate 10 on-time [update-img] ]
do
is never compiledRed [] f: function [] [ object [ x: none ] ] a: object [ ;y: object [ x: none ] y: f y/x: object [ g: function [] [ print "Hello" ] ;z: 1 ] ] probe a
i: draw 100x100 [pen blue line-width 1 circle 50x50 40] blur: function [i] [ i50: copy i i50/alpha: 127 ix: draw i/size [image i -1x0 image i50 1x0] ix2: draw i/size [image i -2x0 image i50 2x0] ix2/alpha: 85 draw ix [image ix2] i50/alpha: 127 draw ix [image i50] draw i50 [image ix] i50/alpha: 127 draw ix [matrix [0 1 1 0 0 0] image i50] ] ? (blur blur blur i)
matrix
:smile: >i: draw 100x100 [pen blue line-width 1 circle 50x50 40 30] blur: function [i] [ split: func [ofs] [ ix: draw ix compose [image i (-1x0 * ofs) image i50 (1x0 * ofs)] iy: draw iy compose [image i (0x-1 * ofs) image i50 (0x1 * ofs)] ] join: func [tgt src alpha] [ src/alpha: alpha draw tgt [image src] ] i50: copy i i50/alpha: 128 ix: iy: i/size split 1 i1: join copy ix iy 128 split 2 i2: join copy ix iy 128 join i1 i2 109 join copy i i1 112 ] ? (blur blur blur i)
blur
- a simple 3x3 box filter, implemented as a horizontal pass, followed by a vertical pass. Uses an intermediate buffer to store the result of the horizontal pass. Modifies the source in place. The wrap around the edges costs a modulo for each color component.#system[ rsblur: func[ buf [red-binary!] w [integer!] h [integer!] tbuf [red-binary!] /local s src d dst offs offs- offs+ idx w3 x y ][ s: GET_BUFFER(buf) src: (as byte-ptr! s/offset) d: GET_BUFFER(tbuf) dst: (as byte-ptr! d/offset) w3: w * 3 loop h [ idx: 1 loop w3[ offs-: idx - 3 // w3 offs+: idx + 3 // w3 dst/1: as byte!((as integer! src/idx)+(as integer! src/offs-)+(as integer! src/offs+) / 3) idx: idx + 1 dst: dst + 1 ] src: src + (3 * w) ] src: (as byte-ptr! s/offset) dst: (as byte-ptr! d/offset) y: 0 offs: 1 loop h [ x: 1 loop w3[ offs-: y - 1 // h * w3 + x offs+: y + 1 // h * w3 + x src/1: as byte!((as integer! dst/offs)+(as integer! dst/offs-)+(as integer! dst/offs+) / 3) x: x + 1 offs: offs + 1 src: src + 1 ] y: y + 1 ] ] ]
/rgb
binary data of an imageRed [] a: make object! [ f: function [] [ print "Hello" ] ] print "Initil - OK" a/f b: copy a print "Copy - NOK" b/f ; nothing when compiled - b is viewed as data c: make a [] print "Make - OK" c/f ; this one works
break
message you saw earlier will prevent that function to break an outer loop it could be used in. So compiler error is the glitch, not the interpreter's "let it be".break
and related problematic players, it's a balance of exceptions in behavior. We can reify certain words to be special, or we can say "If you write code that takes a thunk (other code) as an argument, use break, return, ...
in the thunk at your own risk. Here there by Tygers." For my part, I don't think there's a perfect answer that solves it, because some people will always expect it to do the other thing. My biggest concern with "unreasonable" behaviors is security risk.unbind
the words of a block?word
or a set-word
, which is the fastest and easily usable datatype to be used as KEY in a block
? (unquoted and where, at least, you can use the same character set of a word) words-of
command, I want to neutralize the contextid (no context) for block reusing and maximum security. Actually, I have to create a new anonymous context with all words set to none and bind the block to it, which is quite slow.unbind
native in Rebol.call
work under Windows/GUI, and how? I get -1 (error) on call .doc
when the file does exist. Do I need to specify any refinements?start
?start
and there is no built-in function start
as far as I can see. So what do you refer to?C:\>start /? Starts a separate window to run a specified program or command. START ["title"] [/D path] [/I] [/MIN] [/MAX] [/SEPARATE | /SHARED] [/LOW | /NORMAL | /HIGH | /REALTIME | /ABOVENORMAL | /BELOWNORMAL] [/NODE <NUMA node>] [/AFFINITY <hex affinity mask>] [/WAIT] [/B] [command/program] [parameters]
winword
call {start "" "filename.doc"}
?call {start "" "filename.doc"}
answer a question though?call
, where if you have a question about it you can go there, search for keywords, and learn more about that topic.Unbind
would be a single operation, while the other involves: extracting the words; creating a prototype block with those words set to none; then you should bind it, which means: creating an object and searching in it for the corresponding word and for each word of the block you want to change binding and make the binding. I suppose the whole process is much slower than a single unbind
operation. bind
binds a block, I suppose it traverses the block all, and foreach word it would scan the context to bind the block to for a corresponding word. This operation seems is to my eyes slower than removing the binding from any word, as the former involves a search, while the latter just a single set.bind
is somewhat slow but will be way faster than extraction of wordsblk: [1 2 3] forall blk [if not last? blk [blk: next blk insert blk '|]] blk == [1 | 2 | 3]
parse
attempt:>> b: [a b c d 1 2 3] == [a b c d 1 2 3] >> parse b [any[skip ahead skip insert (to word! '|)]] == false >> b == [a | b | c | d | 1 | 2 | 3]
parse
is ~1.5 time faster:profile/show/count [[blk: copy [a b c d 1 2 3] forall blk [if not last? blk [blk: next blk insert blk '|]]] [blk: copy [a b c d 1 2 3] parse blk [any[skip ahead skip insert (to word! '|)]]]] 10000 Count: 10000 Time | Time (Per) | Memory | Code 0:00:00.063 | 0:00:00 | 4200284 | [blk: copy [a b c d 1 2 3] parse blk [any [skip ahead skip insert (to word! '|)]]] 0:00:00.093 | 0:00:00 | 4200440 | [blk: copy [a b c d 1 2 3] forall blk [if not last? blk [blk: next blk insert blk '|]]]
>> b: collect[loop 100000 [keep random 100]] == [71 76 52 6 4 92 92 43 3 59 82 61 9 76 30 13 34 82 78 72 42 57 76 51 29 14 53 74 50 11 8 59 83 81 99 99 59 99 27 94 53 93 5 63 ... >> blk: copy b == [71 76 52 6 4 92 92 43 3 59 82 61 9 76 30 13 34 82 78 72 42 57 76 51 29 14 53 74 50 11 8 59 83 81 99 99 59 99 27 94 53 93 5 63 ... >> t1: now/time/precise == 14:11:15.1611 >> forall blk [if not last? blk [blk: next blk insert blk '|]] == none >> t2: now/time/precise - t1 == 0:00:06.889 >> t1: now/time/precise == 14:11:22.0611 >> parse b [any[skip ahead skip insert (to word! '|)]] == false >> t2: now/time/precise - t1 == 0:00:06.75085
blk: [a b c d 1 2 3] parse blk [any [skip [end | insert ('|)]]] blk ;== [a | b | c | d | 1 | 2 | 3]
end
before the insertion, but apparently did it wrong and didn't continue that way. Also ('|)
is better!ahead rule
matches the input against rule
but doesn't advance the input. And yes, insert
changes the series in place.forskip
(@dockimbel doesn't love it) and [incr](https://gist.github.com/greggirwin/4dd6deb56dcba704bf6d418aff244373) is an idea that I haven't pressed for input on. I still like it, but we all like our own ideas. :^)PICK
[... any-string! any-word! block! logic! time!]
money!
denominationlogic!
as index forpick
, its true
value selects the first value in the series; the false
one - the second:>> lang: charset "Red-lang" == make bitset! #{0000000000040000000020004D0A} >> pick lang #"a" == true >> pick lang #"b" == false >> pick lang "Red" == true >> pick lang "Re-g" == true >> pick lang [#"R" #"-" "ang"] == true >> pick lang [#"R" #"e" #"b" #"o" #"l"] == false
bitset!
value is an array of bits that stores boolean values, picking a char!
just checks if the respective bit is set, thus returning true
or false
. A string!
index means that all the bits corresponing to the srting characters must be set; a block!
of chars and strings works the same way.money!
denominationas-money 'USD to-float as-money 'eur 1
>> usd: USD$20 == USD$20.00 >> eur: make money! reduce ['EUR to float! usd/amount] == EUR$20.00
m/amount
, so words can have refinements based on the datatype? Wow!>> t: now == 1-Jun-2021/8:44:05 >> t/<TAB> == date day hour isoweek julian minute month second time timezone week weekday year yearday zone
>> probe system/catalog/accessors [ date! [ date year month day zone time hour minute second weekday yearday timezone week isoweek julian ] email! [user host] event! [ type face window offset key picked flags away? down? mid-down? alt-down? aux-down? ctrl? shift? ] image! [size argb rgb alpha] pair! [x y] time! [hour minute second] money! [code amount] ]
email!
, it would be nice to have them for url!
also instead of using decode-url
.money!
accessors are read-only. Is it by design?code
. One argument being that changing the code doesn't convert via an exchange rate, so what's the validity without also changing the amount
? But these are simply data values, and there may very well be cases where using the code
as a tag is useful during processing. Email!
currently just uses @
as a delimiter to support the two parts. This works well in practice, but isn't 100% correct, as email addresses can *technically* use quoted strings in the local-part which may contain @ symbols. So the current model is convenient and relatively safe. From a quick search, it's used in networking bits, Rugby, Uniserve, and mail protocols in ports. I doubt it's used much in user code. We could probably remove those email accessors, but let's leave them until we write mail protocols to decide."1"
and then "USD"
button to change to that currency to EUR$1,00
without conversion or, otherwise, hit the "convert"
button and then select the currency to make a calculated conversion using an exchange rate. [ ["ax" "bx" "cc"] ["ab" "66" "XC"] ["xb" "Y3" "S1"] .... ]
sort/skip ... 2
that whole ting. I have old code somewhere, which will need porting to Red. Will look.combsort
. sort/compare
with a comparatur function:sort/compare block func [this that] [all [this/1 > that/1 this/2 > that/2]]
>> block: collect [loop 15 [keep/only reduce [random 9 random 9 random 9]]] == [[3 5 1] [7 8 5] [4 7 3] [5 7 4] [2 3 3] [7 6 4] [6 4 7] [3 6 5] [9 7 1] [3 7 1] [6 4 9] [2 4 3] [6 9 5] [7 2 8] [2 4 9]] >> sort/compare block func [this that] [any [this/1 < that/1 this/2 < that/2]] == [[2 3 3] [2 4 9] [2 4 3] [3 5 1] [3 6 5] [3 7 1] [4 7 3] [5 7 4] [6 4 7] [6 4 9] [6 9 5] [7 2 8] [7 6 4] [7 8 5] [9 7 1]]
block
in /compare => Comparator offset, block (TBD) or function.
serve this function - to specify the priority of the fields when sorting?sort
in the comparator?/all => Compare all fields (used with /skip)
which seems near to what is needed. In place of All fields it could compare just few.sort
compares in order to place at their respective places in the sorted list.sort
in the comparator?sort
does not error out if things are not "comparable"/stable
. I remember issues under R2 at some point, but confess I haven't tried it in Red./stable
it’s even more unstable as I got hard crash that I wasn’t able to reproduce later, unfortunately, otherwise I would fill a bug.[-1 0 1]
for stable sorting.sort
is important.forall
allows to alter it's offset at iteration time.loop
, repeat
, or foreach
internally, but if there's no internal func to do it, the final logic goes through Ladislav's old cfor
(for
how C does it), which gives you total control. repeat
are when I'm using it with an offset, in place of missing for
. (so if we had for
, I'd vote for repeat
to support reading index back between iterations)1x0
even if it goes over the current line, then skip the extra number of pixels on the next line.cfor
, *every* loop is slower.while
that puts you in control of the end-test.for
:)for [i 1 to 10 step 2][...]
doesn't let you change i
and potentially spinlock. while
or for [[i: 1] [i <= 10] [i: i + 2]] [...]
gives you all the rope you need to shoot yourself in the foot.i
because of spinlock danger?for
will have to be consistent about it.foreach
. Because that's a powerful feature of forall
to skip 1 or more items, and even zero. I'm using it a lot, and I would hate to throw away foreach
and fall back to forall
when I need that.for
is less important.goto
is powerful. Constraints are a pain sometimes but they also provide a lot of value. In this case, the ability to reason about iteration logic without having to read every line of the body./stable
sorting?newWords: ["my" "is not"] ; not ["my" "is" "not"] and side spaces are deleted newMarkers: ["," "..."] ; even there is no space
>> letters: charset [#"a" - #"z" #"A" - #"Z"] == make bitset! #{00000000000000007FFFFFE07FFFFFE0} >> new-words: [] new-markers: [] == [] >> parse/case sentence [some [space | my-words | copy value some letters (append new-words value) | copy value some [not letters skip] (append new-markers value)]]
sort
is important.*** Script Error: _save-cfg has no value *** Where: do *** Stack: tara tara kapat quit
_save-cfg
input.red
from source of red-master-=== Red Compiler 0.6.4 ===- Compiling Z:\home\abdllh\Desktop\cozkaynak\coz.red ... *** Compilation Error: include file not found: boşluk.red *** in file: Z:\home\abdllh\Desktop\cozkaynak\coz.red *** near: [ #include %boşluk.red #include %isim.red #include %işaret.red #include %işlev.red ]
ş, ç, ğ
sort/stable
, thank you.view [canvas: panel 150x150 draw [line 10x0 160x50]]
about
- to exclude a possibility of your mistake) and what does system/view/metrics/colors/panel
tell?repend
and append reduce
do not behave the same?c1: context [ h: make hash! [] repend h ['obj1 make object! [a: 1 b: 2 c: 3]] repend h ['obj2 make object! [a: 4 b: 5 c: 6]] ] c2: context [ h: make hash! [] append h reduce ['obj1 make object! [a: 1 b: 2 c: 3]] append h reduce ['obj2 make object! [a: 4 b: 5 c: 6]] ] print mold c1/h/obj1 print mold c2/h/obj1 print mold select c1/h 'obj1 print mold select c2/h 'obj1
select
statement returns none
on the repend
version.repend
and append reduce
behave the sameabout/debug
in the console to show the details. divide
is behaving properly now :) On the old version, divide 5 2
returned 2
and it was necessary to to-float
one of the operands...modulo
changes still to come. :^)> view [canvas: panel 150x150 draw [line 10x0 160x50]] >
base
face if possible. Only use panel
as a container of the other faces.>> o: make object! [a: 22 b: 33 c: 'a] >> third o == [a: 22 b: 33 c: a]
to-block
returns the C
value as 'a
instead of a
:o: make object! [a: 22 b: 33 c: 'a] >> to block! o == [ a: 22 b: 33 c: 'a ]
body-of
body-of
>> body-of make object! [a: 1 + 1 c: to lit-word! 'a] == [ a: 2 c: 'a ] >> body-of make object! [a: 1 + 1 c: 'a] == [ a: 2 c: 'a ] >> body-of make object! [a: 1 + 1 c: to word! 'a] == [ a: 2 c: 'a ]
Make Object!
to create the context. TO-BLOCK
? make object!
(which will fail in numerous other cases), but so it will be molded into something that looks to us - readers - as part of our code.make object!
(because that's what mold
used to do before /all
) - it just didn't really work as you say, so eventually we got mold/all
as the solution...a
when the object is made? Or what is the use case for 3?>> body-of make object! [a: 1 + 1 c: to lit-word! 'a] >> body-of make object! [a: 1 + 1 c: 'a] >> body-of make object! [a: 1 + 1 c: to word! 'a]
== [ a: 2 c: a ]
== [ a: 2 c: to lit-word! 'a ]
== [ a: 2 c: quote 'a ]
word
- values
version and which one the maker block version, and in which form. copy obj
, and (1) - what is that block used for?copy obj
as a whole because Red can copy it, while Rebol can't. But if you want to move around this block like sending it remotely, you need the maker version...>> a: make object! [b: 22 c: 'z] == make object! [ b: 22 c: 'z ]
>> x: to-map compose [(body-of a)] == #( b: 22 c: 'z )
c: 'z
should be c: z
body-of
, having seen words becoming lit-words. Gregg then explained me the reason in red/bugs. The same could happen when you create an object and you see on the console:>> make object! [b: 22 c: 'z] == make object! [ b: 22 c: 'z ]
>> make object! [b: 22 c: 'z] == make object! [ b: 22 c: z ]
>> make object! [b: 22 c: 'z] == context! [ b: 22 c: z ]
context!
type/bugs
. A key point, to me, is that object specs are evaluated while blocks and maps are not. So what makes sense for one may not make sense for the other. What I care about is how painful it is to change from one to the other, if there are changes in behavior that trip you up, but less so about whether their serialized forms look the same. We can start by comparing maps and blocks, then reduced blocks with objects, etc.0
:list: [#(customers: 2) #(foo: 4)] foreach el list [ ; set el 0 ] probe list
foreach el list [foreach [key value] el [el/:key: 0]]
r: write/info http://test/example.com compose/deep [ post [ upload_file: ( read/binary %"/C/sample.png" ) ] ]
write/binary
?Compiling to native code... *** Compilation Error: undefined symbol: ~b||566 *** in file: %/Users/fjouen/Programmation/Red/RedCV/samples/image_haar/faceDetection.red *** in function: exec/f_loadClassifier *** at line: 1 *** near: [~b||566 stack/mark-func ~rcvReadTextClassifier exec/ctx||503 word/get ~classifierFile word/get ~nParameters ]
refinement!
can't carry a context, which other types (apart lit-word!) can carry one?refinement!
and issue!
don't support it today (though they do use the same structure internally and could in the future). They are the added word types in all-word!
. lit-word
with success:>> x: first bind ['hello] make object! [hello: true] >> probe reduce reduce x true
def do_timestep(u0, u): # Propagate with forward-difference in time, central-difference in space u[1:-1, 1:-1] = u0[1:-1, 1:-1] + D * dt * ( (u0[2:, 1:-1] - 2*u0[1:-1, 1:-1] + u0[:-2, 1:-1])/dx2 + (u0[1:-1, 2:] - 2*u0[1:-1, 1:-1] + u0[1:-1, :-2])/dy2 ) u0 = u.copy() return u0, u
NumPy
's multidimensional arrays with slicing.foreach
loops, or some of @hiiamboris *each menagerie :smile: timestep: does [ v1: u0/1/1 + (D * dt) v8: 0.0 repeat j ny [ repeat i nx [ u/:i/:j: u0/:i/:j if all [j > 1 j < ny i > 1 i < nx][ v1: u0/:i/:j + (D * dt) if all [j > 1 j < ny i > 1 i <= nx][ v2: u0/:i/:j - (2.0 * u0/:i/:j) ] if all [j < (ny - 2) i > 1 i < nx] [ v3: u0/:i/:j ] v4: (v2 + v3) / dx2 if all [j > 1 j < ny i > 1 i <= nx] [ v5: u0/:i/:j - (2.0 * u0/:i/:j) ] if all [j > 1 j < ny i < (nx - 2)] [ v6: u0/:i/:j ] v7: (v5 + v6) / dy2 v8: v1 * (v4 + v7) print [v1 v2 v3 v4 v5 v6 v7 v8] ] u/:i/:j: v8 ] ] u0: copy u ]
Float matrix Mat Order : 4x4 as Red pair! Mat header: 3 64 4 4 Mat values: [ 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 14.0 15.0 16.0 ] Slice 2 3 2 3 [ 6.0 7.0 10.0 11.0 ] Done
[1:-1, 1:-1]
in NumpyXxY
for top-left corner and WxH
for width/height. point!
syntax, but general matrix design shouldn't be too contentious (unlike other areas where questions just lead to more questions).matrix
in @ldci's case as strictly 2d :smile: Notes
sections with longer questions, comments and suggestions. Thank you in advance!append
to the action check). Need to see if it's related to an open ownership
ticket.move
feature.*** Script Error: scan does not allow block! for its buffer argument *** Where: scan *** Stack: view layout layout do-safe parser-init start-stop-processing get-files-for-processing-from-http get-files-for-processing-from-http get-files-for-processing-from-http scan
scan
?scan
(lexer function) is used by it to [convert text
and field
's /text facet into /data](https://github.com/red/red/blob/master/modules/view/view.red#L461). So it's possible your code sets /text
to a block somewhere./text
. So What does this error mean. That function trying to set block to /text
somewhere?/text:
assignment. Maybe log these values into a file for later review.prog-react: make reactor! [percent: 0]
loading-bar: progress 0% react [loading-bar/data: prog-react/percent]
percent
valueprog-react/percent: make percent! processed-count / total
Red [Needs: 'View] image-urls: [ https://i.ytimg.com/vi/1Ne1hqOXKKI/maxresdefault.jpg https://ichef.bbci.co.uk/news/976/cpsprodpb/12A9B/production/_111434467_gettyimages-1143489763.jpg ] processed-count: make float! 0 total: make float! length? image-urls images: [] prog-react: make reactor! [percent: 0] view [ size 600x600 below h1 "Image Viewer Test" loading-bar: progress 0% react [loading-bar/data: prog-react/percent] across button "Start loading" [ foreach url image-urls [ append images load url processed-count: processed-count + 1 prog-react/percent: make percent! processed-count / total print prog-react/percent ] my-image/image: first images ] return my-image: image 300x300 return button "Previous" [ images: back images my-image/image: first images ] button "Next" [ images: next images my-image/image: first images ] ]
do-events/no-wait
after changing progress-bar data facet.blk: [ [OKPD_code OKPD_name quantity isMedicalProduct] ["25.22.11" "aa aaa aaaaa" "1.00" none] ]
OKPD_code "25.22.11"
and so on. What is the best approach for it?OKPD_code 25.22.11 OKPD_code aa aaa aaaaa OKPD_code 1.00 OKPD_code none OKPD_name 25.22.11 OKPD_name aa aaa aaaaa OKPD_name 1.00 OKPD_name none quantity 25.22.11 quantity aa aaa aaaaa quantity 1.00 quantity none isMedicalProduct 25.22.11 isMedicalProduct aa aaa aaaaa isMedicalProduct 1.00 isMedicalProduct none
repeat
, based on the length of one series, and then the index counter to access items in other series.zip: function [b1 b2 /with fn][ out: clear [] len: min length? b1 length? b2 repeat i len [ either with [ fn b1/:i b2/:i ][ repend out [b1/:i b2/:i] ] ] unless with [out] ] blk: [ [OKPD_code OKPD_name quantity isMedicalProduct] ["25.22.11" "aa aaa aaaaa" "1.00" none] ] zip blk/1 blk/2 ;== [OKPD_code "25.22.11" OKPD_name "aa aaa aaaaa" quantity "1.00" isMedicalProduct none] zip/with blk/1 blk/2 func [a b][print [a b]] ;OKPD_code 25.22.11 ;OKPD_name aa aaa aaaaa ;quantity 1.00 ;isMedicalProduct none
clear
here :flushed:. First two lines betterlen: min length? b1 length? b2 unless with [out: make block! 2 * len]
data: [ aa: "foo" !bb: "bar" dd: "baz" ]
foreach [k v] data [ if find to-string k "!" [ data/:k: to-set-word replace to-string k "!" "" ] ] probe data
data/:k
uses k
as a key so it's accessing it's value v
, you need to change directly the value you want. Here's one approach:forall data [if find to string! data/1 #"!" [change data to set-word! next form data/1]]
to-word
is superfluous here.to-logic
!do rejoin [x "1"]
probe as-c-string row/idxThis is all happening on the /system side. What I want to do is either store those strings in a block and return the block (to Red) OR somehow deal with the int-ptr! in Red. Does that make sense? I seem to be caught in between the two worlds of /system and "normal" Red. Thank you as always.
handle!
type then as more idiomatic for pointers.block/rs-append blk integer/push 12345
?---- C ------ --------- Red/System ---------- int p[20] = 0; p: array [20 integer!] p[4] = 123; p/4: 123 p[i] = 123; p/i: 123
*** Compilation Error: undefined symbol: red/block/rs-append-block
Don't know why block/rs-append is there and it's in the block.reds file. do append copy x "2.5"
do reduce [ x/1 "12.3"]
>> recycle/off >> x: [length?] == [length?] >> prof/each/times [ [ do append copy x "2.5" [ do reduce [ x/1 "2.5"] [ ] 100000 <100000>53% .00137ms 100 B [do append copy x "2.5"] <100000>47% .0012 ms 60 B [do reduce [x/1 "2.5"]]
append copy
triggers reallocation of the copied buffer sometimes.x
is buried somewhere far above.; When moving the first element of a serie to its second position, I would expect this to work : a: [ 1 2 3 4 ] move/part (at a 1) (at a 3) 1 a ;= [ 2 3 1 4 ] - 1 inserted after 3 ; But it does not, as the insertion takes place after and not before the insertion point. Therefore I have to write instead a: [ 1 2 3 4] move/part (at a 1) (at a 2) 1 a ;= [ 2 1 3 4 ] - 1 after 2 ; Move appears to work as if it was a removal followed by an insertion : a: [ 1 2 3 4 ] b: take/part (at a 1) 1 insert (at a 2) b a ;= [ 2 1 3 4 ] ; When you perform the move the other way round, moving a higher indexed element towards the beginning of the serie, or between two different series, indexes are not modified by the first removal and therefore insertion takes place as expected, before the insertion point a: [ 1 2 3 4 ] move/part (at a 4) (at a 3) 1 a ;= [ 1 2 4 3 ] - 4 before 3 a: [ 1 2 3 4 ] b: [ 1 2 3 4 ] move/part (at a 1) (at b 3) 1 b ;= [ 1 2 1 3 4 ] - 1 before 3
view [ title "Test" comment { field "Hello" } field "Bye" ]
*** Script Error: VID - invalid syntax at: [comment {^/field "Hello"^/} field] *** Where: do *** Stack: do-file view layout cause-error
a: 1 comment { b: 2 } c: 3
system/lexer/pre-load
though if this feature is so tempting.compose
view compose [title "Test" (comment { field "blah blah" }) field "Ok"]
view compose [ text "Hello" (comment { bold }) gray (comment { button "Btn1" button "Btn2" }) button "Btn3" ]
/* */
syntax as I'm using it in [bulk](https://gitlab.com/hiiamboris/red-mezz-warehouse/-/blob/master/bulk.red) as word in the path. And because it automatically disables all refinements and words starting with *
. E.g. my-block: [*marker: value]
we can't address as my-block/*marker
anymore.;--
--;
; ; ; ...
not as ;;;...
but some people have it the other way it seems/* ... */
in paths @hiiamboris.;;
, for extra visibility, it breaks.rust
comment system. I know it's a different universe of programming language - this is just an example of the types of comments you might wantRegular comments which are ignored by the compiler: // Line comments which go to the end of the line. /* Block comments which go to the closing delimiter. */ Doc comments which are parsed into HTML library documentation: /// Generate library docs for the following item. //! Generate library docs for the enclosing item.
;
- lines where ;;; (at least) are used find . \( -name "*.red" -o -name "*.reds" \) -exec grep -H -e ";;;" {} \; | wc -l ==> 2 - lines where ;; is used at the start of a line find . \( -name "*.red" -o -name "*.reds" \) -exec grep -H -e "^[[:space:]]*;;" {} \; | wc -l ==> 234 and these account for that number of different files find . \( -name "*.red" -o -name "*.reds" \) -exec grep -l -e "^[[:space:]]*;;" {} \; | wc -l ===> 46 out of find . \( -name "*.red" -o -name "*.reds" \) | wc -l ===> 406 - lines where ;; is used two times in the same line find . \( -name "*.red" -o -name "*.reds" \) -exec grep -H -e ";;.\+;;" {} \; | wc -l ==> 16 and these are all comments of the type ;; <comment> ;; <spaces> <end of line> that would not be impacted find . \( -name "*.red" -o -name "*.reds" \) -exec grep -H -e ";;[^;]\+;;[[:space:]]*$" {} \; | wc -l ==> 16 - lines where ; is used at the start of a line then followed by ;; in the same line find . \( -name "*.red" -o -name "*.reds" \) -exec grep -H -e "^[[:space:]]*;[^;]\+;;[^;]" {} \; | wc -l ==> 6
Red/System [ Title: "Pointers" Author: "ldci" ] print ["Let's play with structures and pointers" lf] print ["Create structure and pointer" lf] ;--First we create a structure as an alias (no memory allocation) union: alias struct! [ f [float!] i [integer!] str [c-string!] ] ;--then a pointer to the structure p-struct!: declare struct! [ptr [union]] ;--memory allocation ;--now we have to allocate the structure un: declare union un/f: pi un/i: 255 un/str: "Hello Red world" ;--and to create a pointer to the structure p-struct!/ptr: un ; on fait pointer sur ;--verify structure initialization print ["Structure address: " un lf] print ["Pointer value: " p-struct! lf] print ["Nice, we are pointing to the structure!" lf] print [p-struct!/ptr/f " " p-struct!/ptr/i " " p-struct!/ptr/str lf] print ["Now, let's modify the pointer values" lf] p-struct!/ptr/f: 0.0 p-struct!/ptr/i: 0 p-struct!/ptr/str: "Bye bye crual world!" print ["Pointer values are changed" lf] print [p-struct!/ptr/f " " p-struct!/ptr/i " " p-struct!/ptr/str lf] print ["And the structure too! " lf] print [un/f " " un/i " " un/str lf]
Let's play with structures and pointers Create structure and pointer Structure address: 000030D0 Pointer value: 000030C4 Nice, we are pointing to the structure! 3.141592653589793 255 Hello Red world Now, let's modify the pointer values Pointer values are changed 0.0 0 Bye bye crual world! And the structure too! 0.0 0 Bye bye crual world!
Red [ Title: "Strings" Author: "ldci" ] ;--the way to share global Red words with Red/System code s: "Hello Red" ;--string variable b: #{48656C6C6F20526564} ;--same string as binary ;--Red/System routines getString: routine [return: [string!]][ as red-string! #get 's ] getBinary: routine [return: [binary!]][ as red-binary! #get 'b ] ;--Red code print ["Test String: " getString] append s " is amazing" print ["Test String: " getString] print ["Test Binary: " getBinary]
Test String: Hello Red Test String: Hello Red is amazing Test Binary: #{48656C6C6F20526564}
Red [ Title: "Arrays" Author: "ldci" ] ;-- Basic Red Code arr1: [1 2 3 4 5 6 7 8 9 10] arr2: [512.0 255.0 127.0 64.0 32.0 16.0 8.0 4.0 2.0 1.0] Print "Red Array" n: length? arr1 i: 1 while [i <= n][ print [i ": " arr1/:i] i: i + 1 ] ;--Now with routines for integer array readIntegerArray: routine [ array [block!] /local i [integer!] int [ red-integer!] value tail [red-value!] ][ print ["size: " block/rs-length? array lf] value: block/rs-head array tail: block/rs-tail array print ["value: " value lf] print ["Tail : " tail lf] i: 1 while [value < tail][ int: as red-integer! value print [i ": " int " " int/value lf] value: value + 1 i: i + 1 ] ] ;--and float array readFArray: routine [ array [block!] /local i [integer!] f [red-float!] value tail [red-value!] ][ print ["size: " block/rs-length? array lf] value: block/rs-head array tail: block/rs-tail array print ["value: " value lf] print ["Tail : " tail lf] i: 1 while [value < tail][ f: as red-float! value print [i ": " f " " f/value lf] value: value + 1 i: i + 1 ] ] print newline print ["Integer array"] readIntegerArray arr1 print newline print ["Float array"] readFArray arr2
`Red [ Title: "Call" Author: "ldci" ] ;--How to use R/S #call with Red print ["Red Version : " system/version] print ["Compiled : " system/build/config/OS system/build/config/OS-version] print "Random Tests" random/seed now/time/precise ;--generate Random/seed rand: function [n [integer!]][random n] ;--returns an integer ;--first solution with #system #system [ v: 1000 ;--Red/S word to be used with routines #call [rand v] int: as red-integer! stack/arguments print ["System Call : " int/value lf] ] ;--Second solution with Red routine alea: routine [][ #call [rand v] ;--Use Red/S variable int: as red-integer! stack/arguments int/value ] v: 1000 ;--this a Red word, not the Red/S word ;--Classical Red Function print ["Red Function: " rand v] print ["Red Function: " rand v] print ["Red Function: " rand v] ;--Red Routine which calls Red Function print ["Red Routine : " alea] print ["Red Routine : " alea] print ["Red Routine : " alea]
Red Version : 0.6.4 Compiled : macOS 10.14 Random Tests System Call : 332 Red Function: 824 Red Function: 778 Red Function: 676 Red Routine : 222 Red Routine : 7 Red Routine : 948
toto: object [ a: 1 ] titi: 'a compose [ toto/(titi) ] ; get **toto/(titi)** when expecting **toto/a** toto/(titi) ;= returns 1 as expected
to path! compose to block! quote toto/(titi)
Red [ Title: "Red variables" Author: "ldci" ] ;--3 Red programming rules: Readability, Reliability and Reusability. ;--the way to access and modify global Red variables i: 100 ;--integer! f: 0.0 ;--float! s: "Hello Red" ;--string! getInt: routine [/local int][ int: as red-integer! #get 'i int/value: int/value + 100 int/value ] getFloat: routine [/local fl][ fl: as red-float! #get 'f fl/value: fl/value + pi fl/value ] ;--Some Red scalars can use boxing to return a Red value getIntBoxing: routine [/local int][ int: as red-integer! #get 'i integer/box int/value + 250 ] getFloatBoxing: routine [/local fl][ fl: as red-float! #get 'f float/box fl/value + pi / 2.0 ] getString: routine [/local st ptr][ st: as red-string! #get 's ptr: " and Red/System" ;--just a c-string! considered as pointer string/concatenate-literal st ptr ;--append ptr values to string as c-string! string/rs-head st ] print ["Red words values: " i f s] print ["Routines can modify Red words values"] print ["Test Integer:" getInt] print ["Test Boxing: " getIntBoxing] print ["Test Float: " getFloat] print ["Test Boxing: " getFloatBoxing] print ["Test String: " getString]
Red words values: 100 0.0 Hello Red Routines can modify Red words values Test Integer: 200 Test Boxing: 350 Test Float: 3.141592653589793 Test Boxing: 1.570796326794897 Test String: Hello Red and Red/System
a: [ "x" "y" "z" "e" ] print [ join a ] ;= "x y z e" print [ join/with a #"-" ] ;- "x-y-z-e"
/with
refinement to rejoin
for that. My old approach was a separate delimit
function, because it's also useful on blocks. Then you can chain with rejoin
. Compose
is certainly nice up to a point. Alternative experiments:join
over from Rebol, but I've toyed with behavior on [join/combine](https://gist.github.com/greggirwin/24c022cb5dde5771531a8939309ccb43)forskip
is worth including, so there's an experimental version there as well. I understand the reasoning behind forall
being native in Red, but liked how they were implemented in R2. Admittedly, forskip
is not a *great* name, but some new HOF ideas should fill some of these gaps.for
? Was it decided it is not a good fit for the Redbol languages? I do remember some REP in the past, possibly using dialected aproach. Maybe it was even from you, @greggirwin :-)map-each
](https://gitlab.com/hiiamboris/red-mezz-warehouse/-/blob/master/foreach-design.md#separation):>> a: [ "x" "y" "z" "e" ] == ["x" "y" "z" "e"] >> form a == "x y z e" >> rejoin map-each/eval [x | _] a [[x "-"]] == "x-y-z-e"
loop
(and can be interface compatible, delegating to the current loop
native when possible), but it also overlaps with some new HOF ideas from @hiiamboris. accumulate: function [ "Applies fn cumulatively to acc and each value in series, updating acc" series [series!] fn [any-function!] "A function of two arguments" acc ][ foreach item series [acc: fn acc item] ] >> accumulate next a: [ "x" "y" "z" "e" ] func [a b][rejoin[a "-" b]] first a == "x-y-z-e"
to path! compose to block! quote toto/(titi)
>> to-path compose to-block first [toto/(titi)] == toto/a
>> form ["x" "y" "z" "e"] == "x y z e" >> replace/all form ["x" "y" "z" "e"] space "-" == "x-y-z-e"
>> concat ["x" "y" "z" "e"] #"-" == "x-y-z-e"
>> a: [ "x" "y" "z" "e" ] == ["x" "y" "z" "e"] >> rejoin map-each/eval [x | _] a [[x "-"]] == "x-e-"
new-each.red
is the proper include file, you're using an outdated and experimental designneweach☠
view [ text "Value:" sli: slider text react [face/text: form round sli/data] ]
cool-slider: function [prompt [string!]] [ compose/deep [ panel [ text (prompt) sli: slider text react [face/text: form round sli/data] ] ] ] view compose [ below (cool-slider "First value:") (cool-slider "Second value:") ]
"sli: word is not bound to a context"
. This makes sense, but I don't how to make something I can re-use, but where the parts interact with each other. What's the right way of doing this?func
sli
conflict).gensym
from that.gen-sym: func [/with 'word /reset /no-count /local count] [ count: [0] count/1: add 1 either reset [0] [count/1] ; Using codepoints here because my editor doesn't like the characters. ; Editing alignment goes wonky for the insertion point. to word! rejoin [ #"^(2989)" ; #"⦉" left binding bracket any [word #"^(1F70)"] ; #"🜀" aether :^) either no-count [][count/1] #"^(298A)" ; #"⦊" right binding bracket ] ] proxy-sym: func [word][gen-sym/with/no-count :word] loop 3 [print gen-sym] loop 3 [print gen-sym/with #"^(FFFC)"] print proxy-sym 'a print proxy-sym 's
gensym
was just this. 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 ]
🜀
directly, but you never know in today's world.gensym
is to generate unique symbols, but it doesn't tell you that without a doc string. :^\ I'll fix that.cool-slider: func [prompt [string!] /local ctx] [ ; normally you'd need a copy/deep here, but compose/deep will do that ctx: context [ sli: none code: [ panel [ text (prompt) sli: slider text react [face/text: form round sli/data] ] ] ] compose/deep ctx/code ] view compose [ below (cool-slider "First value:") (cool-slider "Second value:") ]
compose/deep copy/deep ctx/code
though.)>> a: context s: [b: copy [1] p: 'b/1] >> b: context s >> b/b/1: 2 >> mold/flat a == "make object! [b: [1] p: b/1]" >> mold/flat b == "make object! [b: [2] p: b/1]" >> get a/p == 2 >> get b/p == 2 >> a/p =? b/p == true
react
just can't work properlycompose/deep
but didn't test with a path. The double copy kind of hurts. :(;
).parse [thru ";;;" copy body to ";;;"]
. instead of something more complex ;)parse [thru ";;;" copy body to ";;;"]
this rule will fail even to parse itself (body will be " copy body to "
)parse [thru ";;;" copy body to ";;;"]
this rule will fail even to parse itself (body will be " copy body to "
)load/as
some file>> load/as %apple-touch-icon.png 'png == make image! [180x180 #{ 4C69714C69714C69714C69714C69714C69714C69714C69714C...
help load
in the consolesh ë λ make ~/Drafts/Red/mursa red -o build/mursa -r src/main.red ** Script Error: Invalid compressed data - problem: -3 ** Near: script: decapsulate if none? script build/mursa make: build/mursa: No such file or directory make: *** [Makefile:12: test] Error 127
ʕ λ red -o build/mursa -r src/main.red ~/Drafts/Red/mursa -=== Red Compiler 0.6.4 ===- Compiling /home/v/Drafts/Red/mursa/src/main.red ... ...compilation time : 795 ms Target: Linux Compiling to native code...
parse
foreach word (split string #" ") [
-> foreach word split string #" " [
(no parens necessary)return trim/head to-string result
-> trim/head to-string result
(the last value in a function is implicitly returned)wrap: func [string max-len] [ acc: 0 trim/head form collect [ foreach word (split string #" ") [ either acc >= max-len [ sep: "^/ " offs: 0 ] [ sep: #" " offs: acc ] acc: offs + length? word keep reduce [sep word] ] ] ]
"Those who are blessed with the most talent don't necessarily outperform everyone else. It's the people with follow-through who excel."
"[94m[1mYour mind will answer most questions if you learn to relax and wait for the answer.[0m"
result: copy ""
pick
with a logic! index instead of either
expression (but many will find it harder to read):wrap: func [string max-len] [ acc: 0 trim/head to-string collect [ foreach word (split string #" ") [ set [sep offs] reduce pick [["^/" 0]["" acc]] acc >= max-len acc: offs + length? word keep rejoin [sep word] ] ] ]
rejoin
?rejoin [str1 "-" str2 "..." str3]
newline
crossplatform?lf
(linefeed).>> text: "abc^M^/def" == "abc^M^/def" >> write %__abc.txt text >> read %__abc.txt == "abc^/^/def"
write-newline: does [ #either config/OS = 'Windows [ write-stdout "^/" ][ write-stdout "^M^/" ] ]
stdout
has special behavior under the current simple-IO system.>> text: "abc^/^/def" == "abc^/^/def" >> write %__abc.txt text >> read/binary %__abc.txt == #{6162630D0A0D0A646566} >> to string! read/binary %__abc.txt == "abc^M^/^M^/def" >> read %__abc.txt == "abc^/^/def"
console not support 'input-stdin'
from this part of code:unless value? 'input-stdin [ write-log "console not support `input-stdin`" do red-version-error exit ]
input-stdin
, i also assume, that the server also don't see load-json
word. that thing makes me frustratedred > write-newline: does [ > #either config/OS = 'Windows [ > write-stdout "^/" > ][ > write-stdout "^M^/" > ] > ] >
crlf
. That covers any differences.trim/with "(Thomas Edison)" "()"
red > write-newline: does [ > #either config/OS = 'Windows [ > write-stdout "^/" > ][ > write-stdout "^M^/" > ] > ] >
newline
won't expand to ^M^/
while under Windows?newline (^/)
will be converted to ^M^/
when writing to file/stdout under Windows.^M^/
in all cases.> trim/all/with "(Thomas Edison)" "()" >
trim/lines trim/with "(Thomas Edison )" "()"
$PATH
?~/.Red
.a: to-path <b> type? a ; path! type? a/1 ; tag! a: to-path [<b> <c>] type? a; path! type? a/2 ; tag! a: to-path [#b #c] type? a; path! type? a/1 ; issue! type? a/2 ; issue! a: to-path [[b c] d] type? a ; path! type? a/1 ; block! probe pick a/1 1 ; b
block!
flavor.path!
rules evolve, but keeping the literal forms simple and providing helpers for data and domain specific use are ways to experiment.size?correctly displays the bytes of a 100MB file but
-225209311when the file is 4GB
4,069,757,985 bytes
2 ** 32
to itls
(shell command)?foo: func [dir-value /local result][ result: sort read dir-value forall result [ unless dir? first result [ print [first result size? first result] ] ] ]
duin linux to find out the file size
call/output {du -b 1.png} size: "" print size
call/output {du -b 1.png | cut -f -1} data: "" print size
/shell
call/shell/output {du -b 1.png | cut -f -1} size: ""
>> digits: charset [#"0" - #"9"] == make bitset! #{000000000000FFC0} >> parse "1234 other stuff" [copy size some digits] == false >> size == "1234"
bin_file: read/binary random_file
txt_file: read random_file
foo: func [val][ either none? attempt [read to file! val]["It's a binary file"]["Not a binary file"] ]
exists? %tex2t.txt
a: "12345" find/match a "12" ; "12345" find/match/tail a "12"; "345"
git
isn't your thing, there must be some user-friendly clients.. I can't advise here.-c
it builds an external runtime so future compiles are fast if you don't change anything there. That way only your first build is slow. If you use -r
(release mode) the entire runtime is compiled into the EXE which may take a minute. The readme shows all the options.parse
is your friend for building languages/dialects, and you'll learn a lot by doing that. Start simple and have fun.USAGE: PUT series key value DESCRIPTION: Replaces the value following a key, and returns the new value. PUT is an action! value. ARGUMENTS: series [series! port! map! object!] key [scalar! any-string! any-word! binary!] value [any-type!] REFINEMENTS: /case => Perform a case-sensitive search. RETURNS: [series! port! map! object!]
issue!
would have vs. just converting it later?all-word!
key type btw.put
:>> m: #() == #() >> m/(#a): 1 == 1 >> m/(#a) == 1 >> m == #( #a 1 ) >> select m #a == 1 >> put m #a 2 *** Script Error: put does not allow issue! for its key argument *** Where: put *** Stack: >> extend m [#b 3] == #( #a 1 #b 3 )
issue!
can certainly be used as symbols, but for a bit of background, they were strings in Rebol. We have had a *lot* of discussions about this, and there is a *possibility* that they could end up as a hybrid. Sometimes a string, sometimes an word, based on their content. e.g. if they start with a digit, they would be a string, so they could be used for UUIDs, serial numbers, record IDs, etc., without symbol table limitations. There is a huge dark side to this IMO, but the details would be hidden in all but code that leverages them, like you want to. I used them heavily as strings, in R2, so tend to be biased in that direction. Now we do have ref!
values though.pair!
valuessplit "test" ""
return a block of characters?.comb
in Perl/Raku.""
matches everything. And in find
a special case is made to return none
to (my guess) avoid endless loops.split
makes sense.parse "text" [collect any keep skip]
a workaroundparse "text" [collect keep pick to end]
another oneforeach ch str [...]
work for you?split
func will support something close, in split 1
, but you'd still get strings for each element, not chars. collect [foreach ch "test" [keep ch]]
.unique "test"
to filter dupes.explode
somewhere and @rebolek join/with
some of the discussions about split have been going on for decades. explode
explode: func [ "Explodes a string into a block of separate characters" str [string!] ][ collect [foreach i str [keep i]] ]
split
is a function!, you can do source split
to see how it does things right now. Can roll your own split
off of that.chunk
into same size pieces. seems like elemental things are more difficult than they might be.split
just parses.extract
source extract
explode
that works on any-string! values?Extract
uses the same series type as the input, if you don't use /into
.>> extract "testing" 2 == "tsig"
Red []
system/script/header
none
for me?"load
your script instead of do
ing it, you can access the header:script: load %script.red header: script/2
do script
.standard
like "template" or "rubric"?system/standard/header
is a template and is meant when you want to create a script programmatically. system/script/header
should hold the header of the actual script.parent
and path
in the header. Should I be traversing through files and adding the parent and path? On that same note, should system/script/header
contain the header of the script that was originally called? Or the header of the currently-visited script?header
*during* script loading phase (#include
, do
), and after it's loaded and accessed from other functions.do
a file from console itself. During do
the header is changed, and then reverted after it returns.Red [title: "utility function"] print ["including" system/script/header/title] ;) shows "utility function" show-title: does [alert system/script/header/title] ;) shows title of the program that calls it
script
as the primary term for accessing headers, and if we're building a structure of them, do we just call it system/headers
? Or do we still want an intervening word for clarity, to distinguish it from the Red system itself, like system/app/headers
.Include
may pull from different locations, which works for files today, but will apply to modules and packages in the future. When all is said and done, you don't have a tree of files, but their content merged. We may want that for headers as well, but certainly not for everything. e.g. you want a single name and version for the app, which is not overridden.contexts
😄about
in the console pleasezlib-flate -uncompress
but the Red command decompress
generates an errordeflate/uncompress
is all in R/S, so we should be able to debug it. Another test would be to take the same input data, compress it with Red, and see if the binary output matches the one from zlib-flate
.deflate
algo rules.zlib-flate
, as a quick test, to make sure it's not a short-data exception (static Huffman).compress/zlib/deflate
generates compressed data and the linux command zlib-flate -uncompress
succeeds to decompressed these generated data.decompress/zlib/deflate
succeeds to decompress the generated compressed dataSTATE-STORED
in the decoder is seeing an incorrect length, and if that aligns with static Huffman use. Only able to guess at a glance, since the code lacks comments. :^\000000 78 da bb d4 e2 bb 88 51 8d c5 a3 fa d9 d1 72 1d >x......Q......r.< 000010 23 55 c6 05 11 3f 97 30 26 b9 05 b1 49 25 ea ac >#U...?.0&...I%..< 000020 d5 64 91 4a 49 59 b6 d2 92 91 79 21 e3 92 e4 b2 >.d.JIY....y!....< 000030 d4 a2 54 43 3d 63 3d 83 e4 bc c4 dc 25 49 69 79 >..TC=c=.....%Iiy< 000040 e9 be ae 91 41 9e 8e 3e c9 69 79 25 30 76 52 7a >....A..>.iy%0vRz< 000050 5e 96 97 ab a3 9f 82 8f 7f a8 67 70 72 7a 5e 09 >^.........gprz^.< 000060 98 6b 03 e1 a6 e4 27 65 19 5a 9a 19 eb 1a 58 e8 >.k....'e.Z....X.< 000070 1a 59 26 96 34 ae 4c 2a 49 cf b4 30 31 30 35 b6 >.Y&.4.L*I..0105.< 000080 34 30 30 4b 2a 29 c9 f2 09 30 32 34 37 b4 b4 d0 >400K*)...0247...< 000090 35 4e ca 4d 4c 75 0c 0d 09 72 4d 2a 4e ae 90 34 >5N.MLu...rM*N..4< 0000a0 32 30 32 04 69 33 36 08 31 34 b4 32 35 b7 32 30 >202.i36.14.25.20< 0000b0 d0 36 30 02 92 49 25 45 99 46 66 06 26 86 a6 06 >.60..I%E.Ff.&...< 0000c0 20 4e 72 9a 5b 90 a3 9f b3 6b 52 72 3e d0 1b 49 > Nr.[....kRr>..I< 0000d0 99 c5 29 8e 01 1e 01 49 c9 99 15 0a a1 41 7e 56 >..)....I.....A~V< 0000e0 a1 61 ce 9e 56 06 86 56 6e 41 56 1e 46 16 e6 96 >.a..V..VnAV.F...< 0000f0 51 1e 9e 46 7e ae e6 8e 01 5e ca 01 11 0e e7 dc >Q..F~....^......< 000100 63 db 4f 4e f9 ff 26 e8 40 79 ed 84 f8 65 21 ff >c.ON..&.@y...e!.< 000110 3e c8 db 16 f9 5f be d5 f3 33 d5 a5 91 63 79 e7 >>...._...3...cy.< 000120 6a e9 03 8c 2a b2 e7 18 cd 4e dd b8 77 f3 e2 f6 >j...*....N..w...< 000130 49 81 11 37 e6 1b 4b c9 ec be 51 63 13 e4 b5 85 >I..7..K...Qc....< 000140 71 09 5b b3 73 c9 >q.[.s.< 000146
decompress/zlib/deflate
Red 0.6.4 for Windows built 2-Sep-2021/15:40:47+03:00 commit #579b9d3
Red 0.6.4 for Linux built 11-May-2021/6:20:25+03:00 commit #81d0416
actor
and where can I play around with them?money!
unwieldy to work with? I imagine it's being exposed from R2 but I'm having trouble getting it to USD$
like R2.actor
s in Red (yet).on-click
etcon-click
etc>> file-port: open %scraper.red *** Script Error: open does not allow file! for its port argument *** Where: open *** Stack: >> ? 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!]
...
which is used to return a lazy sequence of whatever givensay $fibonacci[^10]
to get the first 10 numbers in the sequencesequence [1 1] <function!> ; function has to match arity
port!
or some sort of stream structurezlib-flate -uncompress
gives 338 bytes lengthf: function [x] [ function [ y ] compose/deep [ print [ (x) y ] ] ] f "Hello" "you" ; (1) this does not work ( f "Hello" ) "you" ; (2) this neither h: f "Hello" h "you" ; (3) this does
context for x is not available
?a b c d e
expression, where any of a,b,c,d,e may be function calls that define some of these words to functions or operators. Then add arg/lit-arg/get-arg syntax on top of that, both for operators and for functions and you'll look into an abyss.apply
:apply: func [fn [any-function!] data [any-type!]][either block? data [do head insert data :fn][fn data]] apply f "Hello" "you" ;Hello you apply :append ["Hello " "you"] ;== "Hello you"
o: reactor [f: func [x][func [y] compose/deep [print [(x) y]]] a: "Hello" d: is [f a]] o/d "you" ;Hello you o/a: "Hey" o/d "you" ;Hey you
f: does [:f] f
would deadlock.function
possibly work?copy
is easy to apply, but hard to work around if Red applied it automatically. make function!
directly.a: [ [1] ] b: func [ value ][ same? here value ] c: body-of :b probe :b c/2: a/1 probe :b b a/1
b: context [ here: [1] return func [value] [same? here value] ]
apply
in your case (sadly, we don't have it in Red yet). I honestly find it hard to imagine real use cases where it's important.call
, forwarding output to a file and monitoring that file.>> send-request/data to-url "http://10.201.1.35:5001/" 'POST [] *** Script Error: value out of range: 1 *** Where: set-path *** Stack: send-request
decompress/zlib/deflate
: I made a mistake; Red 0.6.4 for Linux built 22-Nov-2018/2:40:38+02:00 commit #755eb94
does not generate an error to decompress the 2 files (333 bytes and 326 bytes)... but it generates 4 extra bytes compared with the linux command zlib-flate -uncompress
. PS decompress/zlib
and decompress/zlib/deflate
output the same result.decompress/zlib/deflate
should not be allowed, there is only decompress/zlib
OR decompress/deflate
!decompress/zlib/deflate
, the zlib
is used. https://github.com/red/red/blob/9aea165d97bdbf4c3c368a1a5c34fdc40272a133/runtime/natives.reds#L2723-L2739Error: data not in correct format
>> decompress/zlib/deflate bin 0 0 == #{ D2844DA2012604487BE6C5772C322501A058F9A401624652061A612CAD29041... >> decompress/zlib bin 0 == #{ D2844DA2012604487BE6C5772C322501A058F9A401624652061A612CAD29041... >> decompress/deflate bin 0 *** Script Error: data not in correct format: none *** Where: decompress *** Stack: >> decompress/_deflate bin 0 *** Script Error: decompress has no refinement called _deflate *** Where: decompress *** Stack: >>
decompress
is able to use only one compression method from zlib
, deflate
and gzip
. It should throw an error if multiple refinements is used, because it is confusing, that it silently chooses one of them. [decompress]
It should throw an error if multiple refinements is used, because it is confusing, that it silently chooses one of them.^/
is the newline character.^
is the escape character in Red. Use help char!
to see all the standard char values Red includes by default.>> a: "^/^/575^/^/^/^/" == {^/^/575^/^/^/^/} >> take/last/part a 2 == "^/^/" >> a == {^/^/575^/^/}
chop: func [ "Removes the last value in a series; returns series head." series [series!] "(modified)" /part "Specify the number of values to remove." length [integer!] ][ head remove skip tail series negate absolute any [length 1] ]
>> a: "^/^/575^/^/^/^/" == {^/^/575^/^/^/^/} >> chop/part a 2 == {^/^/575^/^/^/}
do
changed in last few month? do %file.red
but now getting error: Access Error: cannot open
and need to do do load %file.red
>> change-dir %/D/test == %/D/test/ >> >> do %test.red Hello World >> >> do %client-tools.red *** Access Error: cannot open: %common-tools.red *** Where: read *** Stack: do-file
>> >> do load %client-tools.red == make object! [ value: none result: none content-type: none multipart: none boundary: none url... >>
Access Error
%common-tools.red
insidedo file
descends into the directory of that file, but do load file
does not. So it may not find the other included file.load
ing it is the way to go. set-word! ['func | function | ...]
, but why don't you want to load it?parse
is the way to go.alpha-num: charset [#"A" - #"Z" #"a" - #"z" #"0" - #"9" ] other-ch: charset "-_?." word-ch: union alpha-num other-ch ws: charset " ^-^/" ws*: [any [ws]] =set-word: none =word: none set-word=: [some word-ch #":"] word=: [some word-ch] fn-word: ["function" | "func" | "does" | "has"] abc: func [][] def: function [][] ghi: does [] set 'jkl has [][] get-funcs: function [input [string!]][ parse input [ collect [ some [ s: set-word= e: ws* fn-word keep (copy/part s e) | "set '" ws* s: word= e: ws* fn-word keep (copy/part s e) | skip ] ] ] ]
funct
also;
is inside string or it's a comment.field
deneme: ask ">>" parse deneme [ "sh" change c: ["a" b: ["o" | "oq"]] (rejoin ["â" c/b]) ] print deneme
change
's logicdeneme: ask ">>" parse deneme [ "sh" change *"a" ["o" | "oq"] "2" *"â" ] print deneme
red >> parse x: "shao" ["sh" change [#"a" set b [#"o" | "oq"]] (rejoin [#"â" b])] x == "shâo" >> parse x: "shaoq" ["sh" change [#"a" set b [#"o" | "oq"]] (rejoin [#"â" b])] x == "shâoq"
>> parse x: "shao" ["sh" pos: "a" ["o" | "oq"] (? pos pos/1: #"â")] x POS is a string of value: "ao" == "shâo"
variable:
really hold?>> parse "abcd" [pos: (? pos) 2 skip pos: (? pos) to end] POS is a string of value: "abcd" POS is a string of value: "cd"
>> parse "abcd" [pos: (print index? pos) 2 skip pos: (print index? pos) 1 skip pos: (print index? pos) to end] 1 3 4
>> parse inp: "hello" [pos: (print (pos = inp)) 1 skip pos: (print (pos = next inp)) to end] true true
next inp
do?var:
in parseellipsize-at
is destructive?_print
, and see what people think. x
that is similar to to x
but if doesn't find x
it consumes input until the end?opt-to
?to end
part though.finally-opt
?end-if-no
*** Script Error: integer! overflow/underflow *** Where: to *** Stack: to-integer
Read
which forbids me to download a web page on red.Red
? listen and replace programcurses
library. You can do fancy things with curses
, but it's not GUI console.scale 0.2 0.2
(or what works for you, so that the box fits your canvas)Draw
can do beziers, but I don't know what SVG paths use. Maybe @rgchris can say.d="..."
attribute and convert it to shape
parameters like so: svg/vid/to-draw-path svg/parse-path "M100,100l100,00"
view [canvas: base 200x200 white draw compose [[line-width 5 shape [ line 0x0 90x30 30x90 ]]]]
line
it did close in earlier versionsclose
close
but don't remember the resulting design decision.to-image
?? draw
lay: layout [p: panel [box 20x20]] view/no-wait lay img1: to-image lay unview lay
Rebol p: load %pic.txt == {iVBORw0KGgoAAAANSUhEUgAAANsAAACnCAIAAAA a: debase p == 64#{ iVBORw0KGgoAAAANSUhEUgAAANsAAACnCAIAAAA x: load a == make image! [219x167 #{ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF Red p: load %pic.txt == {iVBORw0KGgoAAAANSUhEUgAAANsAAACnCAIAAAAXAb6tAABoYElEQV a: debase p == #{ 89504E470D0A1A0A0000000D49484452000000DB000000A7080 x: load a *** Access Error: invalid UTF-8 encoding: #{89504E47}
z: load/as a 'png == make image! [219x167 #{ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
link: function [link-block [block!] /local result] [ result: "" append result rejoin [{<a href="} (to-string link-block/link) {">} link-block/title {</a>}] append result rejoin [{<br><b>} link-block/site {</b> }] append result rejoin [{<span>} link-block/info {</span><br><br>}] return result ]
func
several times, it replace more, I think result
is not local here, do I have to use copy
for local variable?/local
?result
is a word, which can be local or not""
is a string, and you have to copy the string if you don't want to modify in place/local
, which is easy to test, you will end up with result
being a global word, which may conflict with others in unintended ways. It can be useful at times, especially in small scripts, but you can also use function
to capture local set-words and then use /extern
to expose only those you want. { }
should be two spaces and the third { }
should be one space.> "hello world foo" >
> hello world foo >
>> trim/lines "hello world foo" == "hello world foo"
parse
- flattens spaces to just one, uses trim
to remove from head/tail:>> despace: func [string][to-string parse trim/head/tail copy string [collect any [some #" " keep (#" ") | keep skip]]] >> despace " This is a test. " == "This is a test."
parse
solution:change
much in my parse history, as it messes with the original string, ditto for remove
, as I liked to use markers and my brain was just too busy, when backtracking was needed :-)text: " hello world foo " fix-spaces: [ remove any sp any [ remove [any sp end] | change some sp sp | skip ] ] parse text fix-spaces >> text == "hello world foo"
rejoin parse " hello world foo " [collect [any sp any [some sp not [sp | end] keep (sp) | any sp end | keep skip]]] ;== "hello world foo"
foo: [action: function [value] [ first value]]
>> foo/action == function >> do foo/1 "sdf" *** Script Error: action: needs a value
action
? do append append clear [] select o 'action "sdf" ;== #"s" do append reduce foo "sdf" ;== #"s" do reduce head insert ["sdf"] foo ;== #"s"
parse
:text: " hello world foo " parse trim text [any [remove some space insert " " | skip]] ; == "hello world foo"
change
?parse trim text [any [change some space " " | skip]]
trim/all
is 10x faster.change
already mentioned, I just want to show a different way.#! /usr/local/bin/red Red [ Title: "Thread tests " Author: "Francois Jouen" File: %thread.red Needs: View ] ; code must be compiled with -e option (encap option) ??? ; e.g. red -r -e thread.red random/seed now/time/precise img: make image! reduce [640x480 black] plot: [line-width 1 pen green line 0x240] x: y: 0 height: 400 t1: t2: none scheduler: make object! [ threadCount: 0 threadList: [] delay: 0.0 appendThread: func [ athread [object!] ][ append threadList athread threadCount: threadCount + 1 ] startMessageLoop: func [] [ i: 1 while [i <= threadCount] [ cthread: threadList/:i cthread/tTrigger: cthread/tCount % cthread/tPriority cthread/tExecute cthread/tCount: cthread/tCount + 1 i: i + 1 ] ] ] rThread: make object! [ tNumber: 0 ; thread number tPriority: 1 ; thread priority [1 to N (high to low)] tCount: 0 ; thread calls counter tTrigger: 0 ; trigger for special events such as data visualization tExecute: none ; func as code pointer ] clearScreen: does [ x: 0 canvas/image/rgb: 0.0.0 clear plot compose/into [line-width 1 pen green line 0x240] plot ] showImage: does [ x: x + 1 if x > 640 [clearScreen] y: 40 + multiply height / 2 1 + sin 0.05 * x append plot as-pair x y ;show points according to the thread priority if t1/tTrigger = 0 [canvas/image: draw img plot do-events/no-wait] ] showTime: does [ ct: now/time if t2/tTrigger = 0 [fT2/text: form ct do-events/no-wait] ] initThreads: does [ ; create threads 1 and 2 (make required) t1: make rThread [tNumber: 1 tPriority: 10 tExecute: :showImage] t2: make rThread [tNumber: 2 tPriority: 30 tExecute: :showTime] ;register threads scheduler/AppendThread t1 scheduler/AppendThread t2 ] ;************ test program ***************** view win: layout [ title "Threads Demo" base 640x1 blue return canvas: base 640x480 img return base 640x1 blue return ft2: field 100 center f: field 30 "10" text 30 "High" sl: slider 120 [ v: 1 + to-integer (sl/data * 19) t1/TPriority: 21 - v f/text: form v ] text 30 "Low" button "Clear" [clearScreen] button "Start" [ stop: false until [scheduler/StartMessageLoop stop] ] button "Stop" [stop: true] button "Quit" [quit] do [initThreads sl/data: 50%] ]
do-events/no-wait
omits some events in this case.data: [ lots: [ foo: none ] ]
foo
evaluate to none
print data/lots/foo
print data/lots/fake
it's also none
.type?
for latest path elementfind
on the keys through the path. If your structures are strictly key-value, use find/skip 2
.>> data/lost/foo *** Script Error: path data/lost/foo is not valid for none! type *** Where: catch *** Stack:
flat-path: data/lots/lot/KBKCode
*** Script Error: context for data is not available
can happens?probe data
is printing it to console, so data
is existsfind-path-to-tag: function[data wrd] [ print "find-path-to-tag" wrd: to-word wrd list: copy [] walk: function [data] [ foreach [k v] data [ if (k = wrd) [append list to-word k break] if block? v [ append list to-word k walk v ] ] ] walk data to-path compose [data (list)] ; so it can be bug here? (I need to return ever path started with data) ]
data
context to make it simple data
as path element?data
, there's data
word bound to find-path-to-tag
func, and data
word bound to some outer context whatever it isbind
it appropriately where it's more convenient for you, or pass original data
word as argumentfind-path-to-tag: function [data wrd] [ ;print "find-path-to-tag" wrd: to-word wrd list: copy [] walk: function [data] [ foreach [k v] data [ case [ k = wrd [append list to-word k break] block? v [ append list to-word k walk v ]]]] walk data to-path bind compose [data (list)] system/words ] data: [foo: [bar: none baz: none]] set 'data/foo/baz "123" find-path-to-tag data 'baz ;== data/foo/baz get find-path-to-tag data 'baz ;== "123"
object
on top level to get from:data: [ aaa: "aaa" lots: [ object: [ bar: "bbb" ] ] ]
data: [ aaa: "aaa" object: [ bar: "bbb" ] lots: [ ] ]
data: [ aaa: none ; one or more tags could be on this level lots: [ bbb: none ; one or more tags could be on this level object: [ bar: "bbb" ] ] ]
move
?data: [ aaa: "aaa" lots: [ bbb: none object: [ bar: "bbb" ] ] ] move/part data/lots/object data 2 probe data == [ bar: "bbb" aaa: "aaa" lots: [ bbb: none object: [] ] ]
>> data: [ [ aaa: "aaa" [ lots: [ [ bbb: none [ object: [ [ bar: "bbb" [ ] [ [ ] [ ]() >> move/part at data/lots 3 data 2 data == [ object: [ bar: "bbb" ] aaa: "aaa" lots: [ bbb: none ] ]
a: 12 b: 76 test: #(n1: a n2: b) print test/n1 == a print test/n2 == b
12and
76as results ?
get test/n1
call
to Curl might be used?move/part (at data/lots 3) data 2 data
data
word mean?(at data/lots 3)
find position of object
with it's block2
is size of moving part (word and it's block)data
?data: [aaa: "aaa" lots: [bbb: none object: [bar: "bbb"]]] == [aaa: "aaa" lots: [bbb: none object: [bar: "bbb"]]] >> data: morph data ['a 'b 'c ['d 'e 'f ['g 'h]]][a b f [g h] c [d e]] == [aaa: "aaa" object: [bar: "bbb"] lots: [bbb: none]]
f
work here?:data: [aaa: "aaa" lots: [bbb: none object: [bar: "bbb"]]] () morph data ['a 'b 'c ['d 'e f: [quote object: block!]]][a b f c [d e]] ;== [aaa: "aaa" object: lots: [bbb: none]]
f
because it might have been defined like this:f: [quote object: block!] morph data ['a 'b 'c ['d 'e f]][a b f c [d e]]
morph [1 2 3] ['x 'x 'x] [x ...]
at your own peril ;)>> morph [1 2 3] ['x 'x 'x] [x] == [3]
x
:>> morph [1 2 3] ['x 'x 'x] ['x ...] == [1 2 3] >> morph [1 2 3] ['x 'x 'x] ['x] == [1]
morph data [ahead [set-word! block!] 'w [f: [quote object: block!] | 'x ...] | 'y ...][('y ...) 'f 'w ['x ...]] == [aaa: "aaa" object: [bar: "bbb"] lots: [bbb: none]]
>> unset 'x >> either :x [1][0] *** Script Error: block did not return a value *** Where: either *** Stack: >> case [:x [1] 'else [0]] *** Script Error: block did not return a value *** Where: case *** Stack:
x
is unknown, sometimes unsetvalue? 'x
?either all [not unset? :x :x] [1][0]
either any [unset? :x :x] [1][0]
, and I agree explicit variant is probably the most readableunset
sometimes works as truthy, sometimes doesn'teither
condition to get unset *by mistake*?all
/any
, but not for if
/either
/case
if
, either
, all
/any
, but not for case
if
, all
/any
but not for either
/case
data: [ aaa: "aaa" lots: [ bbb: none boo: [ name: "sf" ] object: [ bar: "bbb" ] customer: [ baz: "ccc" ] ] ] remove-last: function [blk] [ head clear back tail copy blk ] find-path-to-tag: function[xdata wrd] [ wrd: to-word wrd list: copy [] walk: function [xdata] [ index: 0 ; in?: false foreach [k v] xdata [ index: index + 2 if (k = wrd) [ ; append list index - 1 break ] if block? v [ append list to-word k walk v ] ; list: remove-last list ] ] walk xdata to-path compose [data (list)] ] find-path-to-tag data 'object
== data/lots/boo/object/customer
== data/lots/object
context [ ok: no list: copy [] walk: func [data wrd /local k v] [ foreach [k v] data [ case [ wrd = k [append list to-word k ok: yes break] block? v [ append list to-word k walk v wrd list either ok [break][take/last list] ] ] ] ] set 'find-path-to-tag func ['data wrd] [ ok: no clear list walk get data wrd list to-path head insert list data ] ] find-path-to-tag data 'object
take/last
is do so. Was it introduces recently or everyone had forgotten about him at the timeclear back tail
is that it returns the last element that is often not needed (neither is it needed here, but shorter).case
here? It's seems that there is not reason in itwalk
.ok: wrd = k [append list to-word k break]
c-string!
is there from the beginning ;-)#!/usr/local/bin/red Red [ ] ;--A magic square of singly even order has a size that is a multiple of 4 plus 2 ;--(e.g. 6, 10, 14). ;--the sum of each row and column, and both diagonals must be equal to the "magic number" ;--based on FreeBasic Rosetta code sample magicSquare: function [n [integer!] ][ if any [n < 6 (mod n - 2 4) <> 0] [print "Error: incorrect order value!" exit] ;--we make a block of blocks to simulate a matrix array: copy [] v: make vector! n repeat y n [append/only array to-block v] magicNumber: n * (n ** 2 + 1) / 2 n2: n / 2 q2: n2 ** 2 l: n - 2 / 4 x: to-integer n2 / 2 + 1 y: nr: 1 until [ if array/:x/:y = 0 [ array/:x/:y: nr ;--A array/(x + n2)/(y + n2): nr + q2 ;--B array/(x + n2)/(y): nr + q2 * 2 ;--C array/(x)/(y + n2): nr + q2 * 3 ;--D either (mod nr n2) = 0 [y: y + 1] [x: x + 1 y: y - 1] nr: nr + 1 ] if x > n2 [ x: 1 while [array/:x/:y <> 0] [x: x + 1] ] if y < 1 [ y: n2 while [array/:x/:y <> 0] [y: y - 1] ] nr > q2 ] ;--swap left side repeat y n2 [ repeat x l [ array/:x/:y: array/(x)/(y + n2) ] ] ;--make indent y: to-integer round (n2 / 2) + 1 array/1/:y: array/1/(y + n2) array/(l + 1)/(y): array/(l + 1)/(y + n2) ;--swap right side repeat y n2 [ x: n - l + 2 while [x <= n] [ array/:x/:y: array/(x)/(y + n2) ] ] ;--check columms and rows repeat y n [ nr: l: 0 repeat x n [ nr: nr + array/:x/:y l: l + array/:y/:x ] if any [nr <> magicNumber q <> magicNumber][print "Error : value <> magicNumber" ] ] ;--check diagonals nr: l: 0 repeat x n [ nr: nr + array/:x/:x l: l + array/(n - x + 1)/(n - x + 1) ] if any [nr <> magicNumber q <> magicNumber][print "Error : value <> magic_sum" ] ;--results print ["Single even magic square size: " n "*" n] print ["The magic number: " magicNumber] print ["Square matrix:"] repeat y n [ line: copy " " repeat x n [append line pad array/:x/:y 4] ;--pad for aligment print line ] print "Done" ] magicSquare 6
unset!
is tricky, because it's a ghost value and is also truthy, which seems counterintuitive at times. We can reason about it, but also want to keep it in the shadows as much as possible. I'm torn about whether if
should error or either
should not, but they should be consistent with each other no matter what. With case
I'm not so sure. Having it explicit in the expressions you write may be better.unset!
.if
. We don't want to encourage using unset!
as a feature. If a few advanced pieces of code are a tiny bit uglier, so be it.>> x *** Script Error: x has no value *** Where: catch *** Stack: >> :x >> if :x ['huh?] == huh? >> not :x == false
:x
in the console is a special case IMO.unset!
should not exist, so I'm not the best person to talk about this topic :)unset!
is ugly by definition and it must stand out as much as possible so you guys will finally see the light :P:x
not catching typos really makes no sense.:x
for functions and other word-active values (which in red maybe is only functions? i don't recall)unset
one of such active values ;)unset!
is to catch typos.word!
snone!
. As it stands we have outdone 3 value logic, but balanced it on the side of truth(y).none
doesn't work for errors catching;--Recursive memoized with map! datatype fib: function [n] [ m: #(0 0 1 1 2 1) any [m/:n m/:n: (fib n - 1) + (fib n - 2)] ]
i: i + 1
, that kind of thing, presents the language as some remnant of the past.help
?help-string
view [size 800x600 title "Testing"]
RED
in the url!before
the text-list face is being updated. So, when I used the on-down
to look at face/selected, it gets the wrong result>> set [a b] [3 4] == [3 4]
>> info: [a: 1 b: 2] == [a: 1 b: 2] >> set [info/a info/b] [3 4] *** Script Error: invalid argument: info/a *** Where: set
set bind [a b] info [3 4]
if it's an objecton-down
triggers before the text-list has updated itself, so you do want to use on-change
or on-select
.view [text-list data ["A" "B" "C" "D"] on-down [print 'down wait 2]]
display-data
interrupts the flow in human time, because it takes a while to run.load
and to
is different, there is a table in the Wiki, I try to find it. That doesn't mean it's definite and can't be changed.countdown/visible?: false
is not taking effect in time. Would anyone know of a way to force this update to happen or perhaps a better way to structure this code so, I don't have to break the event loop flow?to
does not always fall back to load
from strings. In the case of date, the main conversion is used for [epoch times](https://github.com/red/docs/blob/master/en/datatypes/date.adoc#conversions).1
imprinted on Ubuntu, but not on W10bo@Bo-Legion-i7:~/Downloads$ ./red-064 /home/bo/.red/console-2018-11-22-8164: error while loading shared libraries: libcurl.so.4: cannot open shared object file: No such file or directory bo@Bo-Legion-i7:~/Downloads$ sudo apt install libcurl4 Reading package lists... Done Building dependency tree Reading state information... Done libcurl4 is already the newest version (7.68.0-1ubuntu2.7).
test: "testing^/" take/last/part test 1
take/last
?trim/tail/with test lf
?trim/tail
Red [Title:Prime Finder] max: ask "give an integer: " numbs: [] repeat i (load max) [ numbs: append numbs i ] i: 2 while [i < (length? numbs)] [ j: (i + 1) while [j <= (length? numbs)] [ if (pick numbs j % pick numbs i = 0) [ print [pick numbs j " " pick numbs i] remove numbs j] j: j + 1 ] i: i + 1 ]
numbs/:i
numbs/(i + j)
(as well as numbs/(i)
)? at
may help you hereremove
takes only one argument? at
is not immediately clear to you, I suggest skimming thru http://www.rebol.com/docs/core23/rebolcore-6.htmladd (1, 2)
, just add 1 2
is enoughreduce
takes only one argument - a series and removes the value at the same index skip
and at
- they are similar, but not equivalentpick
?next
just returns the series at the next index and doesn't sets it.list: next list
skip
uses offset and that's why 1 more than when using indexi: 2 while [i < (length? numbs)] [ numbs: at numbs (i + 1) while [(tail? numbs) = false] [ if (first numbs % numbs/:i = 0) [remove numbs numbs: head numbs] ] i: i + 1 ]
op!
- infix functions of two arguments like %
are evaluated before functions, so Red tries to find numbs % numbs/:i
first and numbs
is a block!
valuei: 2 while [i < (length? numbs)] [ numbs: at numbs (i + 1) while [(tail? numbs) = false] [ print (first numbs) either ((first numbs) % numbs/:i = 0) [ remove numbs ] [ numbs: next numbs ] ] numbs: head numbs i: i + 1 ]
4 print 4 => unset numbs => [4 5] first numbs => 4 numbs/:i => 5 % 4 numbs/:i => 4 4 = 0 => false numbs => [4 5] numbs: next numbs => [5] either false [remove => [5] numbs => [5] tail? numbs => false = false false => true numbs => [5] first numbs => 5 5 print 5 => unset numbs => [5] first numbs => 5 numbs/:i => none % 5 numbs/:i => make error! [code: 310 type: 'script id: *** Script Error: none! type is not allowed here *** Where: % *** Stack: show-deep-trace trace-deep also
Red [Title:Prime Finder] max: ask "give an integer: " numbs: [] repeat i (load max) [ numbs: append numbs i ] i: 2 while [not numbs/:i = none] [ comp: numbs/:i numbs: at numbs (i + 1) while [(tail? numbs) = false] [ either ((first numbs) % comp = 0) [ ;i is also relative to the current position remove numbs ] [ numbs: next numbs ] ] numbs: head numbs i: i + 1 ] print numbs
show-deep-trace
for the new instrumentation (which is a bit buggy still)remove-each
:prime-sieve: function [ "Finds the prime numbers less then or equal to n" n [integer!] "upper limit" ][ primes: make block! n / log-e n append primes 2 i: 1 odd-n: collect/into [ while [n >= i: i + 2] [keep i] ] make block! n / 2 while [not empty? odd-n] [ append primes prime: take odd-n remove-each odd odd-n [zero? odd % prime] ] primes ]
>> print prime-sieve 200 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199
>> blk: [a b c d e f g] == [a b c d e f g] >> remove-at-index: func [series [series!] index [integer!]][head remove at series index] == func [series [series!] index [integer!]][head remove at series index] >> remove-at-index blk 3 == [a b d e f g] >> remove-at-index blk 5 == [a b d e g]
sieve
@GalenIvanov. :+1:remove-each
for example, other factors (like binding) come into play, but yes it works. Not to overload you. :^) Ultimately it comes down to the fact that blocks are *not* evaluated by default, so you *can* pass them around like thunks.for: func [current [integer!] end [integer!] process [block!]] [ if (not current = end) [ do process current for current + 1 end process ] ] index-print: func [index [integer!]] [print index] for 0 10 [index-print]
index-print
is getting its arg? By writing control flow funcs, you're diving right into the deep end. :^)index-print
would get its arg? Try do [index-print]
and see what happens.index-print
in the console, as that's the same thing.do
simply evaluates the block. What is in the block is evaluated. Blocks are simply data, and don't have arguments.for: func [current [integer!] endv [integer!] process [block!]] [ if (not current = endv) [ inner: func process/1 process/2 inner current for current + 1 endv process ] ] index-print: [[index [integer!]] [print index]] for 0 10 index-print
for
.for: function [ 'word [word!] start [integer!] end [integer!] body [block!] ][ do-body: func reduce [word] body index: start while [index <= end][ do-body index index: index + 1 ] ] index-print: func [index [integer!]] [print index] for i 0 10 [index-print i]
func reduce [word] body
do
and reduce
in the console. Play with words and lit-words. Note the special lit-arg
(literal word as an argument) in my for
. It shouldn't take long before things start to make sense.d: func [in [integer!]] [print in] ;function body t: func reduce ['in [integer!]] [d in]
for: func [current [integer!] endv [integer!] process [block!]] [ if (not current > endv) [ inner: func reduce ['i [integer!]] process inner current for current + 1 endv process ] ] index-print: func [index [integer!]] [print index] for 0 10 [index-print i]
for: function [ 'word [word!] ;--iteration counter; not local to loop start [integer!] ;--starting index end [integer!] ;--ending index step [integer!] ;--index step, default 1 body [block!] ;--data block to be executed ][ do-body: func reduce [word] body index: start while [index <= end][ do-body index index: index + step ] ] ;--test for i -10 10 5 [print i]
d: func [in [integer!]] [print in] t: func ['i] [d i] t 10
3.3
clause though - doesn't apply to Redi
evaluates next expression'i
does not evaluate words and paths only:i
never evaluates next token whatever it may bestr: {test24|test432|test9454|test011^/test342|test8745|test4|test637^/test1|test2|test3|test4^/}
test: parse str [collect [any [keep any to newline skip]]] b: [] repeat x length? test [ append/only b split test/:x "|" ] probe b
b: [["test24" "test432" "test9454" "test011"] ["test342" "test8745" "test4" "test637"] ["test1" "test2" "test3" "test4"]]
split
:)parse
instead of another split here?any to
cannot possibly match more than oncesplit
it might be eitherstr: {test24|test432|test9454|test011^/test342|test8745|test4|test637^/test1|test2|test3|test4^/} split str [first by lf then by "|"] == [["test24" "test432" "test9454" "test011"] ["test342" "test8745" "test4" "test637"] ["test1" "test2" "test3" "test4"] [""]]
split/group str ["|" lf] == [["test24" "test432" "test9454" "test011"] ["test342" "test8745" "test4" "test637"] ["test1" "test2" "test3" "test4"]]
split str [first by lf then by "|"]I get
*** Script Error: split does not allow block! for its dlm argument *** Where: split *** Stack: split
split/group str ["|" lf]I get
*** Script Error: split has no refinement called group *** Where: split *** Stack: split
d: func [in [integer!]] [print in] t: func ['i] [d i] t current
>> load-json to-json [a: 1 b: [c: 3]] == ["a:" 1 "b:" ["c:" 3]]
map!
for key/value pairs, instead of block!
.>> load-json to-json #(a: 1 b: #(c: 3)) == #( a: 1 b: #( c: 3 ) )
for: func [current endv [integer!] process [block!]] [ if (not current > endv) [ inner: func [i] process inner current for current + 1 endv process ] ] index-print: func [index] [print index] for 0 load ask "give integer: " [index-print i]
func
, inner
is being defined globally. You can do ?? inner
to see what it was defined as.> >> load-json to-json [a: 1 b: [c: 3]] > == ["a:" 1 "b:" ["c:" 3]] >
map!
for key/value pairs, instead of block!
.> >> load-json to-json #(a: 1 b: #(c: 3)) > == #( > a: 1 > b: #( > c: 3 > ) > ) >
data: {test24|test432|test9454|test011^/test342|test8745|test4|test637^/test1|test2|test3|test4^/} data1: parse data [collect [any [keep to newline skip]]] data2: [] repeat x length? data1 [ append/only data2 parse data1/:x [collect [any [keep to ["|" | end] skip ]]] ] probe data2
data1: parse data [collect [any [copy a1 to newline keep (parse a1 [collect [any [keep to ["|" | end] skip ]]]) skip]]]
>> block4: [[1] 1 [[1] [1 [1]] 1]] >> next block4 == [1 [[1] [1 [1]] 1]] >> next next block4 == [[[1] [1 [1]] 1]] >> next next next block4 == [] >> next next next next block4 == [] >>
block1: [1 1 1 1 1 1 1 1] block2: [[1] 1] block3a: [[[1]]] block3: [[[1]] 1 [1 [1]]] block3b: [[1] 1 [[1]]] block4: [[1] 1 [[1] [1 [1]] 1]] finder: function [ block /continue deepest ][ either continue [current: deepest] [current: 1] ;allows default value for argument if (tail? block) [return deepest] either (block? first block) ;if the first element is a block [either (finder/continue first block do current + 1) > ;if I go into the first block (finder/continue next block current) ;if I continue [finder/continue first block do current + 1] [finder/continue next block current]] [finder/continue next block current] ]
grid2: [ ['.' '.' '.' '.' '.' '.'] ['.' 'O' 'O' '.' '.' '.'] ['O' 'O' 'O' 'O' '.' '.'] ['O' 'O' 'O' 'O' 'O' '.'] ['.' 'O' 'O' 'O' 'O' 'O'] ['O' 'O' 'O' 'O' 'O' '.'] ['O' 'O' 'O' 'O' '.' '.'] ['.' 'O' 'O' '.' '.' '.'] ['.' '.' '.' '.' '.' '.'] ] repeat x length? grid2/1 [ print repeat y length? grid2 [ prin grid2/(reduce y)/(reduce x) ] ]
i: what-dir i append /filename
worksw: function ['reference [word!]] [in: func reduce [reference] [print i] in 5] w i
reference
wil refer to i
, i
will refer to 5
. But it is not the usual variable/value thing.>> f: func['a][?? a ?? :a] x: 1 f x a: x x: 1
reduce a
) - although if you need a block with the value like in your _func_ case, you cannot avoid the reduce
call.block: [1 2 3 4 5] feeder: function [inblock] [ duplicate: inblock insert copy/part duplicate (length? inblock) - 1 last inblock print duplicate ] ] feeder block
insert blk take last blk
take/last
print
outside the func then?> (empty? '()) #t > (empty? empty) #t > (empty? (first '())) ; first: contract violation ; expected: (and/c list? (not/c empty?)) ; given: '()
first
on an empty list throws an error, in Red it returns none
, which is why none? probe first probe []
is the same as none? none
which of course is true
. In the second example, the block [none]
isn't positioned at it's tail (after the last value), but tail? probe next probe [none]
is.first
on an empty list returning none? pick [] 1
yields none
but first []
gives an error, in Red both expressions evaluate to none
. So Red is essentially more consistent here, I'd say.none
values allows for cleaner, easier to read code than protecting against errors thrown or verbose handling of edge cases.probe
btw is probably one of the most valueable words when exploring Red as you can put in between expressions virtually anywhere without introducing side effects when learning, understanding and debugging Red code. block: [1 2 3 4 5] starter: func [inblock [block!]] [ either none? first inblock [ [] ][ insert starter copy next inblock first head inblock ] ]
starter
is supposed to do?swap
action:>> ? swap USAGE: SWAP series1 series2 DESCRIPTION: Swaps elements between two series or the same series. SWAP is an action! value. ARGUMENTS: series1 [series! gob!] At position (modified). series2 [series! gob!] At position (modified). >> b: [1 2 3] swap b back tail b == [3 2 1]
grid2
to be, or their exact contents, in your message [here](https://gitter.im/red/help?at=61babec54024f534f2c068b7). Single quoting, as other langs use for strings, isn't used in Red.>> grid2/1 == ['.' '.' '.' '.' '.' '.'] >> grid2/1/1 == '.' >> type? grid2/1/1 == lit-word! >> print grid2/1/1 .'
>> ? 'g' 'g' is a lit-word! value.
>> empty? [] == true >> empty? none == true >> empty? first [] == true
Red [Desc:find every combination of elements in a block] block: [1 2 3 4 5] starter: function [inblock [block!]] [ either empty? inblock [ [] ][ packer first head inblock reduce [starter copy next inblock] ] ] packer: function [f r [block!]] [ either empty? r [ none ] [ append reduce [orderer f first r] reduce [packer f copy next r] ] ] orderer: function [f r] [ either empty? r [ reduce [f] ] [ append reduce [f r] inserter reduce [first r] reduce [orderer f copy next r] ] ] inserter: function [f r] [ either empty? r [ none ] [ append reduce [f first r] reduce [inserter f copy next r] ] ] probe starter block
[[1 [[2 [[3 [[4 [[5] none] [[5]] [4 [none] [none] [4] none] none] none] [[4 [[5] none] [[5]] [4 [none] [none] [4] none] none]] [3 [none] [none] [3] none] none] none] [[3 [[4 [[5] none] [[5]] [4 [none] [none] [4] none] none] none] [[4 [[5] none] [[5]] [4 [none] [none] [4] none] none]] [3 [none] [none] [3] none] none]] [2 [none] [none] [2] none] none] none] [[2 [[3 [[4 [[5] none] [[5]] [4 [none] [none] [4] none] none] none] [[4 [[5] none] [[5]] [4 [none] [none] [4] none] none]] [3 [none] [none] [3] none] none] none] [[3 [[4 [[5] none] [[5]] [4 [none] [none] [4] none] none] none] [[4 [[5] none] [[5]] [4 [none] [none] [4] none] none]] [3 [none] [none] [3] none] none]] [2 [none] [none] [2] none] none]] [1 [none] [none] [1] none] none] none]
none
doing there if there was no none in the original?Red [Desc:find every combination of elements in a block]
Red [Desc: "Find every combination of elements in a block"]
>> blk: [Desc:find every combination of elements in a block] == [Desc:find every combination of elements in a block]
red
flag to have a block sitting there by itself .. normally one needs to copy them.find system/options/script "script.red"
? system/options
h: load/header system/options/script probe h/Red/Title #include %prime.red probe h/Red/Title
system/words/delete
in your function to refer to the global delete
, as in:test: func [/print] [system/words/print ['called pick [with without] print mold to refinement! 'print]] test/print ;-- called with /print test ;-- called without /print
Red [title: "Permutations"] lperm: func [inlist] [ either empty? inlist [[[]]] [mperm first inlist lperm next inlist] ] mperm: func [plett sletts] [ either empty? sletts [[]] [append operm plett first sletts mperm plett next sletts] ] operm: func [plett sletts] [ compose/deep either empty? sletts [[[(plett)]]] [[[(plett) (sletts)] (bperm first sletts operm plett next sletts)]] ] bperm: func [plett sletts] [ either empty? sletts [[]] [compose/deep [[(plett) (first sletts)] (bperm plett next sletts)]] ] lperm [a b c] ;== [[a b c] [b a c] [b c a] [a c b] [c a b] [c b a]]
Red [Purpose: "find every permutation of a given block"] ;simple recursion block: [1 2 3] permuter: function [ remaining [block!] /cont generated [block!] current [block!] ] [ if not cont [ generated: [] current: [] ] either not empty? remaining [ foreach e remaining [ append current e remaining: copy next remaining permuter/cont remaining generated current ] ] [ probe append generated current ] ] probe permuter block
[1 2 3] [1 2 3 1 2 3 3] [1 2 3 1 2 3 3 1 2 3 3 2 3] [1 2 3 1 2 3 3 1 2 3 3 2 3 1 2 3 3 2 3 3] [1 2 3 1 2 3 3 1 2 3 3 2 3 1 2 3 3 2 3 3]
help append
. :^)append/only generated current
puts every permutation in a separate block...probe reduce [current remaining] either not empty? remaining [ foreach e remaining [ nextp: append copy current e remaining: next copy remaining permuter/cont remaining generated nextp
[[] [1 2 3]] [[1] [2 3]] [[1 2] [3]] [[1 2 3] []] [[1 3] []] [[2] [3]] [[2 3] []] [[3] []] [[1 2 3] [1 3] [2 3] [3]]
probe reduce [current remaining] either not empty? remaining [ foreach e remaining [ nextp: append copy current e remaine: next copy remaining permuter/cont remaine generated nextp
== [[1 2 3] [1 3 3] [2 2 3] [2 3 3] [3 2 3] [3 3 3]]
probe reduce [current] either not empty? remaining [ foreach e remaining [ probe reduce [e remaining remaine] if (length? remaine) = 1 [swap remaining next remaining] nextp: append copy current e remaine: next copy remaining permuter/cont remaine generated nextp
... [[1 2 3]] [3 [2 3] [3]] [[1 3]] [2 [2] none] [[1 3 2]] [2 [1 2 3] [3 2]] [[2]] [2 [2 3] none] ...
either not empty? remaining [ foreach e remaining [ nextp: append copy current e remaine: copy remaining remove-each ii remaine [ii = e] permuter/cont remaine generated nextp
[[1 2 3] [1 3 2] [2 1 3] [2 3 1] [3 1 2] [3 2 1]]
[]
. It doesn't give me any errors, but the output is obviously wrong.-e
option--help
>> ? library! No matching values were found in the global context.
Red/System [] #import [ "ask.so" cdecl [ goask: "goask" [ return: [c-string!] ] ] ] probe goask
package main import ( "C" "fmt" ) //export goask func goask() *C.char { var input string fmt.Scanln(&input) return C.CString(input) } func main() { a := goask() fmt.Println(a) }
Red [Purpose: "using call, a go program, and the clipboard to replace ask"] prior: read-clipboard call/wait "go run ask.go" temp: read-clipboard print temp write-clipboard prior
Red [Purpose: "replace ask with go writing a file and red reading it"] call/wait "sudo ./goask" input: load read %input delete %input probe input
>> latest-of 0.3.40 ** Error: TypeError: NetworkError when attempting to fetch resource. ** Where: js-head-helper js-head info? latest-of main ** Near: [*** return js-head-helper source **] ** File: **'>http://hostilefork.com/media/shared/replpad-js/js-css-interop.reb ** Line: 225
include: function [filename] [ set [path: name:] split-path filename dir: clean-path what-dir change-dir path src: load/all name while [p: find src to issue! 'include] [ include p/2 remove/part p 2 ] append heap src change-dir dir heap ] heap: [] save %outfile.red append [Red []] include %filename.red
forall
was broken a month ago or solast list smth
?t: tail list t/-1: t/-1 + 1
>>: make op! function [ "Return series at an offset or shifts bits to the right" data [series! integer!] offset [integer!] ][ if integer? data [return shift-right data offset] skip head data offset ] <<: make op! function [ "Return series at an offset from tail or shifts bits to the left" data [series! integer!] offset [integer!] ][ if integer? data [return shift-left data offset] skip tail data negate offset ]
last
?python >>> f = "hi" >>> f += "hi" >>> f "hihi"
java > String f = "hi" > f += "hi" > f f ==> "hihi"
change back back tail list 1 + pick tail list -2
and Python's list[-2] += 1
you can guess what I would choose *any day*//: make op! function [ "Pick an item or get a slice (copy) from series, or return modulo of a scalar" data [series! number! money! char! pair! tuple! vector! time!] offset [number! money! char! pair! tuple! vector! time!] "Negative indexes are tail-relative in series" ][ unless series? data [return modulo data offset] either integer? offset [ pick either offset >= 0 [data][tail data] offset ][ copy/part skip either 0 <= i: offset/1 [data][tail data] i skip either 0 < i: offset/2 [data][tail data] i ] ]
slice
>> f: [1 2 3] >> f\1 3
f\a
or smth, how to define the meaning of backslash there?+
mean append
for series values? Sure. *Should* we? Could we make -
mean clear at ...
for series? You bet. Should we?>> f: [1 2 3 4] >> f: tail f == [] >> f/-1 == 4 >> f/-2 == 3
>> f/-1 : f/-1 + 1 *** Syntax Error: (line 1) invalid word at : f/-1 + 1 *** Where: set *** Stack: load
0
index access behavior.>> f: [1 2 3 4] == [1 2 3 4] >> f: at f 3 == [3 4] >> f/1 == 3 >> f/0 == none >> f/-1 == 2
>> ? | No matching values were found in the global context.
[|a |1 |-2]
a new type of refinement, and what impact might that have on things like function calls?|
is valid for word use today.>> f: [1 2 3 4] >> f/0 [] >> f/0/-1 4 >> f/0/-2 3
0
meaning tail
makes it a magic number. More than that, it doesn't solve the issue today, but in iterating over indexes, suddenly 0
becomes quite dangerous if you cross that boundary. It also dramatically changes path evaluation, which we want to be consistent. >> f: [1 2 3 4] >> g: tail f >> f/1: "a" >> head g ["a" 2 3 4] >> g/-1: "d" >> head f ["a" 2 3 "d"]
first
function, but not a rest
function.rest: func [s [series!]][next s]
take s 1
do the same thing, except also removing the first member? > (define f (list 1 2 3 4)) > (define g (rest f)) > g '(2 3 4) > (first g) 2
next s
doesn't just return the valuestake
it is, thenrest: func [s [series!]][copy next s]
rest
in the middle of thinking about traversing and indexesg
no longer points to the tail.>> f: [1 2 3 4] == [1 2 3 4] >> g: tail f == [] >> append f "x" == [1 2 3 4 "x"] >> g/-1 == 4 >> g/-1: "d" == "d" >> f == [1 2 3 "d" "x"]
L[i+:j]
which is equal to L[i:i+j]
customer
we goint to lot
, but how to understand that we already not in customer
level?data-pointer: [ lots: [ bar: none baz: none customers: [ customer: [ name: none ] ] lot: [ name: none objs:[ obj: [ price: none ] ] ] ] ] elements-before: function [] [ level: 0 walk: function[data-pointer /extern level] [ foreach [data-name data-value] data-pointer [ if block? data-value [ print data-name walk data-value ] ] ] walk data-pointer ] elements-before
walk
start, remove it after leaving it[data-pointer lots customers customer] [data-pointer lots customers] [data-pointer lots] [data-pointer lots lot] ...
> [data-pointer lots customers customer] > [data-pointer lots customers] > [data-pointer lots] > [data-pointer lots lot] > ... >
data-pointer: [ lots: [ bar: none baz: none customers: [ customer: [ name: none ] ] lot: [ name: none objs:[ obj: [ price: none ] ] ] ] ] remove-last: function [blk] [ head clear back tail copy blk ] elements-before: function [] [ print "elements-before" level: 0 stack: [] walk: function[data-pointer /extern level] [ foreach [data-name data-value] data-pointer [ if block? data-value [ print [data-name " > " stack] append stack to-word data-name walk data-value remove-last stack ] ] ] walk data-pointer ] elements-before
lots > customers > lots customer > lots customers lot > lots customers customer ; ! Error! lot parent is lots but not: lots customers customer objs > lots customers customer lot obj > lots customers customer lot objs == [lots customers customer lot objs]
name-find 10 1 1 1 1 1 1 1 2 1 1 1 2 2 1 1 1 3 3 2 1 1 1 3 4 3 2 1 1 1 4 5 5 3 2 1 1 1 4 7 6 5 3 2 1 1 1 5 8 9 7 5 3 2 1 1
'[1 2 3 4]
is neither a valid word nor series. I'm assuming though Red is committed to having only one kind of series rather different types; ex python has arrays, lists, tuples and dictionaries. ? series!
, and also ? typeset!
>> f: make reactor! [s: [1 2 3 4]] == make object! [ s: [1 2 3 4] ] >> t: is [tail f/s] >> append f/s 5 == [1 2 3 4 5] >> t == [5]
t: is [f/s/((length? f/s) + 1)]
doesn't return an error, but it returns none, the value of tail.t: is [find f/s/((length? f/s) + 1)]
doesn't work because find can't use none as an input.t: is [f/s/(length? f/s)]
t: is [f/s/(length? f/s) + 1]
if mem/1 > rem [break]
speeds things up more, but 123 is still undoable Red 0.6.4 for Windows built 22-Dec-2021/17:36:36+03:00 commit #328c904
[ data-name copy/deep m ]
context [ sum-part: function [nums [block!] count [integer!]][ out: 0.0 loop count [ out: out + nums/1 if empty? nums: next nums [break] ] out ] nums: make map! [1 [1] 2 [1 1]] sums: make map! [1 1 2 2] set 'names function [row][ if row < 1 [cause-error 'user 'message "Argument needs to be >= 1"] either sums/:row [sums/:row][ out: clear [] half: to integer! row / 2 repeat col row - 1 [ unless nums/:col [names col] unless nums/(row - 1) [names row - 1] either col = (half + 1) [ append out at nums/(row - 1) half break ][ append out sum-part nums/(row - col) col ] ] sums/:row: sum nums/:row: copy out clear out sums/:row ;probe reduce [row nums/:row sums/:row] ] ] ]
>> names 23 == 1255.0 >> names 123 == 2552338241.0 >> names 1234 == 1.569787972237331e35
names 1234
, but it takes sooome time to reach the answer. You can now see each row with e.g. names/show 23
or names/show/all 23
. Latter prints row numbers and sums too.context [ sum-part: function [nums [block!] count [integer!]][ out: 0.0 loop count [ out: out + nums/1 if empty? nums: next nums [break] ] out ] nums: make map! [1 [1] 2 [1 1]] sums: make map! [1 1 2 2] set 'names function [row /show /all][ if row < 1 [cause-error 'user 'message "Argument needs to be >= 1"] if show [ unless nums/:row [names row] repeat i row [either all [probe reduce [i nums/:i sums/:i]][print nums/:i]] ] either sums/:row [sums/:row][ out: clear [] half: to integer! row / 2 if row - 1 > last: length? nums [ repeat i row - last - 1 [names last + i] ] repeat col row - 1 [ either col = (half + 1) [ append out at nums/(row - 1) half break ][ append out sum-part nums/(row - col) col ] ] also sums/:row: sum nums/:row: copy out clear out ] ] ]
>> save %latest-red read https://static.red-lang.org/dl/auto/linux/red-latest *** Access Error: invalid UTF-8 encoding: #{9F040834} *** Where: read *** Stack: save
print "choose rock: r, paper: p, or scissors: s" pchoice: ask ""
ask ""
is just input
, and print "xxx" ask ""
is just ask "xxx"
. So the same code can be written as (note newline as in your design):pchoice: ask "choose rock: r, paper: p, or scissors: s^/"
forever [ print "choose rock: r, paper: p, or scissors: s" pchoice: ask "" unless any [pchoice = "r" pchoice = "p" pchoice = "s"] [break]
forever
are also a last resort and should be used sparingly. Since you got break
there, your loop is actually conditional. So this can be just while
:while [find choices pchoice: ask "choose rock: r, paper: p, or scissors: s^/"]
case
:case [ pchoice = cchoice [print "tie"] pindex = cindex [print "you lose"] true [print "you win"] ]
print
out:print case [ pchoice = cchoice ["tie"] pindex = cindex ["you lose"] true ["you win"] ]
'else [..]
instead of true [..]
for more readability. Though it's a matter of taste of course.lx: none unless (find prior lose/:pindex) = none [lx: (index? find prior lose/:pindex) - 1] unless lx = none [remove skip prior lx] ;removes what would have lost to player
remove find prior lose/:pindex ;removes what would have lost to player
Red [Purpose: "Implement a rock-paper-scissors game with weighted probability"] prior: rejoin choices: ["r" "p" "s"] while [ find choices player-move: ask "choose (r)ock, (p)aper, or (s)cissors: " ][ print ["AI draws:" ai-move: random/only prior] ai-win: select "rpsr" player-move ai-loss: select "rspr" player-move print case [ ai-move = player-move/1 ["tie"] ai-move = ai-win ["you lose"] 'else ["you win"] ] append prior ai-win ;-- adds what would have beaten player remove find prior ai-loss ;-- removes what would have lost to player ]
Red [ Purpose: "Implement a rock-paper-scissors game with weighted probability" Needs: View ] prior: "RPS" names: [#"R" "Rock" #"P" "Paper" #"S" "Scissors"] ai-move: function [player-move] [ ai/text: select names ai-move: random/only prior append prior ai-win: select "RPSR" player-move ;-- adds what would have beaten player remove find prior ai-loss: select "RSPR" player-move ;-- removes what would have lost to player round/text: case [ ai-move = player-move ["tie"] ai-move = ai-win ["you lose"] 'else ["you win"] ] ] view [ text "Your move:" player: text "" react later [ai-move face/text/1] return text "AI move:" ai: text "" return text "Result:" round: text "" return button [player/text: face/text] "Rock" button [player/text: face/text] "Paper" button [player/text: face/text] "Scissors" ]
deep/copy
map?m: copy/deep #(nodes: copy/deep #() )
m: copy/deep make map! reduce [nodes: make map! copy/deep [] ]
reduce
is doing and you're goodnodes
is some setted word above reduce [nodes: make map! copy/deep [] ]
?word: value
is a single expression yielding single resultm: copy/deep make map! [ nodes: reduce [make map! copy/deep [] ] ]
>> m: copy/deep make map! [nodes: [make map! copy/deep [] ] ] == #( nodes: [make map! copy/deep []] )
reduce
in console, giving it random input until you figure out how to get 2 results returned?m: copy/deep make map! reduce [to-set-word 'nodes make map! copy/deep [] ]
[]
with copy/deep
because it's empty, it has nothing "deep" in it to be copiedcopy/deep
the map you've just created either, because what you have created is the only existing copy so far and since there is no other reference to it, that original copy will be simply lostask
with newlines misbehaving in --cli
modechoose rock: r, paper: p, or scissors: s r AI Draws: s you win choose rock: r, paper: p, or scissors: s r AI Draws: p you lose choose rock: r, paper: p, or scissors: s s AI Draws: p you win choose rock: r, paper: p, or scissors: s s
loop 3 [ask "hi^/"]
then press up in the input line a few times.cpu-move: select weapons random/only append weapons player-move
change
?encrypt: func [txt [string!] key [integer!] /local temp][ temp: copy "" forall txt [append temp to-char add first txt key] ] decrypt: func spec-of :encrypt copy replace/deep body-of :encrypt 'add 'subtract
copy/deep
ask
to create your own version that doesn't return a value (use unset!
).ask2: func [s][print s input]
reply: func [n msg][wait n print msg]
prin reply 3 "...Hello?"
wait
pausesask-wait: func [ "Prompt the user for input" duration [number! time! block! none!] question [string!] /hide return: [string!] /local buffer ][ buffer: make string! 1 _set-buffer-history buffer head system/console/history _read-input question hide wait duration buffer ]
function [arg1 arg2 [integer!]]
isn't a thing?[arg1 [default!] arg2 [integer!]]
instead?function [arg1 arg2 [integer!]]
isn't a thing?arg1 arg2 [integer!]
expanding to arg1 [integer!] arg2 [integer!]
breaks code. It would have to expand to arg1 [default!] arg2 [integer!]
, which maintains the current behavior, but that's not what you want. So it could *only* work for code that expects that pattern. Which makes it incompatible with Red code in general.function [ "some description" x y z [integer!] ]
function [ "some description" [x y z][integer!] ]
function [ "description" x [integer!] "description" y [integer!] "description" z [integer!] ]
>> fn: func [integer! [string!]][print integer!] == func [integer! [string!]][print integer!] >> fn "x" x
function [ "some description" x y z [integer!] ]
function [ "some description" [x y z][integer!] ]