4

特定の点の周りに多次元点のグリッドを生成するコード形式を Java do F# に移植しようとしています。私はこれを思いつきました:

let gridGenerator midpoint stepSize steps = 
    seq {
        let n = Array.length midpoint
        let direction = Array.create n -steps
        let mutable lastIndex = n-1
        while lastIndex>=0 do
            let next = midpoint |> Array.mapi (fun i x -> x+ direction.[i]*stepSize)
            while lastIndex>=0 && direction.[lastIndex]=steps do 
                direction.[lastIndex]<- (-steps)
                lastIndex<-lastIndex-1;        
            if lastIndex>=0 then
                direction.[lastIndex]<-direction.[lastIndex]+1;
                lastIndex <- n-1;
            yield next;
    }

このコードが恐ろしく命令的であることに加えて (修正方法のヒントをいただければ幸いです)、コンパイル エラーが発生します。

Program.fs(18,15): エラー FS0407: 可変変数 'lastIndex' が無効な方法で使用されています。ミュータブル変数は、クロージャによってキャプチャできません。この突然変異の使用を排除するか、'ref' と '!' を介してヒープに割り当てられた可変参照セルを使用することを検討してください。

このエラーを修正するにはどうすればよいですか? より機能的にするにはどうすればよいですか?

例: midpoint [|0.0, 1.0|]、step size0.5およびstepsの場合、1私が期待する (実際には任意の順序で)

seq{[|-0.5, 0.5|], [|-0.5, 1.0|], [|-0.5, 1.5|], [|0.0, 0.5|], [|0.0, 1.0|], [|0.0, 1.5|], [|0.5, 0.5|], [|0.5, 1.0|], [|0.5, 1.5|]}

これは何度も実行されるため、パフォーマンスが重要であることにも注意してください。

4

3 に答える 3

4

これを行うためのより機能的な方法は次のとおりです。

let rec gridGenerator midpoint stepSize steps =
    match midpoint with
    | [] -> Seq.singleton []
    | p::point ->
        seq {
            for d in - stepSize * steps .. stepSize .. stepSize * steps do
                for q in gridGenerator point stepSize steps do
                    yield (p + d) :: q
        }

そして署名:

val gridGenerator : int list -> int -> int -> seq<int list>

結果を再利用する場合は、結果をキャッシュするか、(配列またはリストに)変換することを忘れないでください。

于 2012-06-08T12:00:27.027 に答える
4
let gridGenerator midpoint stepSize steps =
    seq {
        let n = Array.length midpoint
        let direction = Array.create n -steps
        let lastIndex = ref (n - 1)
        while !lastIndex >= 0 do
            let next = midpoint |> Array.mapi (fun i x -> x + direction.[i] * stepSize)
            while !lastIndex >= 0 && direction.[!lastIndex] = steps do
                direction.[!lastIndex] <- -steps
                decr lastIndex
            if !lastIndex >= 0 then
                direction.[!lastIndex] <- direction.[!lastIndex] + 1
                lastIndex := n - 1
            yield next
    }

?

refはそのような用途に非常に適しており、変更可能な変数とは見なされません (そうでないため)。

于 2012-06-08T10:49:59.383 に答える
3

今では、そのような制約がない F# 4 をそのまま使用できます。

于 2016-04-27T05:05:56.027 に答える