Functional programming 嵌套模式匹配-SML-逐步通过一个示例,非常混乱

Functional programming 嵌套模式匹配-SML-逐步通过一个示例,非常混乱,functional-programming,sml,Functional Programming,Sml,我试图理解模式匹配和递归以及程序是如何执行的 在一个简单的例子中: fun sum_list_num xs = case xs of [] => NONE | x::xs' => case (sum_list_num xs') of NONE => (print "x: "; print (Int.toString x); print "\n"; SOM

我试图理解模式匹配和递归以及程序是如何执行的

在一个简单的例子中:

fun sum_list_num xs =
  case xs of
      [] => NONE 
    | x::xs' => case (sum_list_num xs') of
                    NONE => (print "x: "; print (Int.toString x); 
                             print "\n"; SOME x)
                  | SOME y => (print "x: "; print (Int.toString x);
                               print " y: "; print (Int.toString y); print"\n";
                               SOME (x+y))
我可以看到
SOME y y
中的
y1
基本上起到累加器的作用,因为上面返回的是
sum_list_num[1,2,3,4,5]

x: 5
x: 4 y: 5
x: 3 y: 9
x: 2 y: 12
x: 1 y: 14
val it = SOME 15 : int option
我这样想是对的还是我没有抓住重点?

现在来看一个更高级的例子,我正试图了解模式匹配,我遇到了,但我不能理解它是如何工作的。我修改了函数以打印出每次“匹配”时发生的情况:

fun smatch (str, in_stringlist) = 
  case in_stringlist of
      [] => NONE
    | x::x' => case(same_string(x, str), smatch (str, x')) of
                   (true, _) => (print "MATCH CASE x: "; print x; 
                                  print " x': "; print(gather(x'));
                                 print "\n"; SOME x')
                 | (false, NONE) => (print "NONE CASE x: ";print x;
                                     print "\n"; NONE)
                 | (false, SOME z) => (print "SOME Z CASE x: "; print x;
                                       print " z: ";print(gather(z));
                                       print " x': ";print(gather(x'));print "\n";  
                                       SOME (x :: z))
当使用
smatch(“this”、[“1”、“2”、“this”、“4”、“5”、“6”)调用时,我完全没有预料到的输出。

我迷路的地方:

  • 为什么我在匹配案例中返回
    x'
  • 为什么我要查找的字符串后面的列表中的所有内容都计算为NONE
  • 我一直坐在这里,拿着一张便笺和许多编辑,我很难“跟踪”递归调用的堆叠和计算过程中到底发生了什么
任何帮助都将不胜感激。整天阅读有关模式匹配的SML指南并没有使这一点变得更清楚

注意:第二个例子是Coursera类的一个家庭作业问题(我用一个let函数回答了这个问题,该函数使用累加器来构建列表,而不是嵌套的case语句,我在谷歌搜索模式匹配SML时遇到了上述问题,我整天都在试图解决它)

FYI gather只是一个辅助函数,因此我可以打印字符串列表的内容:

fun gather xs = 
  foldl (fn (x,acc) =>
            acc  ^ " " ^ x) (hd xs) (tl xs)
我可以看到
somey y
中的
y1
基本上起着累加器的作用

我这样想是对的还是我没有抓住重点?

是的,你说得对

sum\u list\u num
函数递归调用自身并将累积结果返回给自身。由于结果被包装在
SOME
/
NONE
中,因此使用模式匹配将结果解包并再次打包到
SOME
中。例如,
SOME y
变成
SOME(x+y)

返回int选项似乎有点多余,因为空列表的和定义良好:

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

但对于某些问题,您确实希望在结果
some
/
NONE
上进行模式匹配,然后将结果打包回去。在这些情况下,您可能还需要考虑使用库函数<代码>选项.map < /COD>和<代码>选项.GETopt < /C>。例如:

fun maximum [] = NONE
  | maximum [x] = SOME x
  | maximum (x::xs) = Option.map (fn y => Int.max (x, y)) (maximum xs)
继续

为什么我在匹配案例中返回
x'

一个更好的问题可能是:这个函数在做什么?从那时起,答案的一部分可能是“…并返回列表的其余部分(
x'
)”。我认为,这段代码中有一部分很难阅读,那就是在每个循环迭代中,在案例主体之前,对
smatch(str,x')
求值,而不管是否使用其返回值

通过首先处理输入列表的尾部,它被向后处理(无论是设计还是意外)

为什么列表中我要查找的字符串后面的所有内容都计算为
NONE
情况

这可能最好通过手动评估函数以获得小的输入来表现。每次我写
~>
,我都会计算下一个术语(在函数运行之前的输入,或者如果函数的所有输入都已计算,则为函数调用)。前几个术语重写为:

smatch ("2", ["1", "2", "3"]) ~>
  case (same_string("2", "1"), smatch ("2", ["2", "3"])) of ... ~>
  case (false, smatch ("2", ["2", "3"])) of ... ~>
  case (false, case (same_string("2", "2"), smatch ("2", ["3"])) of ...) of ... ~>
  case (false, case (true, case (same_string ("2", "3"), smatch ("2", [])) of ...) of ...) of ... ~>
  case (false, case (true, case (false, smatch ("2", [])) of ...) of ...) of ... ~>
  case (false, case (true, case (false, NONE) of ...) of ...) of ...
此时,列表已被完全遍历,最后一个元素已被确定为不是
“2”
,语句的第一个实例(它所匹配的语句对(
(false,NONE)
)实际上正在进行比较。我们继续

  case (false, case (true, (print "NONE CASE x: ";print x; print "\n"; NONE)) of ...) of ... ~>
  case (false, case (true, NONE) of ...) of ... ~>
  case (false, (print "MATCH CASE x: "; print x;  print " x': "; print(gather(x')); print "\n"; SOME ["3"])) of ... ~>
  case (false, SOME ["3"]) of ... ~>
此时,首先匹配
(false,NONE)
模式案例,然后匹配
(true,)
模式,最后匹配
(false,SOME z)
模式:

(print "SOME Z CASE x: "; print x; print " z: "; print(gather(z)); print " x': "; print(gather(x')); print "\n"; SOME ("1" :: "3")) ~>
SOME ["1", "3"]
我一直坐在这里,拿着一张便笺和许多编辑,我很难“跟踪”递归调用的堆叠和计算过程中到底发生了什么

除了手工评估你的函数(当你的术语重写导致大量的错误时,这是很困难的),您可以对代码进行不同的结构,以便在实际元素之前计算列表的尾部时更为明显。似乎也不需要嵌套模式匹配。既然此函数实际上只是过滤掉
str
的第一个实例,为什么不这样写呢:

fun smatch (str, []) = []
  | smatch (str, str2::strs) =
    if str = str2
    then strs
    else str2::smatch(str, strs)
此功能更易于手动评估:

smatch ("2", ["1", "2", "3"]) ~>
  if "2" = "1" then ... else "1"::smatch("2", ["2", "3"]) ~>
  "1"::smatch("2", ["2", "3"]) ~>
  "1"::(if "2" = "2" then ["3"] else ...) ~>
  "1"::["3"]
  ["1", "3"]

顺便说一句,标准库中已经存在您的聚集函数,其名称为
String.concatWith”“

,这对于帮助我了解引擎盖下发生的事情以及对标准库的引用非常有用!
(print "SOME Z CASE x: "; print x; print " z: "; print(gather(z)); print " x': "; print(gather(x')); print "\n"; SOME ("1" :: "3")) ~>
SOME ["1", "3"]
fun smatch (str, []) = []
  | smatch (str, str2::strs) =
    if str = str2
    then strs
    else str2::smatch(str, strs)
smatch ("2", ["1", "2", "3"]) ~>
  if "2" = "1" then ... else "1"::smatch("2", ["2", "3"]) ~>
  "1"::smatch("2", ["2", "3"]) ~>
  "1"::(if "2" = "2" then ["3"] else ...) ~>
  "1"::["3"]
  ["1", "3"]