Reducing a list of functions for composition

Would I be correct in saying that, if I use List.reduce (>>) on a list of functions, all of the functions in that list must have the same signature?

For example, the (contrived and silly) code below will not compile and I get this error:
All elements of a list must be implicitly convertible to the type of the first element, which here is ‘string’. This element has type ‘int option’.

let toNumeric writtenRating =
 match writtenRating with
 | "zero" -> Some 0
 | "one" -> Some 1
 | "two" -> Some 2
 | "three" -> Some 3
 | "four" -> Some 4
 | "five" -> Some 5
 | _ -> None

let toStars numericalRating =
 match numericalRating with
 | Some n -> String.replicate n "*"
 | None -> "Unrated"

let ratingProcesses =
 [ toNumeric
   toStars ] // Error here.
 |> List.reduce (>>) // Error here.

“four” |> ratingProcesses

However, the code below will compile and runs just fine:


// toNumeric and toStars are as above.
let toRating = toNumeric >> toStars
toRating "four"

val it: string = "****"

Or am I wrong and there is some way to do it?

To compose functions like this you need that all functions have the shape 'a -> 'a. Firstly, to even place them on the same list, they need to have the exact same types aka function signatures. Secondly, to compose them in a chain one after the other. Here’s a simple working example:

let add1 = (+) 1 // int -> int
let mult2 = (*) 2 // int -> int

let operations = [ add1; mult2 ] // (int -> int) list

let addOneThenDouble = List.reduce (>>) operations // int -> int

addOneThenDouble 4 |> printfn "%A" // => 10

@Eliemer You have explained things beautifully. I have easily understood it.

Thanks for your reply Eliemer.

I now understand that there are two problems with my code, namely:

  1. The functions in a List need to have the same signature, and;
  2. The List.reduce (>>) function requires that all of the function inputs and outputs have the same type.

In case anyone reading this is still unsure, examples of the first restriction can be seen in the following code where the last function in each List causes an error:

let intToString (n :int) = n.ToString()
let floatToString (n :float) = n.ToString()
let intToInt (n :int) = n * n
let floatToInt (n :float) = (int n)
let floatToFloat (n :float) = n * n

let functions1 = [ intToString; floatToString ]
let functions2 = [ intToString; intToInt ]
let functions3 = [ floatToInt; intToInt ]
let functions4 = [ floatToInt; floatToFloat ]