【问题标题】:Function returning two outputs返回两个输出的函数
【发布时间】:2016-11-16 16:14:04
【问题描述】:

我想创建一个产生两个输出的函数。 请考虑以下示例:

我构建了两个函数,给定一个整数列表,返回偶数位置的元素和奇数位置的元素列表。

let rec alternate1 lst =
    match lst with
    [] -> []
    | [x] -> []
    | x::y::xs -> y::(alternate1 xs)

let rec alternate2 lst =
    match lst with
    [] -> []
    | [x] -> [x]
    | x::y::xs -> x::(alternate2 xs)

这里一切都很好。现在,问题来了:我想创建一个 single 函数alternate,它返回带有签名alternate: int list-> (int list * int list) 的两个列表。

let rec alternate lst =
    match lst with 
    [] -> []
    | [x] -> []
    | [x::y] -> [y]
    (*My attempts:*)
    | x::y::xs -> ((y::alternate xs),  (x::alternate xs))
    | x::y::xs -> [(y::alternate xs);  (x::alternate xs)]
    | x::y::xs -> ((y::alternate xs) && (x::alternate xs))

到目前为止,没有任何解决方案奏效。我很确定这个问题甚至很愚蠢,但我的reference 并没有帮助我解决问题。

【问题讨论】:

  • 为什么不返回两个列表的元组?
  • 那会很理想,但我仍然无法将其付诸实践。

标签: function f#


【解决方案1】:

由于您递归地调用alternate,递归调用会返回两个输出,所以当然不能将该元组视为一个列表 - 就像在y::alternate xs 中一样。

你必须先把元组拆开,把各个部分分开处理,然后在返回之前重新组合成一个元组:

let nextXs, nextYs = alternate xs
x::nextXs,  y::nextYs

然后,您的基本情况也应该返回两个输出 - 否则您的函数的返回类型不明确:

| [] -> [], []
| [x] -> [x], []
| [x; y] -> [x], [y]

(另请注意,您的匹配案例[x::y]实际上匹配一个列表列表,其中仅包含一个列表,其中第一个元素将命名为x,列表的尾部将命名为y . 为了匹配恰好包含两个元素的列表,请使用[x; y]x::y::[])

结合起来:

let rec alternate lst =
    match lst with 
    | [] -> [], []
    | [x] -> [x], []
    | [x; y] -> [x], [y]
    | x::y::rest ->
        let nextXs, nextYs = alternate rest
        x::nextXs,  y::nextYs

另外:从技术上讲,[x; y] 基本情况是不需要的,因为它可以被最后一种情况所覆盖。

【讨论】:

  • 谢谢 Fyodor,现在我肯定对这个程序有了更好的认识。
【解决方案2】:

Fyodor's answer 已完成(和往常一样)
所以我只是想为那些想知道如何使其成为尾递归(使用continuation-passing style)的人添加他的代码的尾递归版本(以及一些减少)

let alternate xs =
  let aux cont even odd (evens, odds) = cont (even :: evens, odd :: odds)

  let rec loop cont = function
  | [] | [_]    as xs -> cont (xs, [])
  | even :: odd :: xs -> loop (aux cont even odd) xs

  loop id xs

另外,可以为每个 side 列表使用 2 个延续,但在这里我认为它不是那么有用,因为每次都操纵两个 side,但无论如何

let alternate xs =
  let aux cont x xs = cont (x :: xs)

  let rec loop evenCont oddCont = function
  | [] | [_]    as xs -> evenCont xs, oddCont []
  | even :: odd :: xs -> loop (aux evenCont even) (aux oddCont odd) xs

  loop id id xs

【讨论】:

  • Sehnsucht,谢谢您的回答。这是另一个有用的知识:)
猜你喜欢
  • 1970-01-01
  • 2019-02-07
  • 2022-01-13
  • 2020-01-19
  • 2011-11-25
  • 2021-09-06
  • 2016-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多