For simplicity, I would say you probably want this:
fun listAdd : (int * int) list -> int list
Now I would simply define this as an abstraction of the unzip function:
fun listAdd ls : case ls of [] => 0 | (x,y) :: ls' => (x + y) + (listAdd ls')
I think it makes no sense to take two separate lists. Just grab the list that contains the product ints. If you need to build this, you can call the zip function:
fun zip xs ys : case xs, ys of [], [] => [] | xs, _ => [] | _, ys => [] | x::xs', y::ys' => (x,y) :: (zip xs' ys')
In general, if you really wanted this, you can write a much more abstract function that has a common type:
fun absProdList : ((`a * `b) -> `c) -> (`a * `b) list -> `c list
This function is simple:
fun absProdList f ls = case l of [] => [] | (x,y) :: ls' => (f (x,y)) :: (absProdList f ls')
This function is a supertype of the addList
function addList
. Just define an anonymous function to recreate addList
as:
fun addList' ls = absProdList (fn (x,y) => x + y) ls
As you can see, the definition of generic function types makes specific calls for functions that are a substitute for types for the general, much simpler and more elegant, with the appropriate combination: Currying, Higher-Order, and anonymous functions.