如何仅通过在 F# 中使用递归来编写此函数?
How can I write this function only by using recursion in F#?
let rec n_cartesian_product = function
| [] -> [[]]
| x :: xs ->
let rest = n_cartesian_product xs
List.concat (List.map (fun i -> List.map (fun rs -> i :: rs) rest) x)
您好!我写了这个函数,但我需要在不使用任何 List.*
内置函数的情况下编写它。由于有一个调用外部函数的内部函数,我假设我必须定义两个相互递归的函数。
定义一个 concat 函数似乎很简单:
let rec list_concat ( lst : 'a list list ) : 'a list =
match lst with
[] -> []
|x::xs -> x @ (list_concat xs)
问题是,我被困在产生 concat 参数的函数的定义上:
let rec fun_i rest =
match rest with
[] -> []
|x::xs -> fun_rs
and fun_rs =
fun_i :: fun_rs
我似乎无法设计出合适的解决方案。你能帮帮我吗?
编辑:例如,给定此输入
[["A";"a"];["B";"b"];["C";"c"]]
我想要这个输出:
[["A"; "B"; "C"]; ["A"; "B"; "c"]; ["A"; "b"; "C"]; ["A"; "b"; "c"];
["a"; "B"; "C"]; ["a"; "B"; "c"]; ["a"; "b"; "C"]; ["a"; "b"; "c"]]
N-笛卡尔积
要递归定义 n 笛卡尔积,最简单的方法就是对原始(非递归)示例中使用的函数进行递归定义:
let rec list_concat lst =
match lst with
|[] -> []
|x::xs -> x @ (list_concat xs)
let rec list_map f lst =
match lst with
|[] -> []
|x::xs -> (f x) :: list_map f xs
let rec n_cartesian_product =
function
| [] -> [[]]
| x :: xs ->
let rest = n_cartesian_product xs
list_concat (list_map (fun head -> list_map (fun tail -> head :: tail) rest) x)
就 F# 中的惯用编写而言,最好使用更通用的函数(如 fold
)编写,而不是使用显式递归编写大量自定义函数。所以,你可以定义一些额外的功能:
let list_collect f = list_concat << list_map f
let rec list_fold f acc lst =
match lst with
|[] -> acc
|hd::tl -> list_fold f (f acc hd) tl
let n_cartesian_product_folder rest first =
list_collect (fun head -> list_map (fun tail -> head :: tail) rest) first
那么我们可以将n_cartesian_product
简单地重新定义为:
let n_cartesian_product2 lst = list_fold (n_cartesian_product_folder) [[]] lst
如果我们使用 F# 核心库函数(而不是自定义递归实现),这种方法将涉及更多标准代码,并且出错更少。
笛卡尔积
(我将把这部分留在这里,因为显然它很有用)
定义一个函数,它接受 'a
的列表并生成 'b * 'a
的列表,其中类型 'b
的所有内容都是一些提供的元素 y
。
/// take a list of 'a and make a list of (y, 'a)
let rec tuplify y lst =
match lst with
|[] -> []
|x::xs -> (y, x) :: (tuplify y xs)
然后定义一个递归遍历我的两个列表的函数,在第一个列表和整个第二个列表的当前元素上调用 tuplify
,并通过对笛卡尔积的递归调用进行连接。
/// cartesian product of two lists
let rec cartesianProduct lst1 lst2 =
match lst1 with
|[] -> []
|x::xs -> tuplify x lst2 @ (cartesianProduct xs lst2)
let rec n_cartesian_product = function
| [] -> [[]]
| x :: xs ->
let rest = n_cartesian_product xs
List.concat (List.map (fun i -> List.map (fun rs -> i :: rs) rest) x)
您好!我写了这个函数,但我需要在不使用任何 List.*
内置函数的情况下编写它。由于有一个调用外部函数的内部函数,我假设我必须定义两个相互递归的函数。
定义一个 concat 函数似乎很简单:
let rec list_concat ( lst : 'a list list ) : 'a list =
match lst with
[] -> []
|x::xs -> x @ (list_concat xs)
问题是,我被困在产生 concat 参数的函数的定义上:
let rec fun_i rest =
match rest with
[] -> []
|x::xs -> fun_rs
and fun_rs =
fun_i :: fun_rs
我似乎无法设计出合适的解决方案。你能帮帮我吗?
编辑:例如,给定此输入
[["A";"a"];["B";"b"];["C";"c"]]
我想要这个输出:
[["A"; "B"; "C"]; ["A"; "B"; "c"]; ["A"; "b"; "C"]; ["A"; "b"; "c"];
["a"; "B"; "C"]; ["a"; "B"; "c"]; ["a"; "b"; "C"]; ["a"; "b"; "c"]]
N-笛卡尔积
要递归定义 n 笛卡尔积,最简单的方法就是对原始(非递归)示例中使用的函数进行递归定义:
let rec list_concat lst =
match lst with
|[] -> []
|x::xs -> x @ (list_concat xs)
let rec list_map f lst =
match lst with
|[] -> []
|x::xs -> (f x) :: list_map f xs
let rec n_cartesian_product =
function
| [] -> [[]]
| x :: xs ->
let rest = n_cartesian_product xs
list_concat (list_map (fun head -> list_map (fun tail -> head :: tail) rest) x)
就 F# 中的惯用编写而言,最好使用更通用的函数(如 fold
)编写,而不是使用显式递归编写大量自定义函数。所以,你可以定义一些额外的功能:
let list_collect f = list_concat << list_map f
let rec list_fold f acc lst =
match lst with
|[] -> acc
|hd::tl -> list_fold f (f acc hd) tl
let n_cartesian_product_folder rest first =
list_collect (fun head -> list_map (fun tail -> head :: tail) rest) first
那么我们可以将n_cartesian_product
简单地重新定义为:
let n_cartesian_product2 lst = list_fold (n_cartesian_product_folder) [[]] lst
如果我们使用 F# 核心库函数(而不是自定义递归实现),这种方法将涉及更多标准代码,并且出错更少。
笛卡尔积 (我将把这部分留在这里,因为显然它很有用)
定义一个函数,它接受 'a
的列表并生成 'b * 'a
的列表,其中类型 'b
的所有内容都是一些提供的元素 y
。
/// take a list of 'a and make a list of (y, 'a)
let rec tuplify y lst =
match lst with
|[] -> []
|x::xs -> (y, x) :: (tuplify y xs)
然后定义一个递归遍历我的两个列表的函数,在第一个列表和整个第二个列表的当前元素上调用 tuplify
,并通过对笛卡尔积的递归调用进行连接。
/// cartesian product of two lists
let rec cartesianProduct lst1 lst2 =
match lst1 with
|[] -> []
|x::xs -> tuplify x lst2 @ (cartesianProduct xs lst2)