将列表拆分为2个奇数和列表甚至职位 - SML?

时间:2017-01-29 04:22:24

标签: functional-programming sml ml

我需要编写一个获取列表并将其拆分为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]

2 个答案:

答案 0 :(得分:2)

以下是您的代码的一些反馈:

  • 为该函数指定一个正确的名称,例如splitpartition。我对这些名称的含义是:拆分(或爆炸)取一些东西并返回一个子组件列表(例如 string→char list ),而 partitioning 会根据谓词(例如List.partition)获取某些内容并分成两部分,但它们并未真正设置在石。
  • 组成一些不是lst的变量名,因为这只是该类型的缩写 - 即使是那种类型也肯定是多余的。对于通用方法,很难找到好名字。许多ML代码使用像xs之类的东西来表示通用的复数形式。
  • 抛弃类型注释;你会得到一个更容易阅读的多态函数:

    fun split input =
        let
          fun split' (xys, count, xs, ys) = ...
        in
          split' (input, 1, [], [])
        end
    
  • 但实际上,您在网上找到的版本有一些优点:模式匹配可确保您的列表在触发函数体之前具有正确的形式,从而最大限度地减少运行时错误。函数hdtl没有。

  • 您可以稍微优化案件的顺序;即首先列出最常见的案例。 x::xsy::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, [])
    
  • 最后,您可能希望将此函数设置为尾递归:

    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
    

答案 1 :(得分:1)

帮助您解决遇到的错误 你需要查看你给出的函数类型

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

它可以容纳任何东西,但编译器无法自行判断。