Как правильно реализовать функцию reduce в F#

#functional-programming #f#

#функциональное программирование #f#

Вопрос:

Я довольно новичок в F # и списках обучения.Мне трудно реализовать свою собственную функцию уменьшения. Я застрял, пытаясь реализовать это. Это то, что у меня есть до сих пор, но я получаю сообщение об ошибке, которое при вызове reduce говорит, что список, который я передаю, является типом типа int, но должен быть типа ‘список. Я был очень разочарован этим, поэтому любая помощь приветствуется.

Вот как выглядит мой код:

 let reduce Fn (list: 'a list) = 
      let rec innerFun list acc =
          match list with
          | (x::xs) :: xss ->
              let newAcc = Fn x xs // the fn applied to the head and the next element
              innerFun xss newAcc // recurse through the list with new accumulator
          | [] -> acc // if the list is empty return the accumulator
      innerFun list 0 
               
   //Calling reduce            
   let red2 = reduce (fun x y -> x*y) [23; 4]

  

Комментарии:

1. Вам не хватает части определения функции в примере?

2. Дал вам ответ о проблеме, которую вы видите, но в вашей реализации есть несколько вещей, которые отсутствуют. Сравните его поведение со встроенным List.reduce , особенно для пустых и одноэлементных списков.

Ответ №1:

Непосредственная проблема, с которой вы сталкиваетесь, на самом деле довольно проста и чисто синтаксическая:

 match list with
| (x::xs) :: xss ->
  

Круглые скобки делают так, чтобы шаблон соответствовал списку списков, т. Е. x::xs Является головным элементом списка, а x and xs соответственно являются его головой и хвостом.

Вам нужно сопоставить два элемента в начале списка — вам нужно удалить скобки:

 match list with
| a::b::tail ->
  

Обратите внимание, что в соглашении об именах, которое вы используете, уже есть подсказка — s in xs означает множественное число — поэтому в этом шаблоне вы разбиваете список на начало «ex» и конец «exes».

Комментарии:

1. Большое спасибо! Это очень полезно! Еще один вопрос, который у меня также возник, заключается в том, как я мог бы использовать функцию reduce в любом типе? Поскольку я передаю int 0 в качестве начального накопителя, результатом всегда будет некоторый int, но, допустим, я хочу выполнить свою функцию reduce для других типов, таких как строки или символы? Есть ли способ, которым я мог бы создать универсальный аккумулятор? Еще раз спасибо

2. Вот о чем мой другой комментарий — обычно reduce не нуждается в этом явном начальном значении и, как ожидается, завершится ошибкой при пустом вводе. Вы могли бы сделать это начальное значение явным и превратить его в аргумент для функции, но в этот момент вы фактически реализуете fold .