First, a few variables and functions were renamed to be more reflective of what they do, e.g. the function unsetVar
was renamed to unsetVarIndex
as it is returning an index (or -1) to an unset variable not the variable. tvar
was the actual unset variable, that will be renamed to unsetVar
. But the other improvement is to the code is in the area that creates new arrays with zero/one settings substituted for the Unset
variable. This is that code as it stood:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: |
let tvar = Array.get curVars varIndex // change the unset var to One and Zero let zeroVar = { tvar with Setting = Zero } let varArrayZero = Array.copy curVars // copy the array so we can change element Array.set varArrayZero varIndex zeroVar let gEstimateZero = estimator wlimit varArrayZero let oneVar = { tvar with Setting = One } let varArrayOne = Array.copy curVars // copy the array so we can change element Array.set varArrayOne varIndex oneVar let gEstimateOne = estimator wlimit varArrayOne |
Along with these variable renames, consider another approach to the beginning part of the while loop:
1: 2: 3: 4: 5: 6: 7: 8: |
while not queue.IsEmpty do match queue with | curVars :: restOfQueue -> let unsetVarIndex = unsetVarIndex curVars if not (unsetVarIndex = -1) then let varArrayZero = Array.mapi (fun index var -> if index = unsetVarIndex then {var with Setting = Zero} else var) curVars let varArrayOne = Array.mapi (fun index var -> if index = unsetVarIndex then {var with Setting = One} else var) curVars |
The first version created a copy of the curVar
array, a new element and then used Array.set
to change the array. This of course works, but the code above is another choice for implementation that avoids intermediate values. It uses the Array.mapi
function which creates a new array, applying a function with an integer (index) and element argument to each array member. In our case, when the index is the same as the unset var’s index we return the variable with Zero or One as a setting, otherwise leave it as is. This is applied to a copy of the array which is the last argument to the Array.mapi
function. As an alternative, the last argument (curVars
) can be piped to the function (see piping). This can sometimes make the code easier to read, for example:
1: 2: |
let varArrayZero = curVars |> Array.mapi (fun index var -> if index = unsetVarIndex then {var with Setting = Zero} else var) let varArrayOne = curVars |> Array.mapi (fun index var -> if index = unsetVarIndex then {var with Setting = One} else var) |
The pipeline operator is left associative so h |> g |> f
groups as (h |> g) |> f
The pipeline operator (|>
)doesn’t introduce any new capabilities, it is just, as they say, ‘syntactic sugar’ for styling the code. That is for a value b and function a (that accepts b as an argument), each of these means the same thing: a b
and b |> a
. The idea is that the result b
is piped to a
as a’s last argument. So an expression such as f (g h)
could be written as h |> g |> f
. Anyway, this final expression using mapi for defining each of varArrayZero
and varArrayOne
is more readable and understandable as to what is trying to be accomplished, versus the ‘array set’ method before. Use the download button to see the complete code at this point.