Clean и Array Slice

Feb 03, 2019 15:46


Непонятно, почему в Clean, где есть изменяемые массивы, построенные на unique types, нет такой вещи, как ARRAY_SLICE в терминах SML или std::slice в терминах Rust. Конечно, при этом придётся немного разрушить uniqueness, но зато ряд алгоритмов из семейства "разделяй и властвуй" станет намного проще. Собственно, ниже определение ArraySlice и две основные функции
:: ArraySlice a = ArraySlice .(.{!a}, Int, Int)

split :: !*(ArraySlice a) !Int -> *(*(ArraySlice a), *(ArraySlice a))
split (ArraySlice (arr, i, sz)) j
    | j >= sz = abort "Attempt to make slice after end"
    | j <= i  = abort "Attempt to make slice before beginning"
    | otherwise = (ArraySlice (arr`, i, j), ArraySlice (arr``, i + j, sz - j))
        where (arr`, arr``) = unsafeArrayDup arr
              // Helper function, which overcomes uniqueness restrictions
              unsafeArrayDup :: u:{!a} -> u:(u:{!a}, u:{!a})
              unsafeArrayDup x =
                  code
                  {
                      push_a 0
                      push_a 1
                      update_a 1 2
                      updatepop_a 0 1
                  }

merge` :: !*(ArraySlice a) !*(ArraySlice a) -> *(ArraySlice a)
merge` (ArraySlice (arr, i, sz)) (ArraySlice (arr`, i`, sz`))
    | (size arr) <> (size arr`) = abort "Different arrays" // FIX проверка должна быть лучше
    | (i + sz) <> i`            = abort "Slices are not adjacent"
    | otherwise = ArraySlice (arr, i, sz + sz`)

Функция split разделяет один на два соседних, при этом сам массив наследуется, а merge склеивает два соседних среза. В функции merge не хватает проверки, что arr и arr` - это один и тот же массив, но её можно дописать, подшаманив с ABC машиной.

Написать instance Array ArraySlice a тривиально и занудно. Единственный сложный момент - как отсчитывать индексы: от начала массива или от начала среза.

Далее, имея функцию swap, которую я написал ниже, мы легко можем написать любимый quicksort на срезах.
Previous post
Up