UPDATE throughout this answer:
This is not Proc equivalent notation but you can write in F#:
let mean =
let t = total << id
let n = total << List.map (constant 1)
listFork t (/) n
I explain this in what follows.
I prefer J's fork conjunction which inspires the fork
below - but note it is not quite the same - to do all the work in F# that, as I understand it, that Arrows would do, but this is guided by the Arrow implementation in the above mentioned F# library rather than looking at the Haskell usage (this is separate to Kliesli Arrows, I use those too, you create an infix operator for those). Anyway in 1 line:
let fork g h f a = h (g a) (f a)
- used in conjunction with
id
, fst
, snd
, flip
, tuple2
, uncurry
etc. as needed
Anyway the way I would use fork
to create the average as described in the question:
let average values = fork List.sum (/) List.length values
or
let average = fork List.sum (/) List.length
The running average version, using list here. (fork
can be raised to different collections, here it is listFork
(if extended to list collection could then be List.fork
) so as common to F# unlike Haskell, need dedicated seqFork
, arrayFork
combinators etc.)
UPDATE: Made as similar in style to Proc as possible:
let total: int list -> float list = List.scan (+) 0 >>List.tail >> List.map float
let constant i = fun _ -> i
let fork g h f a = h (g a) (f a)
let inline listFork g h f = fork g (List.map2 h) f
let mean =
let t = total << id
let n = total << List.map (constant 1)
listFork t (/) n
mean [0;10;7;8];;
>
val total : (int list -> float list)
val constant : i:'a -> 'b -> 'a
val fork : g:('a -> 'b) -> h:('b -> 'c -> 'd) -> f:('a -> 'c) -> a:'a -> 'd
val inline listFork :
g:('a -> 'b list) ->
h:('b -> 'c -> 'd) -> f:('a -> 'c list) -> ('a -> 'd list)
val mean : (int list -> float list)
val it : float list = [0.0; 5.0; 5.666666667; 6.25]
It is not Proc notation obviously. Now I have the running version, I don't know whether this answers your "other approaches as well" finishing point...
Final Update:
With listFork
you can make this more point-free with just a 1-liner:
let mean1 = listFork total (/) (List.map (fun _ -> 1) >> total)
What is not clear in the first example linked to in the OP, is that total
is itself an arrow which does the heavy lifting of a fold or scan. That is the real power of Arrows hence their usefulness in FRP, but that is (or was) outside the scope of my usage of fork
- which was more focused on point-free, composition and piping. At least till now, I will consider this further but not here!
proc
notation in F# - but I think you may be able to find some alternative solution. The question really is, what do you want arrows for? Is it to write more pure code, to do some functional reactive programming or something else altogether? – Foah