I am new to F# and functional programming in general. Given a scenario where you want to iterate over a sequence or list of strings, and map that to a new list of a different type, WITH an accumulator, what is the correct functional approach? I can achieve this in F# using mutable variables, but I am struggling to find the right function to use for this. It's similar to map I think, but there is the notion of state.
In other words, I want to transform a list of strings into a list of win forms radio buttons, but for each new button I want to add 20 to the previous y coordinate. Something like:
new RadioButton(Text=str,Location=new Point(20,y+20),Width=350)
You can use List.fold
:
open System.Drawing
open System.Windows.Forms
let getButtons () =
let strings = ["a"; "b"; "c"]
let (_, pointsRev) = List.fold (fun (offset, l) s -> (offset+20, (new RadioButton(Text=s, Location = new Point(20, offset), Width = 350))::l)) (0, []) strings
pointsRev |> List.rev
The state is a pair containing the current offset and the current output list. The output list is built in reverse order so has to be reversed at the end.
You could also use Seq.map2:
let points = Seq.map2 (fun offset s -> new RadioButton(Text=s, Location = new Point(20, offset)) (Seq.initInfinite ((*)20)) strings |> List.ofSeq
You can access and change variable by reference alike
let x = ref 0
x := !x + 5
new Point(20,!x+20)
and you can use such variable inside closures.
Also you can use mapi
: http://msdn.microsoft.com/en-us/library/ee353425.aspx
And add value to y based on i
alike new Point(20,i*20+20)
Using List.fold
is a great idea (see the accepted answer).
Being an F# beginner myself, I split the fold out into a separate function and renamed some variables so I could understand things more clearly. This seems to work:
let buttonNames = ["Button1Name"; "Button2Name"]
let createRadioButton (offset, radioButtons) name =
let newRadioButton = new RadioButton(Text=name, Location=new Point(20, offset), Width=350)
(offset + 20, newRadioButton::radioButtons)
let (_, buttonsReversed) = buttonNames |> List.fold createRadioButton (0, [])
let buttons = buttonsReversed |> List.rev
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