Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting OCaml to F#: can F# map a list of values directly to a list of identifiers?

Tags:

f#

ocaml

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.

like image 802
Guy Coder Avatar asked Dec 13 '22 02:12

Guy Coder


2 Answers

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"
like image 92
Tomas Petricek Avatar answered Dec 14 '22 16:12

Tomas Petricek


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")
like image 39
Daniel Avatar answered Dec 14 '22 16:12

Daniel