(p, #1 (returnResult (p, q, s)),
#2 (returnResult (p, q, s)),
#3 (returnResult (p, q, s)))
this would [...] cause the same thing to run three times
Yes, that's right. And it's also more verbose than your original proposal.
You could also write e.g.
case returnResult (p, q, s) of
(ra, rb, rc) => recursiveCall (p, ra, rb, rc)
as an alternative to let-in-end.
You could make returnResult
and recursiveCall
curried functions and use uncurry3
:
fun curry3 f x y z = f (x, y, z)
fun uncurry3 f (x, y, z) = f x y z
fun returnResult p q s = (p + 1, q + 2, s + 3)
fun recursiveCall p q r s =
uncurry3 (recursiveCall p) (returnResult p q s)
Here, recursiveCall p
is partially applied to one of its four arguments, making it a function that accepts three curried arguments. uncurry3 (recursiveCall p)
thus becomes a function that accepts a 3-tuple, which is the precise result of returnResult p q s
.
This method relies on the order of arguments conveniently fitting together.
But I think this is a symptom of returnResult
returning too many things.
Ideally functions return the one thing their name suggests that it computes.
Perhaps some of the computations that returnResult
does can be split into multiple functions, or perhaps they're really one thing and should be wrapped in a common data type, or perhaps p
, q
and s
are better passed as implicit arguments of a reader/state monad. I don't have a good example of how the last thing looks in ML at hand, but I also can't say what the situation warrants, since the code is hypothetical.