Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using a sequence on partial application

Tags:

f#

I have a sequence of value that I would like to apply to a function partially :

let f a b c d e= a+b+c+d+e

let items = [1,2,3,4,5]

let result = applyPartially f items

Assert.Equal(15, result)

I am looking after the applyPartially function. I have tried writing recursive functions like this :

let rec applyPartially f items =
| [] -> f
| [x] -> f x
| head :: tail -> applyPartially (f head) tail

The problem I have encountered is that the f type is at the beginning of my iteration 'a->'b->'c->'d->'e, and for every loop it should consume an order.

'a->'b->'c->'d->'e 
'b->'c->'d->'e 
'c->'d->'e 
'd->'e

That means that the lower interface I can think of would be 'd->'e. How could I hide the complexity of my function so that only 'd->'e is shown in the recursive function?

like image 241
Yoann Avatar asked Sep 23 '26 12:09

Yoann


1 Answers

The F# type system does not have a nice way of working with ordinary functions in a way you are suggesting - to do this, you'd need to make sure that the length of the list matches the number of arguments of the function, which is not possible with ordinary lists and functions.

However, you can model this nicely using a discriminated union. You can define a partial function, which has either completed, or needs one more input:

type PartialFunction<'T, 'R> = 
  | Completed of 'R
  | NeedsMore of ('T -> PartialFunction<'T, 'R>)

Your function f can now be written (with a slightly ugly syntax) as a PartialFunction<int, int> that keeps taking 5 inputs and then returns the result:

let f = 
  NeedsMore(fun a -> NeedsMore(fun b ->
    NeedsMore(fun c -> NeedsMore(fun d ->
      NeedsMore(fun e -> Completed(a+b+c+d+e))))))

Now you can implement applyPartially by deconstructing the list of arguments and applying them one by one to the partial function until you get the result:

let rec applyPartially f items =
  match f, items with
  | Completed r, _ -> r
  | NeedsMore f, head::tail -> applyPartially (f head) tail
  | NeedsMore _, _ -> failwith "Insufficient number of arguments"

The following now returns 15 as expected:

applyPartially f [1;2;3;4;5]
like image 72
Tomas Petricek Avatar answered Sep 26 '26 19:09

Tomas Petricek



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!