How to allow a function to accept a generic list of functions?

Viewed 57

How to allow a function to accept a generic list of functions?

I have the code below, but the compiler is rejecting the line where I try to set partiallyAppliedAdds, with the error:

Type mismatch. Expecting a int -> int' given a int -> 'a -> 'b'

type ApplicativeFunctor(fnList: 'a list) =
    member private this.fnList: 'a list = fnList
    member this.ap (apTarget: int list) = ([], this.fnList) ||> List.fold (fun (acc: 'a list) fn -> acc @ (apTarget |> List.map fn))

let add1 a = a + 1
ApplicativeFunctor([add1]).ap([1]) // [2]

let arg1 = [1; 3]
let add x = fun y -> x + y

let partiallyAppliedAdds = ApplicativeFunctor[add].ap(arg1) // Type mismatch. Expecting a int -> int' given a int -> 'a -> 'b'

Is this easily accomplishable in F#, or should I approach this differently?

1 Answers

To fix your version, you do:

type ApplicativeFunctor<'a,'b>(fnList: list<'a -> 'b>) =
    member private _.fnList = fnList
    member this.ap apTarget =
        ([], this.fnList)
        ||> List.fold (fun acc fn -> acc @ List.map fn apTarget)

let add1 a = a + 1
let res1 = ApplicativeFunctor([add1]).ap([1]) (* [2] *)
printfn "%A" res1

let paAdd = ApplicativeFunctor[fun x y -> x + y].ap([1;3])
printfn "%A" paAdd

But the general approach is just

let ap fs xs =
    List.foldBack2 (fun f x state ->
        f x :: state
    ) fs xs []

let add x y z = x + y + z

let xs = [1..3]
let ys = [10;20;30]
let zs = [100;200;300]

let res1 = (ap (ap (List.map add xs) ys) zs)
printfn "%A" res1 (* [111;222;333] *)

(* Custom operators *)
let (<!>) = List.map
let (<*>) = ap

let res2 = add <!> xs <*> ys <*> zs
printfn "%A" res2 (* [111;222;333] *)
Related