2017-01-29 11 views
0

Я должен написать функцию, которая берет список и разбивает его на 2 списка. Первый список будет содержать элементы в нечетном положении, а 2-й список - в четном положении. Вот моя попытка, которая дает мне следующее предупреждение:Разделить список на 2 списка нечетных и четных позиций - SML?

Внимание: тип VARS не обобщен из ограничения значения инстанцируются для фиктивных типов (X1, X2, ...)

Как улучшить это?

fun splt (lst: int list) = 
    let 
     fun splt2 (lst: int list, count: int, lst1: int list, lst2: int list) = 
      if null lst 
      then [] 
      else if (count mod 2 = 0) 
       then splt2 (tl lst, count+1, hd lst::lst1, lst2) 
       else splt2 (tl lst, count+1, lst1, hd lst::lst2) 
    in 
     splt2 (lst,1,[],[]) 
    end 

Вот 2-я правильная реализация, которую я нашел, но меня в основном интересует фиксация 1-го! I want to split a list into a tupple of odd and even elements

fun split [] = ([], []) 
| split [x] = ([x], []) 
| split (x1::x2::xs) = 
      let 
      val (ys, zs) = split xs 
      in 
      ((x1::ys), (x2::zs)) 
      end; 

UPDATE: Улучшение просто заменить

if null lst then 
     [] 

с этим:

if null lst then 
    [lst1]@[lst2] 
+0

Я видел ваши вопросы по поводу последние пару дней. SO не предназначен, чтобы научить вас всему для вашего класса. Вам придется приложить больше усилий. – naomik

+0

@naomik, но я люблю SO. Я узнаю здесь больше, чем в своем классе. Пожалуйста, поделитесь своими знаниями. Я уверен, что многие из них выиграют от этих небольших проблем. –

ответ

1

Чтобы помочь вам по ошибке вы сталкиваетесь вам нужно посмотреть на тип от функции, которую вы указали

val splt = fn : int list -> 'a list 

и спросите себя, что делает «список»?

- val foo = "foo"::(splt[1,2,3,4,5]); 
val foo = ["foo"] : string list 
- val bar = 52::splt[1,2,3,4,5]; 
val bar = [52] : int list 

он может хранить что угодно, но компилятор не может сказать сам.

+0

OMG! Я понял. Спасибо за подсказку :) Я просто должен был вернуть [lst1] @ [lst2] вместо []. –

+0

@ Квадратный корень Я бы просто просил, чтобы вы тщательно проверили остальную часть своего ответа :) – matt

+0

Это правильно. Я просто проверил это :) –

2

Вот некоторые отзывы для вашего кода:

  • Дайте функцию собственное имя, как split или partition. Коннотации, что у меня есть для этих имен: Расщепление (или взрываются) берет что-то и возвращает один список вспомогательных компонентов (например, строка → список символ), в то время как разделение принимает список чего-то и делится на два на основе предиката (например, List.partition), но они действительно не установлены в камне.
  • Составьте имена переменных, которые не являются lst, так как это всего лишь аббревиатура типа - безусловно избыточная, когда даже тип существует. Для общих методов хорошие имена могут быть труднодоступными. Много кода ML использует такие вещи, как xs, чтобы подразумевать общую форму множественного числа.
  • Ditch аннотации типа; вы получите полиморфную функцию, которая читает более легко:

    fun split input = 
        let 
         fun split' (xys, count, xs, ys) = ... 
        in 
         split' (input, 1, [], []) 
        end 
    
  • Но на самом деле, версия, которую вы нашли в Интернете имеет ряд преимуществ: соответствие шаблону гарантирует, что ваши списки имеют правильную форму, прежде чем тело функции срабатывают, что минимизирует ошибки времени выполнения. Функции hd и tl нет.

  • Вы можете немного улучшить порядок корпусов; то есть сначала перечислите наиболее распространенный случай.Скобки вокруг x::xs и y::ys не нужны. Кроме того, два других случая (одного или нуля элементов) могут быть объединены для краткости, но это не имеет большого значения.

    fun split (x1::x2::xs) = 
        let 
         val (ys, zs) = split xs 
        in 
         (x1::ys, x2::zs) 
        end 
        | split rest = (rest, []) 
    
  • Вы также можете использовать случай-в вместо вставленного конца:

    fun split (x1::x2::xs) = 
        (case split xs of 
          (ys, zs) => (x1::ys, x2::zs)) 
        | split rest = (rest, []) 
    
  • Наконец, вы можете сделать эту функцию хвостовой рекурсии:

    fun split xys = 
        let fun split' (x1::x2::xs, ys, zs) = split' (xs, x1::ys, x2::zs) 
          | split' (rest, ys, zs) = (rev (rest @ ys), rev zs) 
        in 
         split' (xys, [], []) 
        end