Более короткий способ перенацеливания элементов кортежа в SML

#sml #smlnj

#sml #smlnj

Вопрос:

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

 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 .

Ответ №1:

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

 fun RecursiveCall p (q, r, s) = RecursiveCall p (returnResult (p, q, s))
  

Комментарии:

1. Нет, в целом это не так. Я не прошу о какой-либо конкретной проблеме, только если в SML / NJ существует общее предложение.

Ответ №2:

 (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)
  

в качестве альтернативы let-in-end.

Вы могли бы создавать функции и использовать returnResult recursiveCall 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 частично применяется к одному из его четырех аргументов, что делает его функцией, которая принимает три аргумента curried. uncurry3 (recursiveCall p) таким образом, становится функцией, которая принимает 3-кортеж, что является точным результатом returnResult p q s .

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

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

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

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

Комментарии:

1. Ну, поскольку некоторые предварительно вычисленные структуры существуют и находятся в структурах данных ra, rb, rc, я думал о том, чтобы снова воспользоваться ими, а не повторно вычислять, поскольку они действительно могут найти применение в другой функции.