Your code looks quite good to me - most of it deals with some loading and initialization, so there isn't much you could do to simplify that part. Alternatively to Array.map2
, you could use Seq.zip
combined with Seq.map
- the zip
function combines two sequences into a single one that contains pairs of elements with matching indices:
let lemmas = Seq.zip words tags
|> Seq.map (fun (x, y) -> lemmatizer.lookup (x, y))
Since lookup
function takes a tuple that you got as an argument, you could write:
// standard syntax using the pipelining operator
let lemmas = Seq.zip words tags |> Seq.map lemmatizer.lookup
// .. an alternative syntax doing exactly the same thing
let lemmas = (words, tags) ||> Seq.zip |> Seq.map lemmatizer.lookup
The ||>
operator used in the second version takes a tuple containing two values and passes them to the function on the right side as two arguments, meaning that (a, b) ||> f
means f a b
. The |>
operator takes only a single value on the left, so (a, b) |> f
would mean f (a, b)
(which would work if the function f
expected tuple instead of two, space separated, parameters).
If you need lemmas
to be an array at the end, you'll need to add Array.ofSeq
to the end of the processing pipeline (all Seq
functions work with sequences, which correspond to IEnumerable<T>
)
One more alternative is to use sequence expressions (you can use [| .. |]
to construct an array directly if that's what you need):
let lemmas = [| for wt in Seq.zip words tags do // wt is tuple (string * string)
yield lemmatizer.lookup wt |]
Whether to use sequence expressions or not - that's just a personal preference. The first option seems to be more succinct in this case, but sequence expressions may be more readable for people less familiar with things like partial function application (in the shorter version using Seq.map
)