在F#中分割函数
我试图在F#中实现一个用于将列表拆分为两个等长半部分的函数(该问题假设列表的长度甚至相等)。 使用搜索功能产生了一个线程,处理我正试图通过现在完全相同的问题:
在F#中将列表拆分成两个相等的列表
我试图实现由用户Juliet提供的解决方案,他提供了一个部分答案:
let cut l =
let rec cut = function
| xs, ([] | [_]) -> xs
| [], _ -> []
| x::xs, y::y'::ys -> cut (xs, ys)
cut (l, l)
其中返回列表的后半部分。 我正在努力找出一种方法来返回上半场,所以我做了一些修改:
let rec cut(xs, ys) =
let zs = []
match xs, ys with
| xs, ([] | [_]) -> (xs, zs)
| [], _ -> ([], [])
| x::xs, y1::y2::ys ->
x::zs
cut (xs, ys)
你可能知道F#是我的第一个函数式编程语言,我对它的工作原理感到困惑不解。 模式匹配对我来说是一件新事物,我从来没有很好的从递归开始。
根据我的理解,模式匹配的工作方式是它基本上是if-then-else语句的更多功能版本,其中 - >左侧的代码是条件(“if”位),所有内容如果条件检查通过(“then”位),则右侧是要执行的代码块。
我不完全确定的是你是否被允许做这样的事情:
| x::xs, y1::y2::ys ->
x::zs
cut (xs, ys)
如果模式匹配确实像if语句那样工作,那么它应该是,因为在if语句中它会看起来像
if (x::xs && y1::y2::ys)
{
x::zs
cut (xs, ys)
}
无论如何,它似乎不允许声明x :: zs,因为Visual Studio给我一个警告:
这个表达式的结果被隐式忽略。 考虑使用“ignore”来显式丢弃该值,例如'expr |> ignore''或'let'将结果绑定到名称,例如let result = expr'。
我不确定最后一部分是什么意思。 我以为我已经将该列表声明为行中函数的局部变量
let zs = []
我想要做的就是在切割函数的每个递归迭代中将列表xs的头部添加到另一个列表zs中,当到达基本案例时,它将包含每个传递过来的元素x(换句话说,列表的前半部分),然后返回两个xs(包含列表的后半部分)和包含前半部分的列表,但似乎不允许这样做?
无论如何,它似乎不允许声明x :: zs,因为Visual Studio给我一个警告。
表达式x::zs
是允许的,但Visual Studio试图告诉你它没有任何作用。 x::zs
创建一个新的列表,但然后立即将其丢弃( 不发生变异的存在价值!)。
根据所提供的代码的其余部分, zs
应该包含列表中的前半部分,但zs
只会包含空列表[]
因为这是它被分配到唯一的价值。 在像C#这样的语言中,你只需通过追加它来改变列表,但是在F#中,你不应该那样做。 既然你已经在使用递归,这是一个迹象表明, zs
应该是递归函数的一个参数,以便你可以在以后使用新值。 (我发现有些人理解递归更好,如果他们认为它作为一个回调。当你递归,它就像一个回调函数提供参数。需要作为参数来提供你想在递归过程中积累的任何值你的功能。)
把这一切放在一起,我想你想要的是这样的:
let rec cut(xs, ys, zs) =
match xs, ys with
| xs, ([] | [_]) -> (xs, zs)
| [], _ -> ([], [])
| x::xs, y1::y2::ys ->
cut (xs, ys, x::zs)
通常情况下,您会将此函数隐藏在一个非递归函数中,该函数正确设置您的参数:
let cut(xs, ys) =
let rec impl(xs, ys, zs) =
match xs, ys with
| xs, ([] | [_]) -> (xs, zs)
| [], _ -> ([], [])
| x::xs, y1::y2::ys ->
impl (xs, ys, x::zs)
impl(xs, ys, [])
注意:有没有必要使用,
s到单独的参数在F#。 当你这样做时,你实际上是在声明一个函数有一个由元组组成的参数。 这通常不是你想要的,它可以防止卷曲功能。 所有你需要用来分隔参数是空格:
let cut xs ys =
let rec impl xs ys zs =
match xs, ys with
| xs, ([] | [_]) -> (xs, zs)
| [], _ -> ([], [])
| x::xs, y1::y2::ys ->
impl xs ys (x::zs)
impl xs ys []
通过添加另一个将缓慢项目生成到列表中的累加器值,可以实现此操作:
let cut l =
let rec loop acc rem =
match rem with
| xs, ([] | [_]) -> List.rev acc, xs
| [], _ -> [], []
| x::xs, y::y'::ys -> loop (x::acc) (xs, ys)
loop [] (l, l)
> cut [1;2;3;4;5;6]
([1; 2; 3], [4; 5; 6])
链接地址: http://www.djcxy.com/p/80593.html
下一篇: Recursion in F#, expected type int but got type "int list