Вычисляя декартово произведение списка чисел с F #

Я новичок в f #

Я пытаюсь вычислить декартовы произведения списка чисел. Я "заимствовал" это.

let xs = [1..99]
let ys = [1..99]
seq {for x in xs do for y in ys do yield x * y}

Есть ли лучший или более элегантный способ?

Гэри

Ответы

Ответ 1

Другой возможностью для решения проблемы, основанной на функциональности, предоставляемой модулем List, будет следующее:

let xs = [1..99]
let ys = [1..99]
let zs = xs |> List.collect (fun x -> ys |> List.map (fun y -> x*y))

что позволяет избежать дополнительных вызовов .concat и также выполнять задание.

Но я бы придерживался вашего решения. Он должен быть самым читаемым, который является настоящим спикером. (Просто попробуйте прочитать коды вслух. Твое вполне понятно, а Нолдорины или мои нет.)

Ответ 2

Отказ от ответственности: у меня нет машины с установленным текущим F #, поэтому я не могу проверить свой код. В принципе, если вы украдете sequence из Haskell, вы можете написать свою программу как

let cartesian = sequence >> List.map product

и запустите его как

cartesian [[1..99]; [1..99]]

Вот как писать sequence. Это обобщенная версия выражения последовательности, которое вы написали. Он просто обрабатывает неограниченное количество списков: { for x in xs do for y in ys do for z in zs ... yield [x;y;z;...] }.

let rec sequence = function
  | [] -> Seq.singleton []
  | (l::ls) -> seq { for x in l do for xs in sequence ls do yield (x::xs) }
// also you'll need product to do the multiplication
let product = Seq.fold_left1 ( * )

Затем вы можете написать свою программу как

let cartesian xs ys = [xs; ys] |> sequence |> List.map product
// ... or one-argument, point-free style:
let cartesian' = sequence >> Seq.map product

Возможно, вам придется изменить некоторые Seq на List s.

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

Ответ 3

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

Попробуйте следующее:

let xs = [1..99]
let ys = [1..99]
xs |> List.map(fun x -> ys |> List.map(fun y -> x * y)) |> List.concat

Казалось бы, немного длиннее, хотя и более функциональный по стилю.