使用 "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);
我的函数工作正常,但我不知道如何重新组合所有这些行
正确
模式匹配的美妙之处在于它经常避免辅助函数,如 head
和 tail
。
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 的评论,谢谢。
我在将这些代码行组合成一个函数时遇到问题
sumFirstEven : int * int seq -> int
使得sumFirstEven (5, s)
是序列s
有人告诉我,我需要将我的行分组到一个包含 "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);
我的函数工作正常,但我不知道如何重新组合所有这些行 正确
模式匹配的美妙之处在于它经常避免辅助函数,如 head
和 tail
。
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 的评论,谢谢。