Advent of Code 2019 day 2 in F#
Possibly not the best solution, but here's one that uses F# more extensively:

let rec processProgram (i: int) (ops: int list) =
    match ops with
    | opCode :: aPos :: bPos :: outPos :: rest  when opCode = 1 -&gt; // add op code
        let a = ops |&gt; List.item aPos
        let b = ops |&gt; List.item bPos
        let complete = [opCode; aPos; bPos; outPos] @ processProgram (i + 4) rest
        let (left, right) = complete |&gt; List.splitAt outPos
        left @ [a + b] @ (right |&gt; List.skip 1)
    | opCode :: aPos :: bPos :: outPos :: rest when opCode = 2 -&gt; // multiple op code
        let a = ops |&gt; List.item aPos
        let b = ops |&gt; List.item bPos
        let complete = [opCode; aPos; bPos; outPos] @ processProgram (i + 4) rest
        let (left, right) = complete |&gt; List.splitAt outPos
        left @ [a * b] @ (right |&gt; List.skip 1)
    | head :: rest  when head = 99 -&gt; // terminate
        ops
    | _ -&gt;
        failwith "Unsported opcode"



I've turned the function into a recursive function with let rec so that it can be called from within itself, I'll generally use this rather than a loop.

Next I'm using list rather than array so that I can pattern match on the operations. Let's look at that:

match ops with
| opCode :: aPos :: bPos :: outPos :: rest  when opCode = 1 -&gt; // add op cod


This expects the list to have at least 4 elements, and I'm destructing it into the pieces we care about, opCode (what we're doing), aPos and bPos (where in the instruction set the values we want are) and outPos (where to put the output in the instruction list). It's then got a when test on the end to check the value of the opCode so we can hit the right op code branch.

When the match is hit we grab the values from their current pos and then process the rest of the instruction set, generating a new list with:

let complete = [opCode; aPos; bPos; outPos] @ processProgram (i + 4) rest


The @ operator concats two list's together.

Then we'll split it on the outPos:

let (left, right) = complete |&gt; List.splitAt outPos


This gives us a tuple of int list * int list that we deconstruct into two variables and lastly we rebuild the list through concatinations:

left @ [a + b] @ (right |&gt; List.skip 1)


We use the left part to start with, as it is all up until the outPos, then insert the result of the op-code (add in this place) and then concat-ing the right but skipping outPos which is the head of the list.

Side note: it's not stated in the requirements that you can update positions beyond the current op stack, so I didn't implement that, it'll only do reverse-updates.