World: r3wp
[I'm new] Ask any question, and a helpful person will try to answer.
older newer | first last |
BrianH 29-Apr-2009 [1909] | Object types are reference types too, but you usually need to do other tricks instead of COPY with them. |
mhinson 29-Apr-2009 [1910] | Many thanks for taking an interest in my newbie fumblings. |
Sunanda 30-Apr-2009 [1911x2] | We were all newbies once! And we all are again every time we start learning something new. I just remembered another puzzle/challenge I presented to the Mailing list, and got back a rich range of replies. This one is purely parse (including my first attempt), so trying it out, and then looking at others' code can help understand parse. As with the other two, it is based on a real-world need, rather than being a textboox exercise. (You experience the results of all three puzzles whenever you browse wwwREBOL.org). Good luck with this one too! http://www.rebol.org/ml-display-thread.r?m=rmlGPGQ |
And, just in case you had any more spare time in the next month, another one that really surprised me as being amenable to a parse solution: http://www.rebol.org/ml-display-thread.r?m=rmlJNFC | |
mhinson 30-Apr-2009 [1913] | Hi, thanks for the extra puzzles. I have managed to write a version that works now, but I am frustrated because I cant understand how to keep variables local & pass them to my function & return the changed values back... In previous programming experience I seem to remeber that the function header listed the variable names & types used localy, then the function was called with the variables of the right type in the right order.. I cant remeber how results were returned in that context. I have been reading here http://www.rebol.com/docs/core23/rebolcore-9.html#section-3.5 but every way I try seems to stop the code working as expected. raw-data: [1 2 3 10 11 99 101 2000 2001 2002 2003 2004] sequence-break: func [][ either (count > 1) [ append result to-pair rejoin [store "x" count] count: 1 reduce [count result] ][ append result store reduce result ] ] compress: func [raw-data][ count: 1 store: reduce raw-data/1 result: copy [] repeat i ((length? raw-data) - 1) [either ((raw-data/(i) + 1) = (raw-data/(i + 1))) [ count: count + 1 ][ sequence-break count result store store: reduce raw-data/(i + 1) ] ] sequence-break count result store reduce result ] print compress raw-data |
Maxim 30-Apr-2009 [1914x4] | here is how to declare a local word using func my-func: func [arg1 /local my-lcl][ print arg1 print my-lcl ] my-lcl: "NOT" my-func "YEP" == arg1 none |
there are three other function! type building functions: DOES HAS FUNCTION look them up in the online rebol dictionary: http://www.rebol.com/docs/dictionary.html you can also get help directly in the rebol console: >> help does USAGE: DOES body DESCRIPTION: A shortcut to define a function that has no arguments or locals. DOES is a function value. ARGUMENTS: body -- The body block of the function (Type: block) (SPECIAL ATTRIBUTES) catch | |
you can also see its source, when its mezzanine code (standard rebol function written in rebol itself) >> source does does: func [ {A shortcut to define a function that has no arguments or locals.} [catch] body [block!] "The body block of the function" ][ throw-on-error [make function! [] body] ] | |
HTH ! | |
mhinson 30-Apr-2009 [1918] | Great, this will help a lot, thanks. I am beginning to realise that just because I have found a way to create a function (e.g. func) that dosn't mean I have found ALL the ways to make a function. This seems to be a common theme in REBOL & has caught me out before. This is my interpretation of what you have said & what I have read, however it does not work so I am obviously misunderstanding the method. ;; I am expecting this to reverse the arguements by passing them to a second function, while keeping all the function variables local & just passing back the result. func1: func [/local arg1 arg2][ temp: arg1 arg1: arg2 arg2: arg1 reduce [arg1 arg2] ] funcA: func [/local argA argB][ func1 argA argB reduce [argA argB] ] probe funcA 2 3 >> probe funcA 2 3 [none none] == 3 >> |
Izkata 30-Apr-2009 [1919] | As written, neither funcA nor func1 take any arguments - the variables listed are after the "/local" key that turns them into local variables initialized to none |
Maxim 30-Apr-2009 [1920] | the ==3 printed is because >> probe funcA 2 3 doesn't grab any argument, so it evaluates funcA, evaluates 2, evaluates 3 and the console prints the last evaluation, so the would be 3. |
mhinson 30-Apr-2009 [1921] | wow! so do I need to pass them my globals & copy them in the function? I expected that copy to be implicit.... I better look at DOES HAS & FUNCTION before I waste anymore of everyones time. sorry. |
Izkata 30-Apr-2009 [1922x2] | So, func1: func [arg1 arg2 /local temp][ temp: arg1 arg1: arg2 arg2: temp ;I think this was a mis-type in you original, if you wanted to swap reduce [arg1 arg2] ] |
an easier way would be: func1: func [arg1 arg2][ reduce [arg2 arg1] ] | |
mhinson 30-Apr-2009 [1924] | I am not after efficency, just trying to understand local & global vairable passing. so reading the above I would expect this clumsy thing to work .. but it dosn't func1: func [arg3 arg4 /local arg1 arg2 temp][ arg1: arg3 arg2: arg4 temp: arg1 arg1: arg2 arg2: temp arg3: arg1 arg4: arg2 reduce [arg3 arg4] ] funcA: func [argZ argY /local argA argB][ argA: argZ argB: argY func1 argA argB argA: argZ argB: argY reduce [argA argB] ] probe funcA 2 3 |
Henrik 30-Apr-2009 [1925x2] | What outcome are you expecting? |
Also note that in funcA in your last bit pasted, func1 has no effect. | |
Sunanda 30-Apr-2009 [1927] | Regarding the many ways of creating a function. I always use 'func .... Life just seems too short to bother with the 'does and 'has shortcuts....The result of them is a standard function anyway. So, for me, the choice is between 'func and 'function. I've made the choice to use 'func, but I would have been just as happy to use 'function. It's a personal preference about how local variables are specified: f: func [a /local b][b: join a a return b] f: function [a][b][b: join a a return b] (though I may change my choice if I were dynamically creating functions rather than typing them :) |
mhinson 30-Apr-2009 [1928] | I was expecting funcA to be passed the values 2 & 3 funcA refer to them as argZ & argY FuncA to use local variables argA & argB & these variables to be given the content of argZ & argY funcA calls func1 and passes it values in argZ & argY func1 recieves values passed and refers to them as arg3 & arg4 func1 uses local vars arg1 & arg2 which are given the content of arg3 & arg4 func1 swaps position of values in arg1 & arg2 (so we know the function has worked) arg3 & arg4 are given the values of arg1 & arg2 func1 ends and passes the changed content of argZ & argY back to funcA that called it, but as argA & argB The end part of my code is wrong.. it should be argZ: argA argY: argB reduce [argZ argY] so expecting argZ & argY to takeon the content of argA & argB finaly passes the content of argZ & argY back to where it was called so the probe shows the swapped values. |
Izkata 30-Apr-2009 [1929x2] | Both functions use pass-by-value, so they can't affect the variables outside of themselves using internal references. And, nothing is being done with what func1 returns: >> func1 2 3 == [3 2] Try this: funcA: func [argZ argY /local argA argB][ argA: argZ argB: argY probe Retval: func1 argA argB argA: Retval/1 argB: Retval/2 reduce [argA argB] ] >> funcA 1 2 [2 1] ;printed by the "probe" == [2 1] ;returned from the function |
(Also, I just copy/pasted without adding Retval to the local variable list) | |
mhinson 30-Apr-2009 [1931x2] | Thanks, the key to my understanding this time was that Both functions use pass-by-value, so they can't affect the variables outside of themselves using internal references I was under the mistaken impression that all the variables unless explicitly made local, would be global. Thanks for putting me on the right path again. |
ah, I can see why I was confused.. this function dat2: "-" f2: func [dat2] ["operating on the global" append dat2 "+" return "added" ] print f2 dat2 print dat2 print f2 dat2 print dat2 keeps adding a "+" to dat2, but if only the value of dat2 is passed to the function I cant see why is is not just doing append "-" "+" which would not seem to have any effect on dat2.. so in this case dat2 seems to be global. ~~confused~~ | |
Izkata 30-Apr-2009 [1933] | In this case, the value passed into f2 is a string!, a subset of series! (block!, file!, and a couple others are also series!). Series! values are the equivalent of pass-by-reference, like how passing an array as an argument in C is pass-by-reference (or similar to it... I forget the exact terminology). Append works by modifying a series! without creating a new one. |
Henrik 30-Apr-2009 [1934] | the value is not copied, which is why it keeps appending. |
mhinson 30-Apr-2009 [1935] | Now I have seen references to this behaviour & the need to use "copy" in some contexts, but I have not managed to understand it yet. I suspect it is a very fundemental thing to grasp. |
Henrik 30-Apr-2009 [1936x2] | It is very fundamental yes. You must see it as such: REBOL is very economical. It will aggresively reuse blocks and strings when it can. |
And so if you specifically want to keep a series from being changed by some operation, you must copy it. | |
mhinson 30-Apr-2009 [1938] | ah. so this is for variables containing series types only? numbers get passed as values (which is in effect a copy?) |
Henrik 30-Apr-2009 [1939x4] | If you type: >> "" in the console. A string is allocated. You can't reuse it here, because you haven't referenced it to get back to it. But it would stay in memory until it's garbage collected. But in this code: >> loop 10 [append "" 1] == "1111111111" The string can be obtained again by the code itself. REBOL reuses the string. |
Series, yes. You can also reference objects this way. Another trap is that series within series are also reused. This is why COPY/DEEP exists. | |
If you know when REBOL reuses series, you can make quite memory efficient and fast code. | |
If you don't know, then you can get some strange bugs. If a series changes without an apparent reason, then it's likely due to whether it's copied or not. | |
mhinson 30-Apr-2009 [1943] | ah.. this is good stuff.. And this (as expected) does NOT add 1 to dat5 each time it is called. dat5: 5 f5: func [dat5][ dat5: dat5 + 1 return dat5 ] print f5 dat5 print f5 dat5 I get it now, I just need to know how to recognise my types accurately. |
Henrik 30-Apr-2009 [1944] | Another important point: In the context of your function above, it doesn't actually matter whether the input is global. This is because REBOL works more on a basis of context rather than locals and globals. Locals and globals are probably what you are used to from other languages, but in REBOL that functionality is achieved through contexts. If the content of the context is allowed to survive, the content will survive. Try: boo: func [/local pond] [ pond: [] append pond 'fish ] >> boo boo == [fish fish] >> boo == [fish fish fish] No globals. :-) |
Maxim 30-Apr-2009 [1945] | other languages are like that too mind you... pointers allocated on the heap will do the same thing... default values for python, for example do the same thing exactly. |
mhinson 30-Apr-2009 [1946x3] | I get it now I think... as expected the code below returns 6 every time it is called. I need to make sure I can recognise what types I am dealing with. Thanks. dat5: 5 f5: func [dat5][ dat5: dat5 + 1 return dat5 ] print f5 dat5 print f5 dat5 |
sorry for multiple posts.. client seemed to have lost my first post. | |
I can't see why that would work that way. Why does pond:[] not make pond be [] each time the function is called? This is close to one of the first questions I wrote myself in my notebook, but not been able to find the answer to. I read the words here http://www.rebol.com/docs/core23/rebolcore-9.html#section-3.6 which seems to be very closly related. Is this just a Rebolish thing it does because it can be useful in some other context? or is there a logical reason that I am not appreciating. Sorry, I am not good at just doing as I am told, I find it helps me remeber if I have better understanding. Thanks. | |
Henrik 30-Apr-2009 [1949x2] | Because the contents of a function is really a context, and once that function is created, it doesn't disappear, including the blocks and series that are existing in that function. (We have to be careful here about using the word "context" to describe what we say, and the concept of "contexts" in REBOL. Don't mix it up.) |
The document you link to is exactly that phenomenon. It's both fundamental and very useful in REBOL for many things. | |
mhinson 30-Apr-2009 [1951] | to store a dynamic value called by several parts of the code perhaps? |
Henrik 30-Apr-2009 [1952] | It's not a unique phenomenon. It's everywhere in REBOL. |
Sunanda 30-Apr-2009 [1953] | It is initially confusing, because the apparent strange behaviour is limited to series, not (not sure what the official term is) numbers. If you try this: f: func [a /local b c] [b: [] c: 0 append b a c: c + a] f 1 f 2 source f You can see that (quite literally, in a metaphorical sense) the in-memory copy of function f has been changed: f: func [a /local b c] [b: [] c: 0 append b a c: c + a] f 1 f 2 source f To not have it change in that way (or to re-initialise b, if you like): f: func [a /local b c] [b: COPY [] c: 0 append b a c: c + a] f 1 f 2 source f But 'c has not changed in either case: c: 0 means exactly what it says. |
mhinson 1-May-2009 [1954] | I have a reasonable understanding of functions now thanks to all your help. Now I have decided to have another go at understanding parsing & what I have picked up in more general terms seems to have helped my understanding of the documentation a bit better. The question I am trying to solve at the moment is: Is there a straight forward way to extract the string "two.txt" from the following string {randomXXXrandom.log XXXrandom.txtrandom} My limited skills let me extract from the first XXX to .txt, but not from the XXX that preceeds the .txt alone. |
Pekr 1-May-2009 [1955] | what do you mean by "two.txt"? I can't see it in your string ... |
mhinson 1-May-2009 [1956] | I changed my string... doh... it is "random.txt" now |
Graham 1-May-2009 [1957] | what's a sample of what you are trying to do ? |
mhinson 1-May-2009 [1958] | {randomXXXrandom.log XXXrandom.txtrandom} is the testing string & I am trying to extract only the string after XXX which ends with .txt |
older newer | first last |