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。
我又回到了 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。