I have a function taking a list as argument and simply mapping this list, so returning a list of the same length. So I hoped to use pattern matching in the assignment like this:
let [s1;s2] = getServices [typeof<web.I18n>;typeof<DB.DBClient>]
But this gets a warning:
Incomplete pattern matches on this expression. For example, the value '[_;_;_]' may indicate a case not covered by the pattern(s)
I understand the warning, but wondered if there was a way to achieve what I want without a warning.
I’m going assume
getServices looks something like
let getServices xs = xs |> List.map getService
As far as the type signature of
getServices, it takes a list and returns a list, and the types don’t indicate in any way that the lists have to be the same length. There isn’t really a way in F# to say that a
list has a known length. So you’ve got some options: you could just do it the manual/boring way:
let s1 = getService typeof<web.I18n>
let s2 = getService typeof<DB.DBClient>
let s1, s2 = getService typeof<web.I18n>, getService typeof<DB.DBClient>
You could just “bypass” the warning by not using pattern matching
let s1, s2 =
let services = getServices [typeof<web.I18n>; typeof<DB.DBClient>]
in services, services
If you don’t mind adding some extra helper code, oftentimes when you find yourself wanting to have a list of a fixed length, tuples are the right tool to reach for. Unfortunately, some of the functionality around tuples isn’t built-up the same as for lists. In my company’s codebase, we have some extra helper modules for tuples, e.g.,
module Tuple2 =
let map fn (x1, x2) = (fn x1, fn x2)
which gets a fair bit of use. Here, you could do
let (s1, s2) = Tuple2.map getService (typeof<web.I18n>, typeof<DB.DBClient>)
Thanks for your answer!
Here is the definition of
let getServices (services: System.Type list) =
let ctx:WebSharper.Web.Context = WebSharper.Web.Remoting.GetContext()
let httpContext:Microsoft.AspNetCore.Http.HttpContext = unbox (ctx.Environment.["WebSharper.AspNetCore.HttpContext"])
let serviceProvider= httpContext.RequestServices
|> List.map (fun t -> unbox (serviceProvider.GetService(typeof<'T>)))
I wanted to avoid calling getService multiple times as the first assignments would be repeated (or they would have to be passed as argument, but at that time the added value of the helper is diminished).
I hadn’t thought of the “bypass”, good idea!