Как сделать функцию, которая работает на ленивых списках (она же «Потоки»)? - PullRequest
0 голосов
/ 26 ноября 2018

Я должен сделать функцию, которая принимает два списка отложенных операций и оператор (например, +, -, *, /) и возвращает один отложенный список после операции.Например, [1; 2; 3], [2; 3; 4; 5] + вернет [3; 5; 7; 5].Ленивый список введен как обычный, потому что он более читабелен.

Я представляю, как это может быть, но у меня есть ошибка после функции () ->.Он говорит, что это выражение имеет тип int lazyList * int lazyList * char -> int lazyList, но ожидалось выражение типа int lazyList.

type 'a lazyList = LNil | LCons of 'a * (unit -> 'a lazyList);;

let rec ldzialanie listA listB operator = function
| LCons(xA, xfA), LCons(xB, xfB), '+' -> LCons(xA + xB, function() -> ldzialanie xfA xfB '+')
| LCons(xA, xfA), LCons(xB, xfB), '-' -> LCons(xA - xB, function() -> ldzialanie xfA xfB '-')
| LCons(xA, xfA), LCons(xB, xfB), '/' -> LCons(xA / xB, function() -> ldzialanie xfA xfB '/')
| LCons(xA, xfA), LCons(xB, xfB), '*' -> LCons(xA * xB, function() -> ldzialanie xfA xfB '*')
| LNil, LNil, _ -> LNil
| LNil, LCons(x, xf), _ -> LCons(x, function() -> xf())
| LCons(x, xf), LNil, _ -> LCons(x, function() -> xf())
| LCons(_), LCons(_), _ -> failwith "Not existible operator"
;;

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

Это

let rec ldzialanie listA listB operator = function
| LCons(xA, xfA), LCons(xB, xfB), '+' ->

говорит о том, что при оценке ldzialanie x y z получается функция , которая принимает в качестве аргумента тройку.
Это не то, что вы хотите - вы хотите, чтобы ldzialanie x y zсоздайте 'a lazyList.

Вы хотите сопоставить вместо аргументов.
Вам также нужно принудительно задавать хвосты ваших ленивых списков при рекурсии - рекурсия требует 'a lazyList, а не unit -> 'a lazyList.
В качестве третьего пункта, function () -> xf() эквивалентен xf.

let rec ldzialanie listA listB operator = match listA, listB, operator with
    LCons(xA, xfA), LCons(xB, xfB), '+' -> LCons(xA + xB, function() -> ldzialanie (xfA()) (xfB()) '+')
  | LCons(xA, xfA), LCons(xB, xfB), '-' -> LCons(xA - xB, function() -> ldzialanie (xfA()) (xfB()) '-')
  | LCons(xA, xfA), LCons(xB, xfB), '/' -> LCons(xA / xB, function() -> ldzialanie (xfA()) (xfB()) '/')
  | LCons(xA, xfA), LCons(xB, xfB), '*' -> LCons(xA * xB, function() -> ldzialanie (xfA()) (xfB()) '*')
  | LNil, LNil, _ -> LNil
  | LNil, LCons(x, xf), _ -> LCons(x, xf)
  | LCons(x, xf), LNil, _ -> LCons(x, xf)
  | LCons(_), LCons(_), _ -> failwith "Not existible operator"
;;

Давайте немного укоротим это.

Если вы посмотрите на «ноль случаев», то результат, когда один аргумент равен LNil, является другим аргументом.

let rec ldzialanie listA listB operator = match listA, listB, operator with
    LCons(xA, xfA), LCons(xB, xfB), '+' -> LCons(xA + xB, function() -> ldzialanie (xfA()) (xfB()) '+')
  | LCons(xA, xfA), LCons(xB, xfB), '-' -> LCons(xA - xB, function() -> ldzialanie (xfA()) (xfB()) '-')
  | LCons(xA, xfA), LCons(xB, xfB), '/' -> LCons(xA / xB, function() -> ldzialanie (xfA()) (xfB()) '/')
  | LCons(xA, xfA), LCons(xB, xfB), '*' -> LCons(xA * xB, function() -> ldzialanie (xfA()) (xfB()) '*')
  | LNil, r, _ -> r
  | l, LNil, _ -> l
  | LCons(_), LCons(_), _ -> failwith "Not existible operator"
;;

В «неnil ", и не совсем очевидно, что рекурсия верна.
Если вы сначала преобразуете символ оператора в функцию, вы можете сжать их до одного случая.

Я бы также позволил аргументу оператора идти первым, чтобы вы могли определить, например, let add_lists = ldzialanie (+).

Примерно так:

let to_function x = match x with
    '+' -> ( + )
  | '*' -> ( * )
  | '/' -> ( / )
  | '-' -> ( - )
  | _ -> failwith "Non-existent operator";;

let rec ldzialanie_helper op listA listB = match listA, listB with
    LCons(xA, xfA), LCons(xB, xfB) -> LCons(op xA xB, function() -> ldzialanie_helper op (xfA()) (xfB()))
  | LNil, r  -> r
  | l, LNil  -> l;;

let ldzialanie op = ldzialanie_helper (to_function op);;
0 голосов
/ 26 ноября 2018

Прежде всего, здесь есть некоторая путаница

let rec ldzialanie listA listB operator = function
    | LCons(xA, xfA), LCons(xB, xfB)

Вы говорите, что ldzialanie применяется к аргументам listA, listB и operator возвращает функцию.И эта функция, которую вы возвращаете, принимает тройное значение, для которого вы сопоставляете шаблон.

Скорее, вы должны использовать match для сопоставления шаблонов с аргументами ldzialanie,

let rec ldzialanie listA listB operator = match listA, listB, operator with
    LCons(xA, xfA), LCons(xB, xfB), '+' ->
  | LCons(xA, xfA), LCons(xB, xfB), '-' -> 

Или есливы предпочитаете определять ldzialanie, используя function, вы должны иметь в виду, что функция ldzialanie, а не ldzialanie listA listB operator.

let rec ldzialanie2 = function 
     LCons(xA, xfA), LCons(xB, xfB), '+' ->
   | LCons(xA, xfA), LCons(xB, xfB), '-' -> 

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

ldzialanie  : int lazyList -> int lazyList -> char -> int lazyList 
ldzialanie2 : int lazyList * int lazyList * char -> int lazyList 

Об этом необходимо помнить при выполнении рекурсивного вызова.

Относительно того, как вы рассчитываете результат, вы должны знать, что с учетом LCons(xA, xfA) тип xfA не 'a lazyList, а unit -> 'a lazyList.Таким образом, вы не можете передать xfA в качестве аргумента, когда вам нужен 'a lazyList.

...