簡體   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)

你好! 我編寫了此函數,但是我需要在不使用任何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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM