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 FIRSTm: 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-pidtext 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 skeys: #(
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 skeys: #(
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 sform 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
dos. 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-gifmy-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 codeRed [ 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 codewin: layout codered
>> 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 viewwin: 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 winforeach-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 codetext: ["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 coderepeat 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 nonefunction 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?thrown? 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-countview [ 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/fontssystem/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.0129937to 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 wintail 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/deepcopy/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: replacerule 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 resmap-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 resuppercase/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 resappend 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 resappend 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 -2form 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
== falsemy-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 objsave 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 andand goes first. He looks and sees ["yes"] and says, "I can't have a block as my first argument"trueop! 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 printhelp 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 :)sourceSource 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 global1b 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!]
== truemold/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"]
truefind/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.blahset load a/1 a/2to 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-specwhich 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 printcode: [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? alength? 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 resultreduced:>> p: to path! reduce ['data o/name] == data/foo >> p == data/foo >> get p == [bar: "hello"]
reduced:> >> 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-42d9d6a76to-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-templatesto-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:
thousandsproblem: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 'redbinunset! 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 bkeep 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.cvsdrawersand
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 wordnone 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
enhex0%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 expermentnone)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-jsonstr: {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 (:does 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/alldump-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
== 22foreach 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/fa: 2
b: case [
a == 1 [ "1" ]
[]
]
probe b ;= nonecase [] 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?1457976860save 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/windowf 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/windowbin: 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 ai: 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 worksbreak 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-ofcommand, 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]winwordcall {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 rulematches 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"]
== falsebitset! 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-cfginput.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 reducebehave 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-floatone 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-ofbody-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: zbody-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 listforeach 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, uNumPy'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).matrixin @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 / totalRed [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 noneclear 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-errora: 1 comment { b: 2 } c: 3system/lexer/pre-load though if this feature is so tempting.composeview 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
==> 6Red/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?funcsli 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...
parseforeach 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 sizecall/output {du -b 1.png | cut -f -1} data: ""
print size/shellcall/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.txta: "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. explodeexplode: 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.extractsource extractexplode 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 doing 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/deflateRed 0.6.4 for Windows built 2-Sep-2021/15:40:47+03:00 commit #579b9d3Red 0.6.4 for Linux built 11-May-2021/6:20:25+03:00 commit #81d0416actor 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.actors 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 doescontext 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.loading 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.fielddeneme: ask ">>"
parse deneme [
"sh" change c: ["a" b: ["o" | "oq"]] (rejoin ["â" c/b])
]
print denemechange's logicdeneme: ask ">>"
parse deneme [
"sh" change *"a" ["o" | "oq"] "2" *"â"
]
print denemered >> 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 versionscloseclose but don't remember the resulting design decision.to-image ?? drawlay: 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 #{
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFlink: 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:changemuch 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 noneprint data/lots/fooprint 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/n1callto Curl might be used?move/part (at data/lots 3) data 2 datadata 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/caseif, either, all/any, but not for caseif, all/any but not for either/casedata: [
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 6unset! 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-stringview [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/tailRed [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/:inumbs/(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 listskip 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 data2data1: 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 ireference 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 blktake/lastprint 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/optionsh: load/header system/options/script probe h/Red/Title #include %prime.red probe h/Red/Title
system/words/deletein 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: 225include: 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-beforewalk 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-beforelots > 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: saveprint "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
sloop 3 [ask "hi^/"] then press up in the input line a few times.cpu-move: select weapons random/only append weapons player-movechange?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 'subtractcopy/deepask 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!]
]