使用 "let" 命令将 sml/ml 中的多个代码行合并为一个函数

Unite multiple code lines into one function in sml/ml using "let" command

我在将这些代码行组合成一个函数时遇到问题

sumFirstEven : int * int seq -> int

使得sumFirstEven (5, s)是序列s

的前5个偶数元素之和

有人告诉我,我需要将我的行分组到一个包含 "let-in commands"

的函数中

这些是我对这些功能的台词:

datatype 'a seq=null|SEQ of 'a*(unit->'a seq);

fun head(SEQ(x,_))=x
|head null=raise Empty;

fun tail(SEQ(_,xf))=xf()
|tail null=raise Empty;


fun sumFirstEven(0,_)=0
|sumFirstEven(n,null)=0
|sumFirstEven(n,xs)=if(head(xs) mod 2=0)then head(xs)+sumFirstEven(n-1,tail(xs))
else sumFirstEven(n,tail(xs));

fun seqFrom i=SEQ(i,fn()=>seqFrom(i+1));
val seqStart=seqFrom 1;

sumFirstEven(5,seqStart);

我的函数工作正常,但我不知道如何重新组合所有这些行 正确

模式匹配的美妙之处在于它经常避免辅助函数,如 headtail

fun sumFirstEven (0, _) = 0
  | sumFirstEven (_, null) = 0
  | sumFirstEven (n, SEQ (h, t)) =
      case h mod 2
        of 0 => h + sumFirstEven (n-1, t ())
         | _ => sumFirstEven (n, t ())

由于前两个子句不匹配,所以在第三个子句中没有必要调用具有失败条件的函数,例如 head...我们已经知道数据是正确的形式!

函数子句中的模式匹配与 let-in-end 表达式(不是命令!)的作用相同。

鉴于您的惰性列表类型,

datatype 'a seq = Null | Seq of 'a * (unit -> 'a seq)

您可能需要辅助功能,

fun even n = n mod 2 = 0

您可能想要手动递归,

fun sumFirstEven (0, _) = 0
  | sumFirstEven (_, Null) = 0
  | sumFirstEven (n, Seq (x, seqf) =
      if even x
      then x + sumFirstEven (n-1, seqf ())
      else sumFirstEven (n, seqf ())

或者您可能希望将结果累加到函数参数中,

fun sumFirstEven (n, seq) =
    let fun sfe (0, _, result) = result
          | sfe (_, Null, result) = result
          | sfe (n, Seq (x, seqf), result) =
              if even x
              then sfe (n-1, seqf (), result + x)
              else sfe (n, seqf (), result)
    in sfe (n, seq, 0) end

使其尾递归(即使用固定数量的堆栈帧)。更方便的是,您可能希望将函数的递归部分提取到单独的高阶折叠组合器中,

fun foldseqn _ e 0 _ = e
  | foldseqn _ e _ Null = e
  | foldseqn f e n (Seq (x, seqf)) =
      case f (x, e) of
          (e', true) => foldseqn f e' (n-1) (seqf ())
        | (e', false) => foldseqn f e' n (seqf ())

fun sumFirstEven (n, seq) =
      foldseqn (fn (x, sum) => if even x
                               then (sum + x, true)
                               else (sum, false)) 0 n seq

还有一个快速测试,

fun nats n = Seq (n, fn () => nats (n+1))
val twelve = sumFirstEven (3, nats 1) (* 2+4+6 *)

编辑: 回复了 Nick 的评论,谢谢。