【问题标题】:computes the length of list which contains list (SML)计算包含列表 (SML) 的列表的长度
【发布时间】:2023-09-16 20:01:01
【问题描述】:

SML 长度函数:

fun length(L) =
    if (L=nil) then 0
    else 1+length(tl(L));

例如:

length [1,2,3] = 3;
length [ [5], [4], [3], [2,1] ] = 4;

根据代码,如果我也想统计列表中的元素,怎么改?

例如:

length [ [5], [4], [3], [2,1] ] = 5;

【问题讨论】:

    标签: sml smlnj ml


    【解决方案1】:

    你可以创建另一个函数来使用你的函数,如下所示:

    fun d_length ( [] ) = 0
    | d_length ( l :: l' ) = length(l) + d_length(l');
    
    d_length[ [5], [4], [3], [2,1] ];
    

    或者,使用内置 reducer:

    List.foldl (fn(e,a) => length(e) + a) 0 [ [5], [4], [3], [2,1] ];
    

    【讨论】:

      【解决方案2】:

      您不想进行比较L=nil,因为这仅适用于可比较的类型列表(例如,不是函数列表)。相反,您需要 Kevin Johnson 建议的模式匹配;

      fun length [] = 0
        | length (x::xs) = 1 + length xs
      

      或者使用尾递归:

      fun length xs =
          let fun len [] n = n
                | len (x::xs) n = len xs (1+n)
          in len xs 0 end
      

      length : 'a list -> int不同,此函数的类型为'a list list -> int

      所有子列表的组合长度可以通过多种方式实现。例如

      fun length2 xss = List.foldl op+ 0 (List.concat xss)
      

      但是正如凯文的回答也利用了,当我们所做的只是稍后再次销毁它时,用List.concat xss 建立一个新列表真的没有任何意义。所以无耻地撕毁他的解决方案:

      fun length2 xss = List.foldl (fn (xs, sum) => length xs + sum) 0 xss
      

      这也可能是表达该函数的最易读的方式,但是如果您要尝试 code golf 该函数非常短,您还可以使用高阶函数重写内部闭包:

      fun curry f x y = f (x, y)
      fun uncurry f (x, y) = f x y
      fun length2 xss = List.foldl (uncurry (curry op+ o length)) 0 xss
      

      【讨论】:

      • 我花了几分钟才明白你用咖喱/非咖喱做了什么。这很聪明。
      • 如果 foldlop+ 默认被柯里化并且没有 Value Restriction 会更聪明。然后是val length2 = foldl (op+ o length) 0!
      • 我在玩这个游戏时肯定遇到过几次价值限制。在 Haskell 中,您可以(我认为)以无点的方式完成这一切,但 SML 使得使用 o 很难建立很多东西
      【解决方案3】:

      这是一个模式匹配的直接递归版本,它不使用内置的length 函数,而是直接计算总长度(“tol”):

      fun tol [] = 0
      |   tol ([]::xss) = tol xss
      |   tol ((x::xs)::xss) = 1 + tol (xs::xss);
      

      最后一个子句中括号的顺序很重要。它覆盖了:: 的右关联性,因此(x::xs)::xss 中的x 被解释为xss 中第一个列表的头部,而不是xss 本身的头部。

      这些答案的模式似乎是以折叠结束,我不想打破模式。这是一个折叠,它将通过将长度映射到列表列表而获得的列表折叠成总和:

      fun tol xss = foldl op+ 0 (map length xss);
      

      【讨论】: