ocaml рекурсивное сопоставление с образцом

Я пытаюсь написать простую рекурсивную функцию, которая просматривает список и возвращает пару целых чисел. Это легко написать на c / c ++ / java, но я новичок в ocaml, поэтому как-то сложно найти решение из-за конфликта типов

должно быть так ..

let rec test p l = ... ;;
val separate : (’a -> bool) -> ’a list -> int * int = <fun>
test (fun x -> x mod 2 = 0) [-3; 5; 2; -6];; 
- : int * int = (2, 2)

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


person REALFREE    schedule 15.06.2010    source источник
comment
Не могли бы вы подробнее рассказать, что должна возвращать эта функция? Что представляет пара целых чисел?   -  person goggin13    schedule 15.06.2010
comment
поэтому он должен возвращать пару целых чисел как (x, y), которая является кортежем в ocaml, единственная проблема, с которой я столкнулся, - это вычисление кортежа ... так что это похоже на то, если элемент списка меньше некоторого числа, тогда (x + 1 , y) else (x, y + 1), поэтому возвращаемое значение будет (x, y), где x - количество элементов, которое больше некоторого числа, а y меньше, чем   -  person REALFREE    schedule 15.06.2010


Ответы (2)


На какое-то время был вдали от OCaml, но я думаю, что это поможет в отношении описания REALFREE в комментарии

let rec test l = 
  match l with 
      [] -> (0,0) 
    | x::xs -> 
        if x > 0 then match (test xs) with (x,y) -> (x+1, y)
        else  match (test xs) with (x,y) -> (x, y+1);;

Вы можете использовать вложенные операторы сопоставления, чтобы извлекать части кортежа для изменения

EDIT: я не знал о синтаксисе Pascal Cuoq, упомянутом в его комментарии ниже, вот такой код, он аккуратнее и немного короче:

let rec test l = 
  match l with 
      [] -> (0,0) 
    | x::xs -> 
    if x > 0 then let (x,y) = test xs in (x+1, y)
    else let (x,y) = test xs in (x, y+1);;

Но принятый ответ все равно намного лучше, особенно с хвостовой рекурсией;).

person goggin13    schedule 15.06.2010
comment
и если вы пишете match .. with .. с одним шаблоном, вы можете вместо этого использовать let: let x, y = test xs in ... - person Pascal Cuoq; 15.06.2010

Одна из проблем заключается в том, что вы возвращаете два разных типа: int для пустого списка или кортеж в противном случае. Это должно быть одно или другое.

Другая проблема заключается в том, что вы пытаетесь добавить 1 к test, но test - это функция, а не значение. Вам нужно вызвать test для чего-то еще, чтобы он вернул значение, но даже в этом случае он должен вернуть кортеж, который вы не можете добавить к целому числу.

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

Я предполагаю, что вы хотите посчитать положительные числа в списке, и в этом случае вы можете написать это так:

let rec test l = 
    match l with [] -> 0
   | x::xs -> if x > 0 then 1 + (test xs)
              else test xs;;

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

let test l =
  let rec test_helper l pos nonpos = 
    match l with [] -> (pos, nonpos)
   | x::xs -> if x > 0 then test_helper xs 1+pos, nonpos
              else test_helper xs pos 1+nonpos
  in test_helper l 0 0;;

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

person danben    schedule 15.06.2010
comment
как я могу изменить его на рекурсивную пересылку? - person REALFREE; 15.06.2010