0

Currently, I use something like this in one of my functions: (all variables are used with more complex functions, but for what I will be asking it doesn't matter and I simplify)

fun RecursiveCall (p, q, r, s) =
  let
    val (ra, rb, rc) = returnResult (p, q, s)
  in
    RecursiveCall (p, ra, rb, rc)
  end

How can I write this in a shorter and (perhaps) nicer way? Meaning, how can I extract the elements of a tuple that was returned from a function and pass these as arguments of another tuple?

Note: One could also write simply RecursiveCall (p, #1 (returnResult (p, q, s)) , #2 (returnResult (p, q, s)), #3 (returnResult (p, q, s))) but (probably) this would in some circumstances cause the same thing to run three times, i.e. returnResult.

2 Answers2

1

It's very difficult to say anything general without knowledge about your actual problem, but you could group the last three elements of the tuple together (it looks like they are a unit), like

fun RecursiveCall p (q, r, s) = RecursiveCall p (returnResult (p, q, s))
molbdnilo
  • 64,751
  • 3
  • 43
  • 82
  • No, they are not in general. I am not asking for any specific problem, only if a general proposal exists in SML/NJ. –  Apr 23 '19 at 17:21
0
(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.

Community
  • 1
  • 1
sshine
  • 15,635
  • 1
  • 41
  • 66
  • Well, since some pre-computed structures do exist and are in the ra, rb, rc data structures, I was thinking of taking advantage of them again, not re-computing, since they actually could find a use further down in another function. –  Apr 23 '19 at 17:24