I am trying to implement the command pattern to control a robot. I'm using this to explore how to implement the command pattern in F#. Below is my implementation:
type Walle(position, rotate) =
let (x:float,y:float) = position
let rotation = rotate
member this.Move(distance) =
let x2 = distance * sin (System.Math.PI/180.0 * rotation)
let y2 = distance * cos (System.Math.PI/180.0 * rotation)
let newPosition = (x+x2, y+y2)
Walle(newPosition, rotation)
member this.Rotate(angle) =
let newRotation =
let nr = rotation + angle
match nr with
| n when n < 360.0 -> nr
| _ -> nr - 360.0
Walle(position, newRotation)
let Move distance = fun (w:Walle) -> w.Move(distance)
let Rotate degrees = fun (w:Walle) -> w.Rotate(degrees)
let remoteControl (commands:List<Walle->Walle>) robot =
commands |> List.fold(fun w c -> c w)
let testRobot() =
let commands = [Move(10.0);Rotate(90.0);Move(16.0);Rotate(90.0);Move(5.0)]
let init = Walle((0.0,0.0),0.0)
remoteControl commands init
In an effort to come up with a functional solution I chose to make the robot's actions return a new instance of the robot at its new position after each invocation (avoid mutation). I also made the command functions close over the state required to execute the actions.
I was curious whether people feel these were good design decisions when implementing the pattern? Or, if there was any other advice people could give on implementing the pattern?
To avoid going the OO way of combining data with operations in a "type" and representing this combination as "Object", a more functional approach in my POV would be to define data and operations separately in a module as shown below:
module Walle =
type Walle = {Position : float * float; Rotation : float}
let Move distance (w:Walle) =
let x2 = distance * sin (System.Math.PI/180.0 * w.Rotation)
let y2 = distance * cos (System.Math.PI/180.0 * w.Rotation)
{w with Position = (w.Position |> fst) + x2, (w.Position |> snd) + y2 }
let Rotate angle (w:Walle) =
let newRotation =
let nr = w.Rotation + angle
match nr with
| n when n < 360.0 -> nr
| _ -> nr - 360.0
{w with Rotation = newRotation}
Now you can create a new Walle and use |> function to pass that to a series of functions that transform the Walle "data". It is all about data and transformation on that data, no objects :). It may not feel like a command pattern as that is more suited for OO style. You really don't need patterns in FP or do we ?
For the robot example, I would rather just use the imperative style, i.e. changing the states of the robot object. Because a robot object usually has the notion of states and actions to change the states. From the OO design perspective, some kinds of objects are better to be immutable, e.g., String, DateTime in .NET, but a lot of them are not.
Immutable objects of course have advantages. In the persistent version in your question, you can save all the past states of the robot and can easily UnDo
commands on the robot.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With