SML 模式匹配记录如何工作

How does SML pattern matching records work

免责声明,这是在线课程的一部分,但我已经解决了作业。我的问题是关于记录工作的模式匹配?

所以在第一个函数中我不必指定记录的结构

fun generateName (ls , name)=
case ls of
[] => name::[]
  | x::xs =>
{
  first= x,
  middle= #middle name,
  last= #last name
}
:: generateName(xs, name);

在这个函数中我做。否则我会收到 flex 记录错误。

fun createName (f, name :{first:string, middle:string, last:string}) =
case f of
x =>
{
  first= x,
  middle= #middle name,
  last= #last name
}

更令人困惑的是这个没有错误

fun generateName2 (nms, name) =
let fun aux (ls, name, acc) =
    case ls of
        [] => name::acc
      | x::xs =>
        aux(xs, name, 
        {
          first= x,
          middle= #middle name,
          last= #last name
        } :: acc)
in
aux (nms, name, [])
end

我什么时候必须指定记录字段?

SML 没有行多态性,因此编译器需要知道记录的所有字段名称。

在return列出的函数中,递归限制了可能的类型;如果name的类型为RgenerateName (ls , name)的类型为R list,所有的字段名都可以从非空递归的情况下推断出来。

中间的例子在输入和输出之间没有这样的关系,所以除非你指定输入字段名称,否则 SML 不知道它们是什么。

@molbdniloo 的回答很好。因为我坚信充分利用编程语言的优点可以使代码更易于推理,所以让我们稍微清理一下您的代码示例。理论上这属于评论,但不太适合这个级别的评论。

希望这里展示的思路能对您有所帮助。好好学习!

fun generateName (ls , name)=
case ls of
[] => name::[]
  | x::xs =>
{
  first= x,
  middle= #middle name,
  last= #last name
}
:: generateName(xs, name);

当我们看到 case 作为函数体中的第一件事,并且它只是作用于其中一个参数时,我们可以在函数签名本身中使用模式匹配。

fun generateName([] , name) = name :: []
  | generateName(x::xs, name) = 
      { first = x,
        middle = #middle name,
        last = #last name } :: generateName(xs, name);

我们还可以进一步使用模式匹配来消除在函数体内提取记录字段的需要。

fun generateName([] , name) = name :: []
  | generateName(x::xs, name as {first:string, middle:string, last:string}) = 
      { first = x,
        middle = middle,
        last = last } :: generateName(xs, name);

在你的第二个例子中,模式匹配一​​个参数只有一个包罗万象的模式是没有意义的。我们可以摆脱它。

fun createName (f, name :{first:string, middle:string, last:string}) =
  { first = f,
    middle = #middle name,
    last = #last name }

如果我们将其作为模式提供,则无需指定类型。

fun createName (f, {first:string, middle:string, last:string}) =
  { first = f,
    middle = middle,
    last = last }

您的第三个代码示例也可以从这些想法中受益。

fun generateName2(nms, name) =
  let 
    fun aux([], name, acc) = name :: acc
      | aux(x::xs, name as { first:string, middle:string, last:string }, acc) =
          aux(xs, name, 
              { first = x,
                middle = middle,
                last = last } :: acc)
  in
    aux(nms, name, [])
  end