2014-02-03 4 views
1

Я пишу функцию, которая принимает пару списков, если длина двух списков равна, тогда создайте пару каждого элемента из каждого списка, но моя функция не работает, и компилятор говорит, что есть синтаксическая ошибкаСинтаксическая ошибка OCaml в рекурсивной функции

Может кто-нибудь объяснить, почему в конце с запятой в конце моей функции возникает синтаксическая ошибка?

Это мой код:

let define_tuple a b = 
(a, b);; 

let zip (a, b) = 
if List.length (fst (a, b)) != List.length (fst (a, b)) 
then 
printf_string "lengths of 2 lists need to be equal" 
else 
let rec create_tuples (a, b) = 
if List.length (List.tl (fst (a, b))) = 0 && List.length (List.tl (snd (a, b))) != 0 
then 
[] 
else 
List.append define_tuple (List.hd (fst (a, b))) (List.hd (snd (a, b))) create_tuples (List.tl (fst (a, b)), List.tl (snd (a, b)));; 



zip ([1; 2; 3], [2; 3; 4]);; 
+0

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

+0

В настоящее время я использую Typerex, который находится здесь: http://www.typerex.org/ –

+0

@ TrungBún вы должны использовать emacs + Tuareg, намного лучше –

ответ

2

Есть немало возможных улучшений и ошибок в коде, и я их все перечислить в следующем:

No. 1

Если вы пишете код в файл и попытаться скомпилировать/запустить файл, то вам не нужно ;; в конце концов, для каждой функции.

No. 2

let define_tuple a b = (a, b);;

Вам не нужно определить такую ​​функцию, вместо этого, вы можете напрямую использовать (a, b).

No. 3

let zip (a, b) = 
    if List.length (fst (a, b)) != List.length (fst (a, b)) then 
    printf_string "lengths of 2 lists need to be equal" 
    else 
    let rec create_tuples (a, b) = 
     if List.length (List.tl (fst (a, b))) = 0 && List.length (List.tl (snd (a, b))) != 0 
     then 
    [] 
     else 
    List.append define_tuple (List.hd (fst (a, b))) (List.hd (snd (a, b))) create_tuples (List.tl (fst (a, b)), List.tl (snd (a, b)));; 

3,1

для вашего первого if ... else ..., это не правильно, как if ветви возвращается unit и else ветви возвращается list.

В OCaml, if и else или любая ветка соответствия шаблону должна возвращать тот же тип.

3,2

Из 3.1, я предлагаю вам написать исключение для non-equal lengths случая. Таким образом, вся функция по-прежнему возвращает список, а код более читабельен, и пользователи вашей функции также могут получить возможность «поймать» ваш случай исключения.

3,3

для функции create_tuples,

let rec create_tuples (a, b) = 
     if List.length (List.tl (fst (a, b))) = 0 && List.length (List.tl (snd (a, b))) != 0 
     then 
    [] 
     else 
    List.append define_tuple (List.hd (fst (a, b))) (List.hd (snd (a, b))) create_tuples (List.tl (fst (a, b)), List.tl (snd (a, b)));; 

3.3.1

List.length (List.tl (fst (a, b))) = 0

Вам не нужно использовать fst (a,b), вместо этого, просто a достаточно, потому что а уже известно.

Это то же самое для вашего использования snd.

В принципе вам не нужны fst и snd на всем протяжении вашего кода.

3.3.1.1

Вы должны проверить, является ли a и b «ы длины равны 0 или нет, не tl из них.

3.3.2

Вам также не нужно (a,b) кортеж в качестве параметров для create_tuples, вместо этого, вы можете использовать create_tuples a b. Это лучше, потому что вашему коду не нужно создавать кортеж для пары параметров.

3.3.3

List.append define_tuple (List.hd (fst (a, b))) (List.hd (snd (a, b))) create_tuples (List.tl (fst (a, b)), List.tl (snd (a, b)))

Прежде всего, List.append является добавление одного списка в другой список. В вашем случае вы добавляете элемент в список, поэтому вы должны использовать ::.

Чтобы включить приложение функции, вы должны использовать (), если хотите, чтобы значение приложения функции использовалось.

например, вы должны сделать (define_tuple (List.hd (fst (a, b))) (List.hd (snd (a, b)))):: (create_tuples (List.tl (fst (a, b)), List.tl (snd (a, b)))).

Если учесть предыдущие пункты вместе, вы можете сделать

(List.hd a, List.hd b)::(create_tuples (List.tl a) (List.tl b))

3,4

Вы определили функцию create_tuples, но вы действительно использовать его в коде? Нет.

Таким образом, в конце концов, вы должны сделать

in create_tuples a b

No. 4

Вы должны использовать <> проверить неравенство.


Полный утонченный/исправленный код

exception Non_equal_list_length 

let zip a b = 
    if List.length a <> List.length b then raise Non_equal_list_length 
    else 
    let rec create_tuples a b = 
     if List.length a = 0 && List.length b = 0 then [] 
     else (List.hd a, List.hd b)::(create_tuples (List.tl a) (List.tl b)) 
    in 
    create_tuples a b 

Некоторые другие улучшения:

  • Вы можете использовать шаблон соответствия непосредственно в списках
  • Вы всегда должны принимать хвост -рекурсивная оценка

Окончательный улучшенный код:

exception Non_equal_list_length 

let zip a b = 
    let rec zipping acc = function 
     | [], [] -> List.rev acc 
     | hd1::tl1, hd2::tl2 -> zipping ((hd1,hd2)::acc) (tl1,tl2) 
     | _ -> raise Non_equal_list_length 
    in 
    zipping [] (a,b) 
+0

Такой отличный ответ! Я новичок в Ocaml, и я так многому научился! Спасибо! –

+0

@ TrungBún вы можете пометить мой ответ как исправленный, так что я могу заработать счет? –

+1

@ TrungBún также вы должны купить книгу реального мира ocaml или бесплатно скачать на своем веб-сайте: https://realworldocaml.org/ –

1

Выражения let a = b действует только на самом верхнем уровне модуля, в котором он определяет имена экспортируемых из модуля. В любом другом месте это выражение используется для введения локальной переменной (или переменных) и имеет вид let a = b in c. Вам не хватает ключевого слова in и выражение, в котором вы хотите использовать локальную переменную create_tuples.

(Есть некоторые другие ошибки, которые вы найдете, когда вы получаете синтаксис в порядке.)

Update

Вот простой пример функции, которая использует вспомогательную функцию, объявленную с let a = b in c:

let myrev l = 
    let rec irev sofar = function 
    | [] -> sofar 
    | hd :: tl -> irev (hd :: sofar) tl 
    in 
    irev [] l 
Смежные вопросы