## Thursday, June 10, 2010

### Surfing the Tuple Pipeline

A situation came up where I needed to pipeline a tuple created by a List.partition to two different functions and then return the result as a tuple. I decided to create a some pipeline operators for tuples. On reading Real-World Functional Programming (RWFP), however, I found a solution involving a map function and the standard forward pipe operator (|>). It turns out that I like the RWFP approach better than mine, but the special tuple pipelines I came up with are not without interest, so I decided to post them here. (As always, presented "as-is" and without warranty or implied fitness of any kind; use at your own risk.)

First, here are a couple of map functions adapted from the example on page 148 of RWFP. Please excuse my quick-and-dirty naming conventions. For clarity in this example only, I named the map functions “map12” for “map one function onto a two-tuple” and “map22” for “map two functions onto a two-tuple.”

`let map12 f (a,b) = ((f a),(f b))`
`let map22 f g (a,b) = ((f a),(g b))`

Here are my pipeline operators. The (||>) works like (|> map12), while the second two act like (map22 |>). (||>>) takes tupled functions, while (||>>> takes curried functions.

`let (||>) (a,b) f = ((f a),(f b))`
`let (||>>) (a,b) (f,g) = ((f a),(g b))`
`let (||>>>) (a,b) f g = ((f a),(g b))`

And here is a small test. Each example partitions a list of integers into lists of even and odd integers, creates a list of the halves of the even integers and the doubles of the odd integers, then sums the two lists and returns the sums as a tuple. (This is probably a useless task, but it demonstrates the operation without as much fluff as the real-world example I was working on.)

`let isEven n = (n%2)=0`
`let doubleIt n = n*2`
`let halveIt n = n/2`
` `
`let nums = [0..19]`
` `
`let a = `
`  List.partition isEven nums`
`  |> map22 (List.map halveIt) (List.map doubleIt)`
`  |> map12 List.sum`
` `
`let b = `
`  List.partition isEven nums`
`  ||>> (List.map halveIt, List.map doubleIt)`
`  ||> List.sum`
` `
`let c = `
`  List.partition isEven nums`
`  ||>>> (List.map halveIt) <| (List.map doubleIt)`
`  ||> List.sum`

All are fairly readable; in general, I prefer the RWFP approach because I feel it better extends the language than does a custom operator. But it would probably be possible to find design situations where any of the three was appropriate.