将列表拆分为 2 个奇数和偶数位置列表 - SML?
Split list into 2 lists of odd & even positions - SML?
我需要编写一个接受列表并将其拆分为 2 个列表的函数。第一个列表将元素放在奇数位置,第二个列表将元素放在偶数位置。这是我的尝试,它给了我以下警告:
警告:类型变量未泛化,因为
值限制被实例化为虚拟类型 (X1,X2,...)
如何改进?
fun splt (lst: int list) =
let
fun splt2 (lst: int list, count: int, lst1: int list, lst2: int list) =
if null lst
then []
else if (count mod 2 = 0)
then splt2 (tl lst, count+1, hd lst::lst1, lst2)
else splt2 (tl lst, count+1, lst1, hd lst::lst2)
in
splt2 (lst,1,[],[])
end
这是我找到的第二个正确实现,但我主要对修复第一个感兴趣!!
I want to split a list into a tupple of odd and even elements
fun split [] = ([], [])
| split [x] = ([x], [])
| split (x1::x2::xs) =
let
val (ys, zs) = split xs
in
((x1::ys), (x2::zs))
end;
更新:改进只是替换
if null lst then
[]
有了这个:
if null lst then
[lst1]@[lst2]
帮助您克服遇到的错误
你需要看看你给的函数的类型
val splt = fn : int list -> 'a list
并问问自己“列表包含什么?
- val foo = "foo"::(splt[1,2,3,4,5]);
val foo = ["foo"] : string list
- val bar = 52::splt[1,2,3,4,5];
val bar = [52] : int list
它可以容纳任何东西,但编译器自己无法判断。
以下是对您的代码的一些反馈:
- 为函数取一个合适的名称,例如
split
或 partition
。我对这些名字的含义是:Splitting(或exploding)需要一些东西并且returns one list of sub-components (e.g. string → char list),而 partitioning 将某物的列表分成两部分基于谓词(例如 List.partition
),但它们并不是一成不变的。
- 编造一些不是
lst
的变量名,因为这只是类型的缩写 - 即使有类型也肯定是多余的。对于泛型方法,好名字可能很难获得。许多 ML 代码使用 xs
之类的东西来暗示通用的复数形式。
放弃类型注释;你会得到一个更容易阅读的多态函数:
fun split input =
let
fun split' (xys, count, xs, ys) = ...
in
split' (input, 1, [], [])
end
但实际上,您在网上找到的版本有一些优点:模式匹配可确保您的列表在触发函数体之前具有正确的形式,从而最大限度地减少 run-time 错误。函数 hd
和 tl
没有。
您可以稍微优化一下案例的顺序;即首先列出最常见的情况。 x::xs
和 y::ys
周围的括号是不必要的。此外,为了简洁起见,可以合并其他两种情况(一个或零个元素),但这并不重要。
fun split (x1::x2::xs) =
let
val (ys, zs) = split xs
in
(x1::ys, x2::zs)
end
| split rest = (rest, [])
您也可以使用 case-of 而不是 let-in-end:
fun split (x1::x2::xs) =
(case split xs of
(ys, zs) => (x1::ys, x2::zs))
| split rest = (rest, [])
最后,你可能想制作这个功能tail-recursive:
fun split xys =
let fun split' (x1::x2::xs, ys, zs) = split' (xs, x1::ys, x2::zs)
| split' (rest, ys, zs) = (rev (rest @ ys), rev zs)
in
split' (xys, [], [])
end
我需要编写一个接受列表并将其拆分为 2 个列表的函数。第一个列表将元素放在奇数位置,第二个列表将元素放在偶数位置。这是我的尝试,它给了我以下警告:
警告:类型变量未泛化,因为 值限制被实例化为虚拟类型 (X1,X2,...)
如何改进?
fun splt (lst: int list) =
let
fun splt2 (lst: int list, count: int, lst1: int list, lst2: int list) =
if null lst
then []
else if (count mod 2 = 0)
then splt2 (tl lst, count+1, hd lst::lst1, lst2)
else splt2 (tl lst, count+1, lst1, hd lst::lst2)
in
splt2 (lst,1,[],[])
end
这是我找到的第二个正确实现,但我主要对修复第一个感兴趣!! I want to split a list into a tupple of odd and even elements
fun split [] = ([], [])
| split [x] = ([x], [])
| split (x1::x2::xs) =
let
val (ys, zs) = split xs
in
((x1::ys), (x2::zs))
end;
更新:改进只是替换
if null lst then
[]
有了这个:
if null lst then
[lst1]@[lst2]
帮助您克服遇到的错误 你需要看看你给的函数的类型
val splt = fn : int list -> 'a list
并问问自己“列表包含什么?
- val foo = "foo"::(splt[1,2,3,4,5]);
val foo = ["foo"] : string list
- val bar = 52::splt[1,2,3,4,5];
val bar = [52] : int list
它可以容纳任何东西,但编译器自己无法判断。
以下是对您的代码的一些反馈:
- 为函数取一个合适的名称,例如
split
或partition
。我对这些名字的含义是:Splitting(或exploding)需要一些东西并且returns one list of sub-components (e.g. string → char list),而 partitioning 将某物的列表分成两部分基于谓词(例如List.partition
),但它们并不是一成不变的。 - 编造一些不是
lst
的变量名,因为这只是类型的缩写 - 即使有类型也肯定是多余的。对于泛型方法,好名字可能很难获得。许多 ML 代码使用xs
之类的东西来暗示通用的复数形式。 放弃类型注释;你会得到一个更容易阅读的多态函数:
fun split input = let fun split' (xys, count, xs, ys) = ... in split' (input, 1, [], []) end
但实际上,您在网上找到的版本有一些优点:模式匹配可确保您的列表在触发函数体之前具有正确的形式,从而最大限度地减少 run-time 错误。函数
hd
和tl
没有。您可以稍微优化一下案例的顺序;即首先列出最常见的情况。
x::xs
和y::ys
周围的括号是不必要的。此外,为了简洁起见,可以合并其他两种情况(一个或零个元素),但这并不重要。fun split (x1::x2::xs) = let val (ys, zs) = split xs in (x1::ys, x2::zs) end | split rest = (rest, [])
您也可以使用 case-of 而不是 let-in-end:
fun split (x1::x2::xs) = (case split xs of (ys, zs) => (x1::ys, x2::zs)) | split rest = (rest, [])
最后,你可能想制作这个功能tail-recursive:
fun split xys = let fun split' (x1::x2::xs, ys, zs) = split' (xs, x1::ys, x2::zs) | split' (rest, ys, zs) = (rev (rest @ ys), rev zs) in split' (xys, [], []) end