我正在编写一个非常注重性能的程序,并且一直在使用C,但是有人告诉我函数式编程很酷,所以我决定用F#重写它。

无论如何,我在F#中很难复制算法的特定函数是Duff's device。它代替了典型的迭代,它展开了循环,因此每次迭代可以复制8个字节,而不是一个字节。

void copy_memory( char* to, char* from, size_t count ) {
    size_t n = (count+7)/8;
    switch( count%8 ) {
    case 0: do{ *to++ = *from++;
    case 7:     *to++ = *from++;
    case 6:     *to++ = *from++;
    case 5:     *to++ = *from++;
    case 4:     *to++ = *from++;
    case 3:     *to++ = *from++;
    case 2:     *to++ = *from++;
    case 1:     *to++ = *from++;
            }while(--n>0);
    }
}

这利用了大小写失败和跳转到C循环中间的能力,据我所知,不幸的是,这是F#似乎缺少的功能。

我在MSDN上阅读了一些文章,并认为F#的match功能将是我最接近C的switch的功能。所以,我开始写这段代码
open System.Reflection
let copyMemory (pTo : Pointer) (pFrom : Pointer) length =
    let n = (length + 7) / 8
    match n % 8 with
    | 0 ->

然后我不知道该怎么办。它不会让我在这里开始循环并在另一种情况下结束循环。

我可以使用F#中的某些内容进行大小写掉入并跳入循环的中间吗?如果您能为我做到这一点,我想我可以自己找出其余的人。

最佳答案

这是在F#中弄乱记忆的惯用方式:-)

#nowarn "9" //stop telling me I'm going to break something
open Microsoft.FSharp.NativeInterop

let inline (~+) ptr = NativePtr.add ptr 1

let rec copyMemory src dest = function
  | 0 -> ()
  | n ->
    NativePtr.read src |> NativePtr.write dest
    copyMemory +src +dest (n - 1)

但这可能更符合达夫(Duff)的精神
let inline (+>) s d =
  NativePtr.read !s |> NativePtr.write !d
  s:= NativePtr.add !s 1
  d:= NativePtr.add !d 1

let copyMemory src dst count =
  let n = ref ((count + 7) / 8)
  let s, d = ref src, ref dst
  let
    rec case_0() = s +> d; case_7()
    and case_7() = s +> d; case_6()
    and case_6() = s +> d; case_5()
    and case_5() = s +> d; case_4()
    and case_4() = s +> d; case_3()
    and case_3() = s +> d; case_2()
    and case_2() = s +> d; case_1()
    and case_1() = s +> d; decr n; if !n > 0 then case_0()
  match count % 8 with
  | 7 -> case_7() | 6 -> case_6()
  | 5 -> case_5() | 4 -> case_4()
  | 3 -> case_3() | 2 -> case_2()
  | 1 -> case_1() | _ -> case_0()

不过实话说
System.Buffer.BlockCopy(src, 0, dest, 0, count)

10-06 02:06