函数返回两个输出

时间:2016-11-16 16:14:04

标签: function f#

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

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

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)

这里一切都很好。现在,问题是:我想创建一个单个函数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并没有帮助我解决问题。

2 个答案:

答案 0 :(得分:6)

由于你以递归方式调用alternate,递归调用会返回两个输出,所以当然你不能将该元组视为列表 - 就像在{{ 1}}。

你必须首先拆开元组,分别处理这些部分,并在返回之前将它们重新组合成一个元组:

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 基本情况,因为它会被最后一种情况所涵盖。

答案 1 :(得分:3)

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

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

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