【问题标题】:How does SML pattern matching records workSML 模式匹配记录如何工作
【发布时间】:2021-09-14 04:13:13
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

    标签: functional-programming sml


    【解决方案1】:

    SML 没有行多态性,所以编译器需要知道一条记录的所有字段名。

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

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

    【讨论】:

      【解决方案2】:

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

      我希望这里显示的想法可以帮助您。好好学习!

      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
      

      【讨论】:

        猜你喜欢
        • 2017-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-29
        • 2019-01-19
        • 2023-04-05
        • 2021-06-01
        • 2012-09-02
        相关资源
        最近更新 更多