OCaml 中的交错

Posted

技术标签:

【中文标题】OCaml 中的交错【英文标题】:Interleaving in OCaml 【发布时间】:2017-02-24 12:22:21 【问题描述】:

我正在尝试创建一个函数来交错一对三元组,例如 ((6, 3, 2), (4, 5 ,1)) 并从这个交错中创建一个 6 元组。 我做了一些研究,但可以理解交错应该如何工作,所以我自己尝试了一些东西,最终得到了一个创建 6 元组但不是以正确的交错方式的代码。这是我的代码

let interleave ((a, b, c), (a', b', c')) =
let sort2 (a, b) = if a > b then (a, b) else (b, a) in
let sort3 (a, b, c) = 
let (a, b) = sort2 (a, b) in
let (b, c) = sort2 (b, c) in
let (a, b) = sort2 (a, b) in
(a, b, c) in
let touch ((x), (y)) = 
let (x) = sort3 (x) in
let (y) = sort3 (y) in
((x),(y)) in
let ((a, b, c), (a', b', c')) = touch ((a, b, c), (a', b', c')) in
(a, b', a', b, c, c');;

有人可以向我解释如何使用哪些功能来实现适当形式的交错。我还没有了解递归和列表,以防你问我为什么要这样做。 已经谢谢你了。

【问题讨论】:

我不明白你在做什么。对我来说,“交错”意味着let interleave ((a, b, c), (a', b', c')) = (a, a', b, b', c, c');;;但是从您的代码中可以清楚地看出您正在尝试做的远不止这些。你能准确解释一下你希望你的函数有什么行为吗? 说实话我迷路了。正如我上面提到的,我认为交错具有某种模式。我想我只是误解了给定的描述。这类似于“一个函数,它采用一对三元组并形成一个 6 元组,表示可以使用这对三元组创建的最大值”。所以我很难从两个三元组中创造出最大值。我希望这很清楚我现在很困惑。谢谢 【参考方案1】:

问题陈述使用“max”这个词,但没有定义它。如果你使用 OCaml 的内置 compare 函数作为你的定义,它使用 lexicographic order。因此,您希望(6 个值中的)最大值位于 6 元组的第一个位置,其次是第二个最大值,依此类推。

考虑到您之前建立的元组排序技能,这应该很容易。

就其价值而言,保留两个 3 元组的身份似乎没有多大价值。一旦进入最外层的函数,您就可以将 6 个值作为 6 元组使用。或者在我看来是这样。

更新

从您的示例(可能应该在一开始就给出它:-) 很清楚您被要求做什么。您希望最终得到一个序列,其中原始元组的元素按其原始顺序排列,但可以任意交错。这通常称为“洗牌”(或合并)。您必须按字典顺序找到具有最大值的 shuffle。

如果你对此进行推理,它相当于从两个元组的前面取最大的值并将其放在输出中。

使用列表要容易得多

【讨论】:

描述中给出的例子表明(6, 4, 5, 3, 2, 1) “645321”是可以从(6, 3, 2)和( 4、5、1)。因此,将最大值放在第一位并按照顺序是行不通的。从上面我想我应该将后一个元组的第一个和第二个数字与第一个元素中的第一个元素进行比较,然后按该顺序对它们进行排序。我想我可以使用 if 语句来实现。 啊哈,这是因为“交错”。我知道了。我会更新我的答案。 谢谢,这次更新让我明白了。我是在正确的方向let interleave ((a, b, c), (a', b', c')) = if a <= a' then (a', a, b, c, b', c') else (a, a', b, b', c, c') in if a <= b' then (a', b', a, b, c, c') else (a', a, b, c, b', c') in if a <= c' then (a', b', c', a, b, c) else (a', b', a, b, c, c') 还是在错误的海域游泳? :-D 我绝对理解这个想法,但现在将其放入代码中有点困难。我对它了解得太多了,无法集中注意力。感谢您的所有回答和cmets。我实际上学到了很多。 请忽略带有 if 语句没有意义的评论:-D【参考方案2】:

现在我明白了你的最终目标是什么。 . .

由于 n 元素的元组对于不同的 n 是不同的类型,因此您需要定义帮助函数来处理不同大小的元组。

一种方法,基本上模仿列表上的递归函数(但需要许多额外的函数,因为元组都有不同的类型),是有两组辅助函数:

将值添加到现有元组的函数:prepend_to_2,直到 prepend_to_5。例如,

let prepend_to_3 (a, (b, c, d)) = (a, b, c, d)

交错两个元组的函数,每个可能的大小最多为 3:interleave_1_1interleave_1_2interleave_1_3interleave_2_2interleave_2_3interleave_3_3。 (请注意,我们不需要 interleave_2_1,因为我们可以使用相反顺序的参数调用 interleave_1_2。)例如,

let interleave_2_2 ((a, b), (a', b')) =
    if a > a'
    then prepend_to_3 (a, interleave_1_2 (b, (a', b')))
    else prepend_to_3 (a', interleave_1_2 (b', (a, b)))

(你知道它是如何工作的吗?)

那么interleave 就是interleave_3_3

使用列表和递归,这会简单得多,因为单个函数可以对任意长度的列表进行操作,因此您不需要相同逻辑的多个不同副本。

【讨论】:

以上是关于OCaml 中的交错的主要内容,如果未能解决你的问题,请参考以下文章

OCaml 中的依赖类型

OCaml中的主要功能

OCaml 中的“and”关键字是啥意思?

OCaml和OCaml评估模型中的功能应用列表

OCaml 中的 D 类不可变数据切片

为啥 OCaml 中的模块类型注释会导致此代码无法编译?