nicolas
nicolas

Reputation: 9835

function merging / combinator in fsharp

I have a list of functions accepting the same type as an input, different types as output

 [ f_i :  Mytype -> res:Sometype_i ] 

Which operation can merge them into one function of the following type ?

 f : Mytype -> \Product_i Mytype_i

Identically, if I have a list of functions returning the same type

 [ f_i : Mytype_i -> res:Sometype ] 

Which operation can merge them into one function of the following type ?

 f : \Product_i Mytype_i ->  Mytype list

It would be some canonical "preCombinator" or "postCombinator". (I imagine it has a name in FP..)

Upvotes: 1

Views: 497

Answers (2)

John Palmer
John Palmer

Reputation: 25526

An alternative to Tomas' solution for the second problem with the added bonus of returning the functions in the same order as they were initially

let funcs =
  [ (fun n -> n + 1)
    (fun n -> n * 2) ]

let merged = fun input -> funcs |> List.map (fun f -> f input)

Upvotes: 3

Tomas Petricek
Tomas Petricek

Reputation: 243126

The answer to your first question is that you cannot do that in general. A list is a data structure with dynamic length, but the length of the resulting tuple has to be known statically at compile time. (You could construct the resulting tuple using reflection and use it as obj, but that's not really useful.)

In the second case, you want to turn a list of functions into a function returning list, which can be done (both have dynamic length). You can write something like:

let funcs =
  [ (fun n -> n + 1)
    (fun n -> n * 2) ]

let merged =
  funcs |> List.fold (fun agg f ->
    fun inp -> (f inp)::(agg inp)) (fun _ -> [])

The primitive operation (passed to fold) is a function that takes a function of type TInp -> TOut list and a function TInp -> TOut and combines them into a function returning a longer list. So you could also write:

// val addResult : ('a -> 'b list) -> ('a -> 'b) -> 'a -> 'b list  
let addResult agg f inp = (f inp)::(agg inp)

// val merge : ('a -> 'b) list -> ('a -> 'b list)
let merge funcs = funcs |> List.fold addResult (fun _ -> [])

Upvotes: 3

Related Questions