简体   繁体   中英

Shifting arrays in F#

So I have a function which shifts some ternary values in an array by the desired amount, but when I shift any array, (b) value(s) (on the right if shifting left, and the left if shifting right) will always be replaced with null. Here's my code:

let ( <<| ) (a:FalseTrit[]) (b:int) =
    array.Copy(a, b, a, 0, a.Length - 1)
    array.Clear(a, a.Length - b, b)
let ( |>> ) (a:FalseTrit[]) (b:int) =
    array.Copy(a, 0, a, b, a.Length - b)
    array.Clear(a, 0, b)

I couldn't find any answers on the internet. Is there a better way to do this, or something I did wrong? Thanks in advance.

Array.Clear sets a range of elements in an array to the default value of each element type (see docs ).

Since FalseTrit is a reference type and not a value type, it has default value null .

Expanding on the comment by Alexey Romanov why you should prefer standard library functions from Microsoft.FSharp.Collections.Array module over instance members of System.Array : Type inference makes them easier to use and curried arguments prettier.

While the documentation for Array.blit misses the assurance of System.Array.Copy in regard of arrays overlapping, I strongly suspect the same applies because of its underlying implementation:

If sourceArray and destinationArray overlap, this method behaves as if the original values of sourceArray were preserved in a temporary location before destinationArray is overwritten.

let (<<|) a b =
    Array.blit a b a 0 (Array.length a - b)
    Array.fill a (Array.length a - b) b Unchecked.defaultof<_>
// val ( <<| ) : a:'a [] -> b:int -> unit
let (|>>) a b =
    Array.blit a 0 a b (Array.length a - b)
    Array.fill a 0 b Unchecked.defaultof<_>
// val ( |>> ) : a:'a [] -> b:int -> unit 

Here, the behavior of the original code is kept: Unchecked.defaultof will return null for reference types.

On a stylistic note, consider replacing the code by a generator expression returning a fresh array, because mutation is not seen as functional best practice, and neither are custom operators returning unit .

let (<<|) a b = [|
    for i in b..Array.length a - 1 + b ->
        if i < Array.length a then a.[i]
        else Unchecked.defaultof<_> |]
// val ( <<| ) : a:'a [] -> b:int -> 'a []
let (|>>) a b = [|
    for i in -b..Array.length a - 1 - b ->
        if i < 0 then Unchecked.defaultof<_>
        else a.[i] |]
// val ( |>> ) : a:'a [] -> b:int -> 'a []

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM