简体   繁体   English

如何仅通过在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)

Hello! 你好! I wrote this function but I need to write it without using any List.* built-in functions. 我编写了此函数,但是我需要在不使用任何List.*内置函数的情况下编写它。 Since there's an inner function that calls an outer function, I assume I must define two mutually recursive functions. 由于有一个内部函数调用了外部函数,因此我假设必须定义两个相互递归的函数。

Defining a concat function seemed easy: 定义concat函数似乎很容易:

let rec list_concat ( lst : 'a list list ) : 'a list =
match lst with 
[]    -> []
|x::xs  -> x @ (list_concat xs)

The problem is, I'm stuck at the definition of the functions which yield the argument for concat: 问题是,我陷入了产生concat参数的函数的定义中:

let rec fun_i rest =
    match rest with
    [] -> []
    |x::xs -> fun_rs

and fun_rs =
fun_i :: fun_rs

I can't seem to devise a proper solution. 我似乎无法设计适当的解决方案。 Can you help me? 你能帮助我吗?

edit: for instance, given this input 编辑:例如,鉴于此输入

[["A";"a"];["B";"b"];["C";"c"]]

I want this output: 我想要这个输出:

[["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-Cartesian Product N-笛卡尔积

To define the n cartesian product recursively, the easiest method is just to make recursive definitions of the functions used in your original (non-recursive) example: 要递归定义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)

In terms of writing idiomatically in F#, it's best to write using more general functions (like fold ), rather than making a lot of custom functions with explicit recursion. 就用F#惯用地编写而言,最好使用更通用的函数(例如fold )进行编写,而不是使用显式递归来制作大量自定义函数。 So, you could define some additional functions: 因此,您可以定义一些其他功能:

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

Then we can redefine n_cartesian_product simply as: 然后我们可以简单地重新定义n_cartesian_product

let n_cartesian_product2 lst = list_fold (n_cartesian_product_folder) [[]] lst

If we were using F# core library functions (rather than custom recursive implementations) this approach would involve more standard code with less to go wrong. 如果我们使用的是F#核心库函数(而不是自定义递归实现),则此方法将涉及更多的标准代码,而出错的机会更少。

Cartesian Product (I'll leave this part here since apparently it was useful) 笛卡尔积 (我将在这里保留这部分,因为它显然很有用)

Define a function that takes a list of 'a and make a list of 'b * 'a where all of the things of type 'b are some supplied element y . 定义一个函数,该函数采用'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)

Then define a function that recurses through both my lists, calling tuplify on the current element of the first list and the entire second list and concat that with the recursive call to cartesian product. 然后定义一个遍历我的两个列表的函数,在第一个列表的当前元素和整个第二个列表上调用tuplify ,并将其与笛卡尔积的递归调用相结合。

/// cartesian product of two lists
let rec cartesianProduct lst1 lst2 =
    match lst1 with
    |[] -> []
    |x::xs -> tuplify x lst2 @ (cartesianProduct xs lst2)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM