views:

502

answers:

3

Ok. I'm not asking for a plssendcodezkthx. But I am somewhat new to FP and I'm trying to figure out how to do this, because I know the code I have won't accomplish what I'd like to achieve. So all arguments about optimization aside, here is my code Then I'll explain.

let moveBoids boids =
    boids |> List.map (fun(boid) -> 
        let others = List.filter (fun(b) -> b.Id <> boid.Id) boids
        let positions = others |> List.map(fun(b2) -> b2.Position)
        let velocities = others |> List.map(fun(b3) -> b3.Velocity)
        let c = centerWithFlock (boid, positions)
        let d = distanceFromFlock (boid, positions)
        let v = matchVelocityWithFlock (boid, velocities) 
        let v2 = List.fold_right (addVector) [c; d; v] {X=0.; Y=0.; Z=0.}
        let p = addVector boid.Position v2
        {boid with Position=p; Velocity=v2})

I'm trying to map my list of boids to a new list of boids. Sounds easy, except I'm pretty sure if I run this, each boid will only change according to the original list, not to the list as each boid updates itself. How the hell can I do that using a map style call? Should I not even be using a map style call? I know my function is closed over my boids list, so how can I pass the updated list to the next call?

Word.

+2  A: 

I think this may fix it..

let rec foo boids newboids =
    match boids with
    | h :: t -> 
        let others = List.filter (fun(b) -> b.Id <> h.Id) newboids
        let positions = others |> List.map(fun(b2) -> b2.Position)
        let velocities = others |> List.map(fun(b3) -> b3.Velocity)
        let c = centerWithFlock (h, positions)
        let d = distanceFromFlock (h, positions)
        let v = matchVelocityWithFlock (h, velocities) 
        let v2 = List.fold_right (addVector) [c; d; v] {X=0.; Y=0.; Z=0.}
        let p = addVector h.Position v2
        let list = [{h with Position=p; Velocity=v2}] @ others
        foo t list
    | [] -> newboids
Nicholas Mancuso
+2  A: 

Yeah, a map does not seems too good for this... you can do it with a fold (where you accumulate the 'news' as you process the 'olds' and compute 'others' as 'news' + non-me 'olds') or you could covert to an array and use a loop to in-place update (and then convert back to a list when done if needed).

Brian
+2  A: 

Hi Nicholas,

that's an interesting problem - the solution you posted looks good, but I was just wondering (aside question) why do you need to take into account previous changes during the processing? Even with this behavior, the first boid in the list will not reflect changes done later in the processing...

Does it make a big difference whether the calculation uses the updated state instead of the original?

Thanks, T.

Tomas Petricek
the head of "list" is the updated boid for each iteration, no? So this would reflection that? I'm trying to doing the "Boids" simulation in F# and WPF. All three are new to me, and it sounded like fun. But I would imagine if each boid only remapped itself to old data, instead of as its updated...
Nicholas Mancuso
then it wouldn't have proper flocking emerge.
Nicholas Mancuso
Hmm, it can probably make a difference, but I'm still not completely sure. It would be interesting to try that after you'll have the example running!
Tomas Petricek