I've been trying to figure out how to resize an already initialized array in OCaml. However, it seems that while you can write a function that will create a brand new array with the elements of the old one copied over (and extra slots), that function's output cannot be assigned to existing array. How would one do this? Is there an easy way in which to use references to make this happen if not without?
Here's a tiny example:
let rec function_that_adds_to_array storage args ... =
(* let's say the function has a set of if-else constructs that controls what it does, and let's further say that one of the cases leads to: *)
let new_array = Array.make (Array.length storage) ("Null", ("Null", -2)) in
Array.blit collection 0 new_array 0 index; (* index is controlled by the function's recursion *)
Array.set new_array index (obj_name, obj_expr);
new_array) (* insert the macro at tail *)
...
;;
### main method ###
let storage = Array.make 10 ((x : string), (a, b)) in
...
while true do
...
storage = function_that_adds_to_array storage args....;
...
A print statement at the end of the function_that_adds_to_array(...) confirms that a new array is returned, containing the old elements of the initial array, however, in the main method, storage remains identical. Is this because of the immutability of OCaml's elements? I thought Arrays were mutable. I've looked around, and some mention writing hacks to getting OCaml to act like Perl, however, using one individual's resize hack function proved futile. Any way I can get storage to become a new array? It needs to be an update-able collection of tuples (i.e. (string, (x, y)) )?
In OCaml you can't assign to variables, period. There's no special limitation for arrays. However, you can have a variable that is bound to a reference, which can hold different values of the same type. This structure is what is usually called a "variable" in imperative languages. To have different sized arrays in a variable x you could write code as follows:
# let x = ref [| 0 |];;
val x : int array ref = {contents = [|0|]}
# Array.length x;;
Error: This expression has type int array ref
but an expression was expected of type 'a array
# Array.length !x;;
- : int = 1
# x := [| 2; 3 |];;
- : unit = ()
# Array.length !x;;
- : int = 2
The ! operator dereferences a reference, and the := operator assigns a new value.
If you're new to OCaml I'll include my standard advice that you should investigate the use of immutable data before deciding to recreate the patterns of imperative languages that you already know. If you're not new to OCaml, I apologize for my impertinence!
Related
How to loop through the elements of an array and access them by their index in Q# language since the conventional looping in C++ doesn't work here.
Suppose the array is arr = T[], where T is any type in Q#.
let n = Length(arr);
for (i in 0 .. (n-1)) {
// use the element arr[i]
}
It is to be noted that if arr is defined using 'let' then the values are immutable and can be accessed but not assigned. If it is defined using 'mutable' literal then the elements can also be set using the 'set' keyword. In that case define the array is follows
mutable arr = new T[N]
where N is the length required.
How can I create an Array of Convex.MaxAtoms (or for that matter, other Convex types) with the Convex package? I'm not sure if an Array is the right structure, but what I want to do is initialize something my_array of length n so that I can update each element in a loop like
using Convex
v = Variable(n)
w = Variable(n)
my_array = ...initialized array?...
for i = 1:n
my_array[i] = max(v[i],w[i])
end
I've tried doing
my_array = Convex.MaxAtom[]
for i = 1:n
push!(x, max(v[i], w[i]))
end
but I want to avoid reallocating memory and do it upfront. I feel that I must be missing an important part of Julia in not understanding what types to use to construct this.
In Julia Vector{AnyType}(n) (replace AnyType with a valid type in the application) allocates a vector of uninitialized AnyType elements of length n. More generally, Array{AnyType,3}(2,3,4) would allocate a 3-dimensional tensor of size 2x3x4 and analogously any dimension or shape can be allocated.
For the case in the question, a solution would be:
a = Vector{Convex.MaxAtom}(n)
P.S. the elements are allocated but uninitialized, this is fast, but it may be safer to use fill(some_value, n) or zero(AnyType, n) (which requires zero(AnyType) to be defined).
When I dereference an array using #$arrayRef or #{$arrayRef} it appears to create a copy of the array. Is there a correct way to dereference an array?
This code...
sub updateArray1 {
my $aRef = shift;
my #a = #$aRef;
my $aRef2 = \#a;
$a[0] = 0;
push(#a, 3);
my $aRef3 = \#a;
print "inside1 \#a: #a\n";
print "inside1 \$aRef: $aRef\n";
print "inside1 \$aRef2: $aRef2\n";
print "inside1 \$aRef3: $aRef3\n\n";
}
my #array = (1, 2);
print "before: #array\n";
my $ar = \#array;
print "before: $ar\n\n";
updateArray1(\#array);
print "after: #array\n";
$ar = \#array;
print "after: $ar\n\n";
... has the output...
before: 1 2
before: ARRAY(0x1601440)
inside1 #a: 0 2 3
inside1 $aRef: ARRAY(0x1601440)
inside1 $aRef2: ARRAY(0x30c1f08)
inside1 $aRef3: ARRAY(0x30c1f08)
after: 1 2
after: ARRAY(0x1601440)
As you can see, #$aRef creates a new pointer address.
The only way I've found to get around this is to only use the reference:
sub updateArray2 {
my $aRef = shift;
#$aRef[0] = 0;
push(#$aRef, 3);
print "inside2 \#\$aRef: #$aRef\n";
print "inside2 \$aRef: $aRef\n\n";
}
updateArray2(\#array);
print "after2: #array\n";
$ar = \#array;
print "after2: $ar\n\n";
Which produces the output:
inside2 #$aRef: 0 2 3
inside2 $aRef: ARRAY(0x1601440)
after2: 0 2 3
after2: ARRAY(0x1601440)
Is it possible to dereference a pointer to an array without the whole array getting duplicated? Or do I need to keep it in reference form and dereference it any time I want to use it?
Dereferencing does not create a copy as can be seen in the following example:
my #a = qw(a b c);
my $ra = \#a;
#{$ra}[0,1] = qw(foo bar); # dereferencing is done here but not copying
print #$ra; # foo bar c
print #a; # foo bar c
Instead, assigning the (dereferenced) array to another array creates the copy:
my #a = qw(a b c);
my $ra = \#a;
my #newa = #$ra; # copy by assigning
$newa[0] = 'foo';
print #newa; # foo b c
print #a; # a b c
Assigning one array to another says essentially that all elements from the old array should be assigned to the new array too - which is different from just having a different name for the original array. But assigning one array reference to another just makes the old array available with a different name, i.e. copy array reference vs. copy array content.
Note that this seems to be different to languages like Python or Java because in these languages variables describe array objects only, i.e. the reference to the array and not the content of the array.
Using the experimental refaliasing feature:
use 5.022;
use warnings;
use feature 'refaliasing';
no warnings 'experimental::refaliasing';
\my #array = $array_ref;
But why not just keep it as a reference? There's nothing you can do with an array that you can't also do with an array reference.
My observation/understanding is that it's about the name--if you give a name to the dereferenced array, it will be copied, since perl variables are passed by copy--they're exactly like structs in C++. But even if a reference is copied (this is analogous to int *newPtr = oldPtr in C/C++), each copy of the reference will point at the same object. Only if you access its elements via the reference, or by dereferencing it inline, the original array will be modified. I don't think there's any way around this. When you call my #foo = #{$barRef}, you're calling a copy constructor. Scalars are the same--when you modify an argument via $_[0] = val, the caller's variable is modified as well. But if you give a name to the variable, a la my $arg = $_[0], a copy is made.
That said, there are convenient ways to work with references that you should know about, if you don't already use them:
$arrayRef->[0] = "foo";
$hashRef->{key} = "value";
$codeRef->(); # execute a code reference
But indeed, since push can't deal with a reference, you need to use an inline dereference like you did in your example.
If you really, really want to create an array which is a reference, there's an old perl technique that can do it. You shouldn't use this in modern code. It's described here: https://perldoc.perl.org/perlsub.html#Passing-Symbol-Table-Entries-(typeglobs)
The code explicitly asks for data to be copied
my #a = #$aRef;
in order to create a new array #a.
It is not clear to me what you mean by
Is it possible to dereference a pointer to an array without the whole array getting duplicated?
If all values are needed in some operation – to make another array, or print them out, or send them to sort or map ... – then data may be copied, or it may not if that is done by pointer. If data is copied (even only on the stack) then it's the same as if we had an array, it is effectively "dereferenced."
It's a question of what is done with data and one cannot say much in general.
If you need to access a specific element (or slice) then derefence that, don't create a new array.
However, please not by #$aRef[0] = 0; even as it happens to be legal, but by either of
$$aRef[0] = 0;
$aRef->[0] = 0;
where I find the second version to be generally safer against silly errors, and clearer.
I have some code in Swift 3.0 like so for trying to update the property in a array of elements...
for point in listOfPoints {
var pointInFrame : Float = Float(point.position.x * sensorIncomingViewPortSize.width) + Float(point.position.y)
point.status = getUpdateStatus( pointInFrame )
}
However I get a compile error of:
'Cannot assign to property: 'point' is a 'let' constant' [for line 3]
Is there anyway to make the iterator (point) mutable in Swift, like how you can use 'inout' for a function parameter?
Or are you supposed to do this task another way?
Thanks in Advance.
Stan
Just change it to var instead of let where you declare point. let is a constant.
Another way to accomplish this:
for i in 0 ... myStructArray.count - 1 {
var st = myStructArray[i]
st.someStringVariable = "xxx" // do whatever you need with the struct
st.someIntVariable = 123 // do more stuff
// last step (important!):
myStructArray[i] = st // necessary because structs are VALUE types, not reference types.
}
If you only need to make one change, you can omit the steps of defining the local variable (st in the example) as the array element and then afterwards setting the array element as equal to the local variable. But if you're going to make lots of changes to the element, if may be cleaner to make the local variable, make all the changes to it, and then assign that variable back to the array element.
If the array was of a Class rather than a Struct, that last step of assigning back wouldn't be necessary (reference type -- Class, vs value type -- Struct).
In Matlab, I was trying to put anonymous functions in an array:
>> a=[#(k)0.1/(k+1) #(k)0.1/(k+1)^0.501]
??? Error using ==> horzcat
Nonscalar arrays of function handles are not allowed; use cell arrays
instead.
So I wonder what kinds of elements are allowed in an array, and in a cell array?
For example, I know that in an array, the elements can be numerical or strings. What else?
In short: Cell array is a heterogeneous container, regular array is homogeneous. This means that in a regular array all of the elements are of the same type, whereas in cell array, they can be different. You can read more about cell array here.
Use cell array when:
You have different types in your array
You are not sure whether in the future you might extend it to another types
You are working with objects that have an inheritance pattern
You are working with an array of strings - almost in any occasion it is preferable to char(n,m)
You have a large array, and you often update a single element in a function - Due to Matlabs copy-on-write policy
You are working with function handles (as #Pursuit explained)
Prefer regular array when:
All of the elements have the same type
You are updating the whole array in one shot - like mathematical operations.
You want to have type safety
You will not change the data type of the array in the future
You are working with mathematical matrices.
You are working with objects that have no inheritance
More explanation about copy-on-write:
When you pass an array to a function, a pointer/reference is passed.
function foo(x)
disp(x);
end
x= [1 2 3 4 5];
foo(x); %No copy is done here! A pointer is passed.
But when you change it (or a part of it), a copy is created.
function foo(x)
x(4) = x(4) + 1;
end
x= [1 2 3 4 5];
foo(x); %x is being copied! At least twice memory amount is needed.
In a cell array, only the cell is copied.
function foo(x)
x{4} = x{4} + 1;
end
x= {1 2 3 4 5}; %Only x{4} will be copied
Thus, if you call a function that changes a single element on a large array, you are making a lot of copies - that makes it slower. But in a cell array, it is not the case.
Function handles are actually the exception here, and the reason is that the Matlab syntax becomes surprising if you allow function handles to be a part of non-cell array. For example
a = #(x)x+1;
a(2); %This returns 2
But, if arrays of function handles were supported, then
b = [#(x)x+1, #(x)x+2];
b(2); %This would return #(x)x+2
b(3) = #(x)x+3; %This would extend the size of the array
So then would this be allowed?
a(2) = #(x)x+2; %Would this extend the size of the previously scalar array
Longwinded edit: This is documented in the release notes accompanying release R14, which was the first release allowing anonymous functions. Prior to R14 you could create function handles as references to m-file functions, and they could be placed in non-cell arrays. These could only be called using feval (e.g.: fnSin = #sin; output = feval(fnSin, pi)).
When anonymous functions were introduced, the Mathworks updated the syntax to allow a simpler calling convention (e.g. fnSin = #sin; output = fnSin(pi)) which had the effect of causing an ambiguity when using non-cell array of function handles. It looks like they did their best to grandfather this new behavior in, but those grandfathered conditions have certainly expired (this was 2004).
The arrays can store only data with a fixed length. For instance, double, single, char, logical, integer.
The reason is that (I guess) they are stored directly in a block of memory. On the other hand cells are stored as a list of pointers, each pointer can point to a data of different size.
That's why arrays cannot store strings, function handle, arrays, and multiple data types.
Those type can have different length. For instance 'bla' has 3 bytes, 'blabla' has 6 bytes. Therefore if they are stored in the same memory block, if you want to change 'bla' into 'blabla' you would have to shift all the rest of the memory, which would be very slow, and so it's not handled.