OCaml:Lists中元素的组合,函数推理

OCaml: Combination of elements in Lists, functional reasoning

我又回到了 OCaml 编码中,我非常想念它。我非常想念它,我完全失去了用这种语言推理的能力,今天我碰壁了。

我想做的是一组n个列表之间的元素组合。 我通过首先尝试在两个任意大小的列表之间组合元素来分解问题。

假设我们必须列出:l1 = [1;2;3]l2 = [10,20]

我想做的是获取以下列表:

 l_res = [10;20;20;40;30;60]

我知道如何使用循环结构来做到这一点,但我真的很想在没有它们的情况下解决这个问题。

我尝试了以下方法:

       let f l1 l2 = 
         List.map (fun y -> (List.map (fun x -> x * y) l1) l2

但这似乎不起作用。我得到的类型是 f : int list -> int list -> int list list 但我想要 f : int list -> int list -> int list

我已经尝试了很多不同的方法,我觉得我太复杂了。

我错过了什么?

你缺少的是 List.map f [a; b; c] 给出 [f a; f b; f c] 所以你将从你的函数中得到的是

f [a; b; c] [d; e] = [[ad; ae]; [bd; be]; [cd; ce]]

但你想要

 f [a; b; c] [d; e] = [ad; ae; bd; be; cd; ce]

所以你需要使用另一个迭代器, :

 let f l1 l2 = 
   let res = List.fold_left (fun acc x ->
     List.fold_left (fun acc y -> (x * y) :: acc) acc l2
   ) [] l1 in
   List.rev res

或压平你的结果:

val concat : 'a list list -> 'a list

Concatenate a list of lists. The elements of the argument are all concatenated together (in the same order) to give the result. Not tail-recursive (length of the argument + length of the longest sub-list).

 val flatten : 'a list list -> 'a list

Same as concat. Not tail-recursive (length of the argument + length of the longest sub-list).

let f l1 l2 =  
  let multiply x = List.map (( * )x) l2 in
  l1 |> List.map multiply
     |> List.concat

一些 Core 风格的答案:

open Core.Std

let f1 l1 l2 =
  List.map (List.cartesian_product l1 l2) ~f:(fun (x, y) -> x * y)

let f2 l1 l2 =
  List.concat_map l1 ~f:(fun x -> List.map l2 ~f:(fun y -> x * y))

let f4 l1 l2 =
  let open List.Monad_infix in
  l1 >>= fun x ->
  l2 >>| fun y ->
  x * y

最后一个答案明确地(可以说是其他两个答案隐含地)使用了列表 monad,这是一个教科书用例。我在 Batteries 中找不到列表 monad,这可能并不令人惊讶,因为它的使用范围远不如(比如)选项或结果 monad。