Processing block parameter with word types in red / rebol - rebol

When calling:
f [(h test) (h test2)]
I want to get:
"<p><h1>test</h1><h1>test2</h1></p>"
Instead I get:
"<h1>test2</h1></p>"
I can't see why my code below doesn't work. Note that I want to use g function below because I have several h like functions, g is called by each of them to factorize them. So don't get rid off g, it's on purpose.
html: copy ""
emit: func [code] [repend html code]
f: func [param [block!]] [
html: copy ""
emit: func [code] [repend html code]
emit <p>
foreach p param [
emit p
]
emit </p>
return html
]
g: func ['arg [string! word!] /local html] [
return h :arg
]
h: func ['arg [string! word!]] [
either word? arg [
text: to-string arg
][
text: arg
]
html: copy ""
emit: func [code] [repend html code]
print text
emit <h1>
emit text
emit </h1>
return html
]
f [(h test) (h test2)]
Update:
Now I get error in red:
Script Error: html is not in the specified context
f: func[param [block!] /local html][
html: copy ""
emit: func [code] [repend html code]
emit <p>
foreach p param [
emit p
]
emit </p>
return html
]
g: func['arg [string! word!] /local html][
return h :arg
]
h: func['arg [string! word!] /local html][
either word? arg [text: to-string arg][
text: arg
]
html: copy ""
emit: func [code] [repend html code]
print text
emit <h1>
emit text
emit </h1>
return html
]
f [(h test) (h test2)]

Your problem is the usage of a global html: copy "" everywhere and new initailzing the already emitted html. If you make it local with /local html in the spec blocks either manually or by replacing func with funct in Rebol2 or function in Red, it should work
>>f [ [h test] [h test2]]
test
test2
== "<p><h1>test</h1><h1>test2</h1></p>"
>>

Ok, here a slightly optimized version for Red and Rebol without funct or function
emit: func [code html] [repend html code]
f: func[param [block!] /local html][
html: copy ""
emit <p> html
foreach p param [
emit p html
]
emit </p> html
return html
]
g: func['arg [string! word!] l][
return h :arg
]
h: func['arg [string! word!] /local html text][
either word? arg [text: to-string arg][
text: arg
]
html: copy ""
print text
emit <h1> html
emit text html
emit </h1> html
return html
]
>>f [ [h test] [h test2]]
test
test2
== "<p><h1>test</h1><h1>test2</h1></p>"

Related

Tracer function written in Rebol

It is possible in Rebol (Red, R3 Ren-c) to write a function similar to TRACE that produces the following result:
foo: func [val1 val2 /local temp] [
temp: val1 + 5
val2 + temp
]
bar: func [x /ris 'var "blablalba"][
if ris [set var "fatto"]
(foo x 2) + 8
]
trace [foo bar]
bar/ris 7 yyy
Enter BAR
x = 7
var = yyy
Enter FOO
val1 = 7
val2 = 2
FOO returned 14
BAR returned 22
At the user-level, the most straightforward approach is to write a closure-like wrapper that would call tracing hooks you provide before and after calling the main code, and which then would return the result of evaluation.
A rough sketch of that idea in Red is as follows:
frame-of: function [
func [function!]
/local
match
][
parse spec-of :func [
collect any [
set match [not quote return: all-word!] keep (to word! match)
| skip
]
]
]
report: function [frame [block!]][
environment: construct collect [forall frame [keep to set-word! frame/1]]
also environment set environment reduce frame
]
trace: function [
'target [word!]
enter [block!]
leave [block!]
][
chain: reduce [
'do enter
'set/any quote 'result 'do body-of get target
'do leave
quote :result
]
new: func spec-of get target chain
info: context [
frame: bind frame-of get target :new
name: target
result: none
]
bind body-of :new info
set target :new
exit
]
With that in place, you can then:
enter: [print ['entering name 'with mold/flat body-of report frame]]
leave: [print [name 'returned result]]
trace foo enter leave
trace bar enter leave
Which, for your example, gives:
>> bar/ris 7 yyy
entering bar with [x: 7 ris: true var: 'yyy]
entering foo with [val1: 7 val2: 2 local: false temp: none]
foo returned 14
bar returned 22
== 22
Mind that this is just a PoC. The basic idea is that your original function gets replaced by an instrumented version, created via a closure over some internal namespace with debugging info. You can also throw some Red/System into the mix to gain fine-grained access to runtime information, like e.g. evaluation stack.
I am leaving pretty-printing with indentation and disabling of tracing as an exercise for the reader ;)
This solution, not very elegant, works on both Red and Rebol and should meet the demand requirements (I hope I have considered all cases):
extract-args: func [args-block /local emit result rules w ref] [
result: copy []
emit: func [x] [append result x]
rules: [
any [
/local some [word!]
| set w [word! | get-word!] (emit w)
| set w lit-word! (emit to-get-word w)
| [string! | block!]
| set ref refinement! set w [word! | lit-word! | get-word!]
(if ref [emit w])
| refinement!
]
]
parse args-block rules
result
]
pretty-print-args: func [spc /wrd] [
foreach wrd extract-args spc [
print [**indentation** " " to-string wrd " = " get wrd]
]
]
insert-**result**: func [spc] [
either find spc quote /local
[append spc [**result**]]
[append spc [/local **result**]]
]
**indentation**: copy ""
add-1-ind: func [][append **indentation** copy " "]
remove-1-ind: func [] [remove/part skip tail **indentation** -3 3]
my-trace: func [wrds /local w spc bdy bdy' uw] [
foreach w wrds [
uw: uppercase to-string w
spc: copy spec-of get w
insert-**result** spc
bdy: body-of get w
bdy': compose/deep copy [
add-1-ind
print [**indentation** "Enter" (uw)]
pretty-print-args [(spc)]
set/any '**result** do [(bdy)]
print [**indentation** (uw) "returned" mold :**result**]
remove-1-ind
:**result**
]
set w func spc bdy'
]
]
Then:
>> my-trace [foo bar]
== func [x /ris 'var "blablalba" /local **result**][
add-1-ind
...
>> bar/ris 7 yyy
Enter BAR
x = 7
var = yyy
Enter FOO
val1 = 7
val2 = 2
FOO returned 14
BAR returned 22
== 22
>> source bar
bar: func [x /ris 'var "blablalba" /local **result**][
add-1-ind
print [**indentation** "Enter" "BAR"]
pretty-print-args [x /ris 'var "blablalba" /local **result**]
set/any '**result** do [
if ris [set var "fatto"]
(foo x 2) + 8
]
print [**indentation** "BAR" "returned" mold :**result**]
remove-1-ind
:**result**
]

Elm View Function Returns a Function Instead of the Value of it

The Elm Compiler gives me this error in my view function ...
TYPE MISMATCH - Something is off with the 2nd branch of this case expression:
div [] [
div [] [text (String.fromInt value)],
div [] [button [ onClick identity ] [ text "Enter number" ]]]
This div call produces:
Html #(a -> a)#
But the type annotation on view says it should be:
Html #Msg#Elm
Does anyone know how I can fix this issue?
Thank you!
module Main exposing (..)
import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)
-- MAIN
main =
Browser.sandbox { init = init, update = update, view = view }
-- MODEL
type alias Model =
Result String Int
init : Model
init =
Result.Ok 0
-- UPDATE
type alias Msg = Int
update : Msg -> Model -> Model
update msg model =
collatz msg
collatz : Int -> Result String Int
collatz start =
if start <= 0 then
Result.Err "Only positive numbers are allowed"
else
Result.Ok (collatzHelper start 0)
collatzHelper : Int -> Int -> Int
collatzHelper start counter =
if start == 1 then
counter
else if modBy 2 start == 0 then
collatzHelper (start // 2) (counter + 1)
else
collatzHelper (3 * start + 1) (counter + 1)
-- VIEW
view : Model -> Html Msg
view model =
case model of
Err err ->
div [] [text err]
Ok value ->
div [] [
div [] [text (String.fromInt value)],
div [] [button [ onClick identity ] [ text "Enter number" ]]]
The compiler error message, as always with Elm, is fairly straightforward to understand. The problem is the onClick attribute in this line:
div [] [button [ onClick identity ] [ text "Enter number" ]]
As the compiler says, this has type a -> a, when it's expected to have type Msg, which in your case is the same as Int. That is, you've passed a function and it should be an integer.
Since value here is indeed an Int, that seems the natural choice to use here:
div [] [button [ onClick value ] [ text "Enter number" ]]
and this does indeed compile. However, this app doesn't seem particularly useful, because the user has no way to change the value displayed. You will need to include some sort of numeric input in your app to allow that - and then you will need a new alternative in your Msg type to handle the change of value.
Judging by this and your previous question (which is where I assume you got the idea of using identity as an onClick value - unfortunately that doesn't work in general), you seem to be struggling a bit with how the Elm Architecture works, so if you haven't already I would strongly recommend going through the tutorial.

How I can pass to a function the union type without including the tag

Playing with the Elm checkboxes example. I am trying to move the following repetative code in view
, label []
[ br [] []
, input [ type' "checkbox", checked model.underline, onCheck Underline ] []
, text "underline"
]
into a separate function and use it three times. So far I have ...
makeLabel : String -> Bool -> Msg -> Html Msg
makeLabel caption bool msg =
label []
[ br [] []
, input [ type' "checkbox", checked bool, onCheck msg ] []
, text caption
]
and I would use it like
makeLabel "underline" model.underline Underline
but then I receive the following error
Function `makeLabel` is expecting the 3rd argument to be:
Msg
But it is:
Bool -> Msg
How do I pass my makeLabel function the correct action to take when a user changes the checkbox?
type Msg
= Red Bool
| Underline Bool
| Bold Bool
I don't understand how I can pass to a function the union type (Underline) without including the tag (Underline Bool)
The problem is in your type signature, rather than the code. Try this:
makeLabel : String -> Bool -> (Bool -> Msg) -> Html Msg

is there an object constructor in rebol

I usually program by functions in an "instinctive" manner, but my current problem can be easily solved by objects, so I go ahead with this method.
Doing so, I am trying to find a way to give an object a constructor method, the equivalent of init() in python, for example.
I looked in the http://www.rebol.com/docs/core-fr/fr-index.html documentation, but I couldn't find anything relevant.
There is no special constructor function in Rebol, but there is a possibility to write ad hoc init code if you need it on object's creation in the spec block. For example:
a: context [x: 123]
b: make a [
y: x + 1
x: 0
]
So, if you define your own "constructor" function by convention in the base object, you can call it the spec block on creation. If you want to make it automatic, you can wrap that in a function, like this:
a: context [
x: 123
init: func [n [integer!]][x: n]
]
new-a: func [n [integer!]][make a [init n]]
b: new-a 456
A more robust (but bit longer) version of new-a that would avoid the possible collision of passed arguments to init with object's own words would be:
new-a: func [n [integer!] /local obj][
also
obj: make a []
obj/init n
]
You could also write a more generic new function that would take a base object as first argument and automatically invoke a constructor-by-convention function after cloning the object, but supporting optional constructor arguments in a generic way is then more tricky.
Remember that the object model of Rebol is prototype-based (vs class-based in Python and most other OOP languages), so the "constructor" function gets duplicated for each new object created. You might want to avoid such cost if you are creating a huge number of objects.
To my knowledge, there is no formal method/convention for using object constructors such as init(). There is of course the built-in method of constructing derivative objects:
make prototype [name: "Foo" description: "Bar"]
; where type? prototype = object!
My best suggestion would be to define a function that inspects an object for a constructor method, then applies that method, here's one such function that I've proposed previously:
new: func [prototype [object!] args [block! none!]][
prototype: make prototype [
if in self 'new [
case [
function? :new [apply :new args]
block? :new [apply func [args] :new [args]]
]
]
]
]
The usage is quite straightforward: if a prototype object has a new value, then it will be applied in the construction of the derivative object:
thing: context [
name: description: none
new: [name: args/1 description: args/2]
]
derivative: new thing ["Foo" "Bar"]
note that this approach works in both Rebol 2 and 3.
Actually, by reading again the Rebol Core documentation (I just followed the good old advice: "Read The French Manual"), there is another way to implement a constructor, quite simple:
http://www.rebol.com/docs/core-fr/fr-rebolcore-10.html#section-8
Of course it is also in The English Manual:
http://www.rebol.com/docs/core23/rebolcore-10.html#section-7
=>
Another example of using the self variable is a function that clones
itself:
person: make object! [
name: days-old: none
new: func [name' birthday] [
make self [
name: name'
days-old: now/date - birthday
]
]
]
lulu: person/new "Lulu Ulu" 17-May-1980
print lulu/days-old
7366
I find this quite convenient, and this way, the constructor lies within the object. This fact makes the object more self-sufficient.
I just implemented that successfully for some geological stuff, and it works well:
>> source orientation
orientation: make object! [
matrix: []
north_reference: "Nm"
plane_quadrant_dip: ""
new: func [{Constructor, builds an orientation object! based on a measurement, as given by GeolPDA device, a rotation matrix represented by a suite of 9 values} m][
make self [
foreach [a b c] m [append/only matrix to-block reduce [a b c]]
a: self/matrix/1/1
b: self/matrix/1/2
c: self/matrix/1/3
d: self/matrix/2/1
e: self/matrix/2/2
f: self/matrix/2/3
g: self/matrix/3/1
h: self/matrix/3/2
i: self/matrix/3/3
plane_normal_vector: reduce [matrix/1/3
matrix/2/3
matrix/3/3
]
axis_vector: reduce [self/matrix/1/2
self/matrix/2/2
self/matrix/3/2
]
plane_downdip_azimuth: azimuth_vector plane_normal_vector
plane_direction: plane_downdip_azimuth - 90
if (plane_direction < 0) [plane_direction: plane_direction - 180]
plane_dip: arccosine (plane_normal_vector/3)
case [
((plane_downdip_azimuth > 315) or (plane_downdip_azimuth <= 45)) [plane_quadrant_dip: "N"]
((plane_downdip_azimuth > 45) and (plane_downdip_azimuth <= 135)) [plane_quadrant_dip: "E"]
((plane_downdip_azimuth > 135) and (plane_downdip_azimuth <= 225)) [plane_quadrant_dip: "S"]
((plane_downdip_azimuth > 225) and (plane_downdip_azimuth <= 315)) [plane_quadrant_dip: "W"]
]
line_azimuth: azimuth_vector axis_vector
line_plunge: 90 - (arccosine (axis_vector/3))
]
]
repr: func [][
print rejoin ["Matrix: " tab self/matrix
newline
"Plane: " tab
north_reference to-string to-integer self/plane_direction "/" to-string to-integer self/plane_dip "/" self/plane_quadrant_dip
newline
"Line: " tab
rejoin [north_reference to-string to-integer self/line_azimuth "/" to-string to-integer self/line_plunge]
]
]
trace_te: func [diagram [object!]][
len_queue_t: 0.3
tmp: reduce [
plane_normal_vector/1 / (square-root (((plane_normal_vector/1 ** 2) + (plane_normal_vector/2 ** 2))))
plane_normal_vector/2 / (square-root (((plane_normal_vector/1 ** 2) + (plane_normal_vector/2 ** 2))))
]
O: [0 0]
A: reduce [- tmp/2
tmp/1
]
B: reduce [tmp/2 0 - tmp/1]
C: reduce [tmp/1 * len_queue_t
tmp/2 * len_queue_t
]
L: reduce [- axis_vector/1 0 - axis_vector/2]
append diagram/plot [pen black]
diagram/trace_line A B
diagram/trace_line O C
diagram/trace_line O L
]
]
>> o: orientation/new [0.375471 -0.866153 -0.32985 0.669867 0.499563 -0.549286 0.640547 -0.0147148 0.767778]
>> o/repr
Matrix: 0.375471 -0.866153 -0.32985 0.669867 0.499563 -0.549286 0.640547 -0.0147148 0.767778
Plane: Nm120/39/S
Line: Nm299/0
Another advantage of this way is that variables defined by the "new" method directly belongs to the object "instance" (I ran into some trouble, with the other methods, having to mention self/ sometimes, having to initialize variables or not).
I'm trying to find out how OO works in REBOL. Prototypical indeed. Yesterday I came across this page, which inspired me to the classical OO model below, without duplication of functions:
;---- Generic function for class or instance method invocation ----;
invoke: func [
obj [object!]
fun [word!]
args [block!]
][
fun: bind fun obj/.class
;---- Class method names start with a dot and instance method names don't:
unless "." = first to-string fun [args: join args obj]
apply get fun args
]
;---- A class definition ----;
THIS-CLASS: context [
.class: self ; the class refers to itself
;---- Class method: create new instance ----;
.new: func [x' [integer!] /local obj] [
obj: context [x: x' .class: none] ; this is the object definition
obj/.class: self/.class ; the object will refer to the class
; it belongs to
return obj
]
;---- An instance method (last argument must be the instance itself) ----;
add: func [y obj] [
return obj/x + y
]
]
Then you can do this:
;---- First instance, created from its class ----;
this-object: THIS-CLASS/.new 1
print invoke this-object 'add [2]
;---- Second instance, created from from a prototype ----;
that-object: this-object/.class/.new 2
print invoke that-object 'add [4]
;---- Third instance, created from from a prototype in another way ----;
yonder-object: invoke that-object '.new [3]
print invoke yonder-object 'add [6]
;---- Fourth instance, created from from a prototype in a silly way ----;
silly-object: yonder-object/.class/.class/.class/.class/.new 4
print silly-object/.class/add 8 silly-object
print this-object/.class/add 8 silly-object
print THIS-CLASS/add 8 silly-object
(It works in REBOL 2, and prints 3, 6, 9, 12, 12, 12 successively.) Hardly any overhead. Probably it won't be difficult to find a dozen of other solutions. Exactly that is the real problem: there are too many ways to do it. (Maybe we'd better use LoyalScript.)

Shared function in Rebol (implementation inheritance)

Someone said you can have (implementation inheritance) with Rebol using get. So I tried:
shape: context [
x: 0
y: 0
draw: func['object][
probe get object
]
]
circle: make shape [
radius: 10
draw: get in shape 'draw
]
rectangle: make shape [
draw: get in shape 'draw
]
I want to pass the object by reference not by value so I pass only the name using 'Object. But then I have to call it like this
circle/draw 'circle
which is rather lame as I need to repeat the name circle twice while in usual inheritance there is the this keyword which avoid this kind of unatural syntax. Is there a more elegant way ?
Thanks.
There is a self word. At the risk of creating a false sense of certainty about that, I'll give you an example that presumably does what you want:
shape: make object! [
x: 0
y: 0
draw: func [object [object!]] [
probe object
]
]
circle: make shape [
radius: 10
draw: func [] [
shape/draw self
]
]
rectangle: make shape [
draw: func [] [
shape/draw self
]
]
Here we've made functions that take zero arguments by calling the base class function with the appropriate "self"
Beware: like other words, it gets bound...and the binding sticks. This can get tricky once you start working with abstractions...
selfWordAlias: func [] [
return 'self
]
triangle: make shape [
draw: func [] [
shape/draw get selfWordAlias
]
]
Calling triangle/draw will probably surprise you. You're in the object method and selfWordAlias returns the word "self". But the notion of self was captured and bound at the time the selfWordAlias was defined, which was in the global system context. So that's what you get back.
There are tools for dealing with this, but make sure you've got a firm grip on Scoping in Rebol !
I would have thought that using Rebol's prototypical inheritance is all that you need. It is simpler and more elegant:
shape: make object!
x: 0
y: 0
draw: func [] [probe self]
]
circle: make shape [
radius: 10
]
triangle: make shape []
Which give the following results:
>> shape/draw
make object! [
x: 0
y: 0
draw: func [][probe self]
]
>> circle/draw
make object! [
x: 0
y: 0
draw: func [][probe self]
radius: 10
]
>> triangle/draw
make object! [
x: 0
y: 0
draw: func [][probe self]
]
I use this method when I want to use same function (not the copies of function) for all my objects.
Point the function whenever you create an object, even if you copy another object.
>> f: does [print "hello"]
>> o: context [a: 1 b: :f]
>> o/b
hello
>> p: context [a: 2 b: :f]
>> p/b
hello
>> same? get in o 'b get in p 'b
== true ;they are exactly the same function
>> append last second :f " world!" ;change the function
== "hello world!"
>> o/b
hello world!
>> p/b
hello world!
Ofcourse you should take care about the binding issues. Hope this will help.