Более короткий способ ретаргетинга элементов кортежа в SML - PullRequest
0 голосов
/ 11 апреля 2019

В настоящее время я использую что-то подобное в одной из своих функций: (все переменные используются с более сложными функциями, но для того, что я буду просить, это не имеет значения, и я упрощаю)

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

Как я могу написать это более коротким и (возможно) более приятным способом? То есть, как я могу извлечь элементы кортежа, которые были возвращены из функции, и передать их в качестве аргументов другого кортежа?

Примечание: Можно также написать просто RecursiveCall (p, #1 (returnResult (p, q, s)) , #2 (returnResult (p, q, s)), #3 (returnResult (p, q, s))), но (возможно) это в некоторых случаях приведет к тому, что одна и та же вещь будет запущена три раза, то есть returnResult.

Ответы [ 2 ]

1 голос
/ 13 апреля 2019

Очень сложно сказать что-либо общее без знания вашей реальной проблемы, но вы можете сгруппировать последние три элемента кортежа (похоже, что они единое целое), как

fun RecursiveCall p (q, r, s) = RecursiveCall p (returnResult (p, q, s))
0 голосов
/ 12 апреля 2019
(p, #1 (returnResult (p, q, s)),
    #2 (returnResult (p, q, s)),
    #3 (returnResult (p, q, s))) 

это [...] приведет к тому, что одна и та же вещь будет запущена три раза

Да, все верно. И это также более многословно, чем ваше первоначальное предложение.

Вы также можете написать, например,

case returnResult (p, q, s) of
  (ra, rb, rc) => recursiveCall (p, ra, rb, rc)

как альтернатива пустому концу.

Вы можете сделать returnResult и recursiveCall curry функциями и использовать 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)

Здесь recursiveCall p частично применяется к одному из четырех аргументов, что делает его функцией, принимающей три карри аргумента. Таким образом, uncurry3 (recursiveCall p) становится функцией, которая принимает 3-кортеж, что является точным результатом returnResult p q s.

Этот метод опирается на порядок аргументов, удобно сочетающихся друг с другом.

Но я думаю, что это признак returnResult возврата слишком многих вещей.

В идеале функции возвращают одну вещь, которую их имя предполагает, что она вычисляет.

Возможно, некоторые из вычислений, которые выполняет returnResult, можно разделить на несколько функций, или, может быть, они действительно едины и должны быть заключены в общий тип данных, или, возможно, p, q и s лучше передавать как неявные аргументы читателя / монады состояния. У меня нет хорошего примера того, как выглядит последняя вещь в ML, но я также не могу сказать, что требует ситуация, так как код является гипотетическим.

...