F#:如何找到笛卡尔幂
我写笛卡尔幂函数有问题。我找到了许多关于计算笛卡尔积的例子,但没有一个是关于笛卡尔幂的。F#:如何找到笛卡尔幂,f#,functional-programming,F#,Functional Programming,我写笛卡尔幂函数有问题。我找到了许多关于计算笛卡尔积的例子,但没有一个是关于笛卡尔幂的。 例如,[1;2]被提升到3=[[1;1;1];[1;1;2];[1;2;1];[1;2;2];[2;1;2];[2;2;2;1];[2;2;2] 我使用以下代码计算笛卡尔积: let Cprod U V = let mutable res = [] for u in U do for v in V do res <
例如,[1;2]被提升到3=[[1;1;1];[1;1;2];[1;2;1];[1;2;2];[2;1;2];[2;2;2;1];[2;2;2]
我使用以下代码计算笛卡尔积:
let Cprod U V =
let mutable res = []
for u in U do
for v in V do
res <- res @ [[u;v]]
res
let Cpower U n =
let mutable V = U
for i=0 to n-1 do
V <- Dprod U V
V
让Cprod U V=
设可变res=[]
为你做的事
对于v-in-v-do
res我解决了我的问题:
let rec Cprod = function
| [] -> [[]]
| hs::tss ->
[ for h in hs do
for ts in D tss ->
h::ts]
let Cpower U n =
let mutable inp = []
for i=0 to n-1 do
inp <- inp @ [U]
Dprod inp
让rec Cprod=函数
| [] -> [[]]
|hs::tss->
[适用于hs-do中的h
对于D tss中的ts->
h::ts]
设Cpower U n=
设可变inp=[]
对于i=0到n-1 do
inp至于错误的来源,我们有以下类型的限制
// Cprod: seq<`a> -> seq<`a> -> `a list list
let Cprod U V =
...
// Cpower: seq<`a> -> int -> ???
let Cpower U n =
// V: seq<`a>
let mutable V = U
// n: int
for i=0 to n-1 do
(* The next line implies two type constraints:
V: seq<`a>
V: `a list list *)
V <- Dprod U V
V
//Cprod:seq->seq->`列表
让我们一起来=
...
//Cpower:seq->int->???
让我们共同努力=
//五:seq
设可变V=U
//n:int
对于i=0到n-1 do
(*下一行表示两种类型约束:
五:seq
V:`列表*)
V以下是从Haskell移植的一个版本:
let replicate n x = [for i in 1 .. n -> x]
let sequence ms =
List.fold (fun m' m -> [for x in m do for xs in m' -> (x::xs)]) [[]] ms
let Cpower n l = replicate n l |> sequence
它的工作原理类似于计数:如果您将l
视为数字,那么它会复制它们以获得您拥有的位数,然后使用序列对它们进行计数
换句话说,所有小于2^3的二进制数都可以通过将[0;1]
复制3次来生成[[0;1];[0;1];[0;1]
,然后对其运行序列
通过切换到顺序折叠
,可以使这一点变得更慢:
let sequence' ms =
Seq.fold (fun m' m -> seq {for x in m do for xs in m' do yield (x::xs)})
(seq {yield []})
ms
let rec cartesianPow input n = seq {
if (n = 1) then
// This handles the case when the recursion terminates. We need to turn
// each element from the input into a list containing single element:
// [1; 2; 4] ^ 1 = [ [1]; [2]; [3] ]
for el in input do
yield [el]
else
// We perform one Cartesian product (and run the rest of the
// power calculation recursively). Mathematically:
// [1; 2; 3] ^ n = [1; 2; 3] x ([1; 2; 3] ^ (n-1))
for el in input do
for rest in cartesianPow input (n - 1) do
yield el :: rest }
cartesianPow [ 0; 1 ] 3
这将为您提供一系列结果,而不是列表。不幸的是,我无法通过查看它来判断它是否足够懒:它可能必须在内存中生成整个列表才能开始为您提供第一个元素。您应该能够通过在调试器中单步执行它来找到答案。(或者你可能比我更擅长阅读懒惰。)我还想补充一点,在编写F#代码时,通常更倾向于避免使用可变的
值。当您学习F#或需要优化某些代码以加快运行时,这很好,但如果您想编写更惯用的F#代码,最好使用递归,而不是可变的
值
我试图更优雅地书写笛卡尔的力量,这是我的版本。它是递归实现的。当我们需要计算X^1
时,我显式地处理这种情况,递归情况执行如下笛卡尔积:X^n=X*X^(n-1)
我使用的是序列表达式,该方法使用yield
生成序列元素(作为结果返回):
let sequence' ms =
Seq.fold (fun m' m -> seq {for x in m do for xs in m' do yield (x::xs)})
(seq {yield []})
ms
let rec cartesianPow input n = seq {
if (n = 1) then
// This handles the case when the recursion terminates. We need to turn
// each element from the input into a list containing single element:
// [1; 2; 4] ^ 1 = [ [1]; [2]; [3] ]
for el in input do
yield [el]
else
// We perform one Cartesian product (and run the rest of the
// power calculation recursively). Mathematically:
// [1; 2; 3] ^ n = [1; 2; 3] x ([1; 2; 3] ^ (n-1))
for el in input do
for rest in cartesianPow input (n - 1) do
yield el :: rest }
cartesianPow [ 0; 1 ] 3
这不是最有效的实现(例如,因为在for
循环中使用yield
可能不是一件好事),但这是大型n
的唯一问题。在F#中,通常最好从更容易理解的最干净的实现开始:-)。您知道@has linear runtime是吗?最后使用::和反转(如果有必要的话)将比使用@快得多。