2013-07-24 2 views
2

Я новичок в SML, и я пытаюсь получить индекс элемента в списке. Я знаю, что использование List.nth даст мне значение элемента в позиции индекса, но я хочу значение индекса. Там может быть встроенная функция, о которой я не знаю. В моем случае список не будет содержать дубликатов, поэтому, если элемент находится в списке, я получаю индекс, если он не возвращает ~ 1. Вот код, который у меня есть. Это работает, но я не думаю, что это очень чистый:SML: получить индекс элемента в списке

val L=[1,2,3,4,5]; 
val m=length L-1; 
fun Index(item, m, L)=if m<0 then ~1 else 
    if List.nth(L, m)=item then m else Index(item,m-1,L); 
+1

В чем ваш вопрос? Я считаю, что нет стандартной функции, которая делает это явно, по крайней мере, в структуре списка. Что касается очистки кода, я бы предложил 1) использовать опцию или исключение вместо возврата '~ 1', 2) скрыть параметр' m', обернув функцию во внешней функции, 3) использовать сопоставление шаблонов на 'm 'для устранения одного условного (' if m <0 ... ') – waldrumpus

+0

Спасибо за советы. Вопрос был действительно: «Каков наилучший способ сделать это?». Было бы неплохо передать m в функцию, так как она в любом случае зависит от длины L, но, как я уже сказал, я новичок в SML и не знаю, как совместить эти два. Причина для кода: У меня есть два списка разных типов, которые связаны между собой. Обновление элемента в списке 1 требует обновления элемента в той же позиции в списке два. Я считаю, что структура List может предоставить что-то вроде этого «zip», но сейчас это работает. –

ответ

5

Выработать на мой предыдущий комментарий, я предлагаю некоторые изменения для реализации, которая подходит лучше в ML идиомы:

fun index(item, xs) = 
    let 
    fun index'(m, nil) = NONE 
     | index'(m, x::xr) = if x = item then SOME m else index'(m + 1, xr) 
    in 
    index'(0, xs) 
    end 

отдельные изменения:

  • Have index возвращают значение типа int option. NONE означает, что элемента нет в списке, SOME i означает, что он есть в списке, а индекс его первого появления - i. Таким образом, не нужно использовать специальные значения (~1), и предполагаемое использование функции может быть выведено из его типа.
  • Скрыть параметр m, переименовав функцию в index' и обернув ее внешней функцией index, которая называет ее соответствующими аргументами. Символ prime (`) часто указывает вспомогательные значения.
  • Используйте соответствующий шаблон в списке, чтобы перейти к отдельным элементам, устраняя необходимость в List.nth.

Также отметим, что наиболее часто, функции и имена переменных начинаются со строчной буквы (индекс вместо Index), а заглавные буквы используются для конструктора констант (НЕКОТОРЫХ) и тому подобное.

+0

Благодарим вас за подробное объяснение. Я видел эту идиому несколько раз здесь, в SO, и не мог понять цель называть как внутренние, так и внешние функции с тем же именем. Я попытался это сделать, но трудно найти то, что вы не знаете, как оно называется. Еще раз спасибо! :) –

0

Я хотел бы предложить более простую и менее эффективную версию этой функции index. Я согласен с тем, что не желательно использовать исключения, а не int option, и что он не является хвостовым рекурсивным. Но это, безусловно, легче читать и, следовательно, может служить учебным материалом:

fun index (x, []) = raise Subscript 
    | index (x, y::ys) = 
    if x = y then 0 else 1 + index (x, ys) 
Смежные вопросы