построение списка целых в ocaml - PullRequest
3 голосов
/ 13 апреля 2011

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

rec myFunc xy создаст список со всеми целыми числами от x до y, включая x и y

Для логики сейчас у меня есть что-то вроде этого:

let rec buildList i n = let x = i+1 in if i <= n then i::(buildList x n)

Но это дает мне ошибку "Выражение имеет тип" список, но ожидалось выражение типа единица.

Я думал, что buildList возвращает список целых чисел, а я как int, поэтому оператор cons будет действительным, но он говорит, что он должен быть пустым?

Почему это происходит и как я могу это исправить?

Ответы [ 5 ]

7 голосов
/ 13 апреля 2011

Если условие истинно, вы возвращаете список i::(buildList x n).Если это не так, что вы возвращаете?

Добавьте else [] в вашу функцию, чтобы вернуть пустой список, когда условие не выполнено.Если у вас нет else, компилятор предполагает, что это else () (отсюда и сообщение об ошибке).

3 голосов
/ 14 апреля 2011

В вашем if отсутствует условие else

Я предлагаю вам использовать хвостовую рекурсивную функцию:

let buildList x y =
  let (x,y) = if x<y then (x,y) else (y,x) in
  let rec aux cpt acc =
      if cpt < x then acc
      else aux (cpt-1) (cpt::acc)
  in aux y []

Сначала убедитесь, что вы правильно упорядочили свои границы (защита от идиотов), а затем составьте список благодаря локальной рекурсивной функции, которая принимает аккумулятор.

1 голос
/ 13 февраля 2014

Две альтернативы, опирающиеся на комплект батарей,

Использование функции развернуть, целью которой является создание списка,

let range ~from:f ~until:u = 
    BatList.unfold f (function | n when n <= u -> Some (n, succ n) | _ -> None)

Использование Enum, позволяющее работать с ленивой структурой данных,

# BatList.of_enum @@ BatEnum.(1--9);;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]
0 голосов
/ 11 декабря 2016
let buildList i n =
 let rec aux acc i =
   if i <= n then
     aux (i::acc) (i+1)
   else (List.rev acc)
 in
 aux [] i

Тест:

# buildList 1 3;;
- : int list = [1; 2; 3]
# buildList 2 1;;
- : int list = []
# buildList 0 250000;;
- : int list =
[0; 1; 2; 3; .... 296; 297; 298; ...]
0 голосов
/ 13 февраля 2014

Мое предложение, это учитывает порядок аргументов.

let rec iota n m = 
  let oper = if n < m then succ else pred  in 
    if n = m then [n] else n :: iota (oper n) m

Редактировать:

Выбор оператора находится внутри рекурсивной части, лучше снаружи это так:

let iota n m = 
  let oper = if n < m then succ else pred  in 
    let rec f1 n m = if n = m then [n] else n :: f1 (oper n) m in
      f1 n m

Вболее 200000 элементов Я получаю переполнение стека (так что мы здесь)

# iota 0 250000;;
Stack overflow during evaluation (looping recursion?).

Todo: хвостовая рекурсия

...