When I enter (map [?1 + ?2] [1 2 3] [2 4 6]) into the command center, it works fine. But when I enter this code
to test
(map [?1 + ?2] [1 2 3] [2 4 6])
end
I get the diagnostic: "Expected command." with map highlighted. I'm stumped. Suggestions would be appreciated. Thanks.
(I'm using NetLogo 5.1.0.)
The problem is that map is not considered a command (as the diagnostic says). When I replace map with foreach (and put the function at the end) it's fine.
In fact, that's what I really wanted in the first place. I was using map for it's side-effects of running through multiple lists rather than to return a list. My mistake.
For user convenience, the command center allows you to set the "context" of your commands and does a little extra interpretation depending on that context. The problem is not that the map reporter is failing, but that it reports a list, and you need a command saying what to do with that list.
After you enter (map [?1 + ?2] [1 2 3] [2 4 6]) in the command center, look not just at the result but also at the code actually executed (right above the result). If you put that code in your test procedure, it will work.
you code does not work because you are producing a new list with map but you are not assigning that list to any variable. You are right that map is not a command primitive, it is a reporter primitive, so it returns a value and you have to put that value somewhere, like print it on the screen:
to test
print (map [?1 + ?2] [1 2 3] [2 4 6])
end
or store it in a variable:
to test
let a-variable (map [?1 + ?2] [1 2 3] [2 4 6])
print a-variable
end
Related
I am trying to split a string variable into multiple dummy coded variables. I used these sources to get an idea of how one would achieve this task in SPSS:
https://www.ibm.com/support/pages/making-multiple-string-variables-single-multiply-coded-field
https://www.spss-tutorials.com/spss-split-string-variable-into-separate-variables/
But when I try to adapt the first one to my needs or when I try to convert the second one to a macro, I fail.
In my dataset I have (multiple) variables that contain a comma seperated string that represents different combinations of selected items (as well as missing values). For each item of a specific variable I want to create a dummy variable. If the item was selected, it should be represented with a 1 in the new dummy variable. If it was not selected, that case should be represented with a 0.
Different input variables can contain different numbers of items.
For example:
ID
VAR1
VAR2
DMMY1_1
DMMY1_2
DMMY1_3
1
1, 2
8
1
1
0
2
1
1, 3
1
0
0
3
3, 1
2, 3, 1
1
0
1
4
2, 8
0
0
0
Here is what I came up with so far ...
* DEFINE DATA.
DATA LIST /ID 1 (F) VAR1 2-5 (A) VAR2 6-12 (A).
BEGIN DATA
11, 28
21 1, 3
33, 12, 3, 1
4 2, 8
END DATA.
* MACRO SYNTAX.
* DEFINE VARIABLES (in the long run these should/will be inside the macro function, but for now I will leave them outside).
NUMERIC v1 TO v3 (F1).
VECTOR v = v1 TO v3.
STRING #char (A1).
DEFINE split_var(vr = TOKENS(1)).
!DO !#pos=1 !TO char.length(!vr).
COMPUTE #char = char.substr(!vr, !#pos, 1).
!IF (!#char !NE "," !AND !#char !NE " ") !THEN
COMPUTE v(NUMBER(!#char, F1)) = 1.
!IFEND.
!DOEND.
!ENDDEFINE.
split_var vr=VAR1.
EXECUTE.
As I got more errors than I can count, it's hard to narrow down my problem. But I think the problem has something to do with the way I use the char.length() function (and I am a bit confused when to use the bang operator).
If anyone has some insights, I would really appreciate some help :)
There is a fundamental issue to understand about SPSS macro - the macro does not read or interact in any way with the data. All the macro does is manipulate text to write syntax. The syntax created will later work on the actual data when you run it.
So, for example, Your first error is using char.length(!vr) within the syntax. You are trying to get the macro to read the data, calculate the length and use, but that simply can't be done - the macro can only work with what you gave it.
Another example in your code: you calculate #char and then try to use it in the macro as !#char. So that obviously won't work. ! precedes only macro functions or arguments. #char, in your code, is neither, and it can't become one - can't read the data into the macro...
To give you a litte push forward: I understand you want the macro loop to run a different number of times for each variable, but you can't use char.length(!vr). I suggest instead have the macro loop as many times as necessary to be sure you can deal with the longest variable you'll need to work with.
And another general strategy hint - first, create syntax to deal with one specific variable and one specific delimiter. Once this works, start working on a macro, keeping in mind that the only purpose of the macro is to recreate the same working syntax, only changing the parameters of variable name and delimiter.
With my new understanding of the SPSS macro logic (thanks to #eli-k) the problem was quite easy to solve. Here is the working solution.
* DEFINE DATA.
DATA LIST /ID 1 (F) VAR1 2-5 (A) VAR2 6-12 (A).
BEGIN DATA
11, 28
21 1, 3
33, 12, 3, 1
4 2, 8
END DATA.
* DEFINE MACRO.
DEFINE #split_var(src_var = !TOKENS(1)
/dmmy_var_label = !DEFAULT(dmmy) !TOKENS(1)
/dmmy_var_lvls = !TOKENS(1))
NUMERIC !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls) (F1).
VECTOR #dmmy_vec = !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls).
STRING #char (A1).
LOOP #pos=1 TO char.length(!src_var).
COMPUTE #char = char.substr(!src_var, #pos, 1).
DO IF (#char NE "," AND #char NE " ").
COMPUTE #index = NUMBER(#char, F1).
COMPUTE #dmmy_vec(#index) = 1.
END IF.
END LOOP.
RECODE !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls) (SYSMIS=0) (ELSE=COPY).
EXECUTE.
!ENDDEFINE.
* CALL MACRO.
#split_var src_var=VAR2 dmmy_var_lvls=8.
Loop variable of repeat can be used in its block like this:
>> b: func [x] [x + i]
== func [x][x + i]
>> repeat i 2 [print reduce append copy [b] [3]]
4
5
You can see that the variable "i" is used by the function "b".
However,in the following example, the loop variable "idx" is not seen by the function. Error message is given:
*** Script Error: idx has no value
Red []
map: function [a-func a-block][
result: [] args: [] clear result
either parse a-block [some block!][
repeat idx length? a-block/1 [
clear args
foreach x a-block [append args to-block x/:idx]
append result reduce append copy [a-func] args
]
return result
]
[
repeat idx length? a-block [
append result to-block a-func a-block/:idx
]
]
]
map func [x y] [x + y - idx] [[1 2] [3 4]]
Why is the second code wrong? And how to make it working?
Loop variable of repeat can be used in its block like this
Unfortunately, this is conceptually wrong. Loop "variable" is not used in the block, it is "globally visible" both to function's body block and to repeat.
>> repeat index 5 []
>> index
== 5
Diagrammatically, that's lambda → <idx in global context> ← repeat, not lambda → repeat → <idx in repeat's "scope"> as you probably think.
However,in the following example, the loop variable "idx" is not seen by the function.
This is because you are using function constructor, which makes idx word local to its context, like so:
>> function [][repeat index 3 []]
== func [/local index][repeat index 3 []]
By contrast, func (used in your first example) doesn't do that.
>> func [][repeat index 3 []]
== func [][repeat index 3 []]
That is, in this code:
map func [x y] [x + y - idx] [[1 2] [3 4]]
idx within the anonymous function that you map over the block and idx in map implementation are two completely different "variables", bound to different contexts: one to the global (in which it has no value, hence the error message), and another to a local (where it is set to none by default).
The mechanics of Red's "scoping" model (or rather complete absence thereof) is a bit of an advanced topic, though I can elaborate on it if needed.
Suffice to say that it does not rely on traditional lexical scoping (like in most of the Lisp dialects), nor does it have variables in the strict sense of the term. Rather, it relies on symbolic values (aka words) that carry with them a binding to namespaces (aka contexts), which can be changed at will during the runtime (see bind in the example below) — a bit like f-expressions in Kernel and older Lisps, or perhaps anaphoric macro, of which collect (see below also) is a prime example: note that it "captures" keep word, which from then on refers to its internal context, where it is defined as an ad-hoc alias for append. Check out source collect output to see what I mean.
Here's a sketch of map (yours technically is more like zip, but anyway) to give you a hint at the potential solution.
map: function [
function [function!]
series [series!]
][
spec: spec-of :function ; ideally needs to be cleaned up
step: length? spec
index: 1
bind body-of :function 'index
collect [
foreach :spec series [
keep/only do compose [(:function) (:spec)]
index: index + step
]
]
]
Example:
>> map func [x] [reduce [index x]][a b c d]
== [[1 a] [2 b] [3 c] [4 d]]
>> map func [x y] [reduce [index x + y - index]][9 2 1 4]
== [[1 10] [3 2]]
I'm using the matrix extension in my model and I'd like to be able to change the elements of this matrix through the GUI rather than hard coding them. It looks like this at the moment:
extensions [matrix]
globals [test_matrix]
to setup
set test_matrix matrix:from-row-list [[
1
2
3
4
]]
end
But if I try to set the values using the Input function on the GUI I get an error that it 'expected a literal value.'
set test_matrix matrix:from-row-list [[
element1
element2
element3
element4
]]
When you do [ 1 2 3 4 ] in the first section you're creating a list literal, and NetLogo only allows constant values in list literals (numbers, strings, other list literals). See the Lists section of the programming guide for more.
To make a list with non-literal (variable or expression) values use the list primitive:
set test_matrix matrix:from-row-list (list (list
element1
element2
element3
element4
))
See the FAQ entry as well.
How do you iterate a function of multivalent rank (>1), e.g. f:{[x;y] ...} where the function inputs in the next iteration step depend on the last iteration step? Examples in the reference manual only iterate unary functions.
I was able to achieve this indirectly (and verbosely) by passing a dictionary of arguments (state) into unary function:
f:{[arg] key[arg]!(min arg;arg[`y]-2)}
f/[{0<x`x};`x`y!6 3]
Note that projection, e.g. f[x;]/[whilecond;y] would only work in the scenario where the x in the next iteration step does not depend on the result of the last iteration (i.e. when x is path-independent).
In relation to Rahul's answer, you could use one of the following (slightly less verbose) methods to achieve the same result:
q)g:{(min x,y;y-2)}
q)(g .)/[{0<x 0};6 3]
-1 -3
q).[g]/[{0<x 0};6 3]
-1 -3
Alternatively, you could use the .z.s self function, which recursively calls the function g and takes the output of the last iteration as its arguments. For example,
q)g:{[x;y] x: min x,y; y:y-2; $[x<0; (x;y); .z.s[x;y]]}
q)g[6;3]
-1 -3
Function that is used with '/' and '\' can only accept result from last iteration as a single item which means only 1 function parameter is reserved for the result. It is unary in that sense.
For function whose multiple input parameters depends on last iteration result, one solution is to wrap that function inside a unary function and use apply operator to execute that function on the last iteration result.
Ex:
q) g:{(min x,y;y-2)} / function with rank 2
q) f:{x . y}[g;] / function g wrapped inside unary function to iterate
q) f/[{0<x 0};6 3]
Over time I stumbled upon even shorter way which does not require parentheses or brackets:
q)g:{(min x,y;y-2)}
q){0<x 0} g//6 3
-1 -3
Why does double over (//) work ? The / adverb can sometimes be used in place of the . (apply) operator:
q)(*) . 2 3
6
q)(*/) 2 3
6
I have this function f
f:{{z+x*y}[x]/[y]}
I am able to call f without a 3rd parameter and I get that, but how is the inner {z+x*y} able to complete without a third parameter?
kdb will assume, if given a single list to a function which takes two parameters, that you want the first one to be x and the remainder to be y (within the context of over and scan, not in general). For example:
q){x+y}/[1;2 3 4]
10
can also be achieved by:
q){x+y}/[1 2 3 4]
10
This is likely what's happening in your example.
EDIT:
In particular, you would use this function like
q){{z+x*y}[x]/[y]}[2;3 4 5 6]
56
which is equivalent to (due to the projection of x):
q){y+2*x}/[3 4 5 6]
56
which is equivalent to (due to my original point above):
q){y+2*x}/[3;4 5 6]
56
Which explains why the "third" parameter wasn't needed
You need to understand 2 things: 'over' behavior with dyadic functions and projection.
1. Understand how over/scan works on dyadic function:
http://code.kx.com/q/ref/adverbs/#over
If you have a list like (x1,x2,x3) and funtion 'f' then
f/(x1,x2,x3) ~ f[ f[x1;x2];x3]
So in every iteration it takes one element from list which will be 'y' and result from last iteration will be 'x'. Except in first iteration where first element will be 'x' and second 'y'.
Ex:
q) f:{x*y} / call with -> f/ (4 5 6)
first iteration : x=4, y=5, result=20
second iteration: x=20, y=6, result=120
2. Projection:
Lets take an example funtion f3 which takes 3 parameters:
q) f3:{[a;b;c] a+b+c}
now we can project it to f2 by fixing (passing) one parameter
q) f2:f3[4] / which means=> f2={[b;c] 4+b+c}
so f2 is dyadic now- it accepts only 2 parameters.
So now coming to your example and applying above 2 concepts, inner function will eventually become dyadic because of projection and then finally 'over' function works on this new dyadic function.
We can rewrite the function as :
f:{
f3:{z+x*y};
f2:f3[x];
f2/y
}