I am converting several modules based on OCaml to F# and ran into something like this
let [x; y; z] = map func1 ["a"; "b"; "c"]
where [x; y; z]
is a list of identifiers and
map func1 ["a"; "b"; "c"]
returns a list of functions.
Currently I am binding each value in the list to the identifier separately i.e.
let fList = map func1 ["a"; "b"; "c"]
let x = fList.[0]
let y = fList.[1]
let z = fList.[2]
The use of the identifiers is for a second function i.e.
func2 x y z
I know I can modify func2 to accept a list, but since func2 in reality takes values along with each function for each parameter it would be even more work. i.e.
func2 (x g) (y h) (z i)
I have looked for ways to do this as efficiently as OCaml and came up empty. I searched for unmap, deconstruct, and looked at the methods for List
Can F# map a list of values directly to a list of identifiers?
EDIT
The code I am converting does define a map function in its own library.
EDIT
@OnorioCatenacci It was just something I wrote as an example instead of trying to spend many minutes creating a real working example. The real code has a copyright so I can't use it here without the full disclosure. The point I was trying to make was that I was not assigning constant values to identifiers but functions to identifiers. I only put in map func1 ["a"; "b"; "c"]
to show that the functions were being generated as needed based on some input and not hardcoded. The real code builds logic circuit simulators and the functions returned are different logic circuits; think combinators. It is all part of an automated theorem prover. Tomas and Daniel understood the question and gave correct answers that I verified with the real code.
In other words func1 "a"
will return a function using the parameter "a"
. map func1 ['a", "b", "c"]
will return a list of functions. Since functions are first-class in F#, they can be returned as values.
You can apply map to a list and then use pattern matching to bind the elements to identifiers in F#. The syntax is exactly the same as in the sample you wrote:
let [x; y; z] = List.map func1 ["a"; "b"; "c"]
The only problem with this example is that the F# compiler cannot statically verify that the result will be a list of length 3 and so it gives you a warning saying "Incomplete pattern matches on this expression." In this example, it cannot actually happen, but if you, for example, redefined map
incorrectly so that it would throw away the first element, the code would break.
This is just a warning, so you can ignore it, but if you want to avoid it, you'll need to use match
and throw some custom exception in the unexpected case:
match List.map func1 ["a"; "b"; "c"] with
| [x; y; z] ->
// Continue here if the pattern matching does not fail
func2 (x g) (y h) (z i)
| _ -> invalidOp "Pattern matching failed"
If you want to avoid the "incomplete pattern matches" warning Tomas mentions, you could use tuples--which have fixed length--and define your own map
function:
module Tuple3 =
let map f (a, b, c) = (f a, f b, f c)
let x, y, z = Tuple3.map func1 ("a", "b", "c")
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