【问题标题】:Case Statements and Pattern Matching案例陈述和模式匹配
【发布时间】:2013-11-28 00:41:27
【问题描述】:

我正在使用 SML 进行作业编码,并且我已经完成了一些练习题,我觉得我错过了一些东西 - 我觉得我使用了太多 case 语句。这是我正在做的事情以及我遇到的问题的问题陈述。:

  1. 编写一个函数 all_except_option,它接受一个字符串和一个字符串列表。如果字符串不在列表中,则返回 NONE,否则返回 SOME lst,其中 lst 类似于参数列表,但字符串不在列表中。

    fun all_except_option(str : string, lst : string list) =
      case lst of 
       [] => NONE
      | x::xs => case same_string(x, str) of
                   true => SOME xs
                 | false => case all_except_option(str, xs) of
                              NONE => NONE
                            | SOME y=> SOME (x::y)  
    
  2. 编写一个函数get_substitutions1,它接受一个字符串列表list(一个字符串列表,替换的列表)和一个字符串s,并返回一个字符串列表。结果包含在替换列表中的所有字符串也有 s,但 s 本身不应该在结果中。

    fun get_substitutions1(lst : string list list, s : string) = 
      case lst of
        [] => []
      | x::xs => case all_except_option(s, x) of
                     NONE => get_substitutions1(xs, s)
                    | SOME y => y @ get_substitutions1(xs, s)
    

- same_string 是一个提供的函数, fun same_string(s1 : string, s2 : string) = s1 = s2

【问题讨论】:

  • 这是 Coursera 编程语言课程第 2 周作业的一部分。由于在线发布解决方案是违规行为,我要求重新措辞这个问题以更改函数名称,使其与分配不完全匹配。

标签: functional-programming pattern-matching case sml


【解决方案1】:

首先我会开始在函数定义中使用模式匹配 而不是有一个“顶级”案例陈述。它基本上归结为 脱糖后也一样。此外,除非严格需要,否则我会摆脱显式类型注释:

fun all_except_option (str, []) = NONE
  | all_except_option (str, x :: xs) =
    case same_string(x, str) of
      true  => SOME xs
    | false => case all_except_option(str, xs) of
                 NONE   => NONE
               | SOME y => SOME (x::y)

fun get_substitutions1 ([], s) = []
  | get_substitutions1 (x :: xs, s) =
    case all_except_option(s, x) of
      NONE   => get_substitutions1(xs, s)
    | SOME y => y @ get_substitutions1(xs, s)

如果速度不重要,那么您可以在第一个函数中合并这两种情况:

fun all_except_option (str, []) = NONE
  | all_except_option (str, x :: xs) =
    case (same_string(x, str), all_except_option(str, xs)) of
      (true, _)       => SOME xs
    | (false, NONE)   => NONE
    | (false, SOME y) => SOME (x::y)

但是由于您在第二个函数中使用了追加(@),并且因为它不是 尾递归,我不认为这是您的主要关注点。请记住, append 是潜在的“邪恶”,你应该几乎总是使用连接(和 然后在返回结果时反转结果)并在可能的情况下进行尾递归(它 总是)。

如果你真的喜欢显式类型注释,那么你可以这样做:

val rec all_except_option : string * string list -> string list option  =
 fn (str, []) => NONE
  | (str, x :: xs) =>
    case (same_string(x, str), all_except_option(str, xs)) of
      (true, _)       => SOME xs
    | (false, NONE)   => NONE
    | (false, SOME y) => SOME (x::y)


val rec get_substitutions1 : string list list * string -> string list =
 fn ([], s) => []
  | (x :: xs, s) =>
    case all_except_option(s, x) of
      NONE   => get_substitutions1(xs, s)
    | SOME y => y @ get_substitutions1(xs, s)

但这只是我的首选方式,如果我真的必须添加类型注释。

顺便问一下,你到底为什么有same_string 功能?您可以直接进行比较。使用辅助功能只是很奇怪,除非你打算在某个时候用一些特殊的逻辑来交换它。但是,您的函数名称并不暗示这一点。

【讨论】:

  • 当我尝试顶部代码块时,我收到编译错误,提示“错误:运算符不是函数” - 似乎 all_except_options(s, x) 部分无法与get_substitutions1 (x :: xs, s) 块。我如何告诉 sml NONE 和 SOME 是 all_except_options 返回的情况,而不是 get_substitutions 的情况?
  • 您可以说“fun 关键字分解了这两个功能”。它在 SML/NJ 110.72 中工作,所以要么您使用另一个解释器,要么您做错了什么。您可以将嵌套的 case 表达式放在括号内。但是,您收到的错误消息听起来与案件无关?
  • @Jesper.Reenberg 我知道这是一个旧线程,但我想弄清楚all_except_option 中的SOME y 中的内容。如果您将其切换为返回 SOME (x::"wtf"::y) 您可以看到它在匹配字符串之前在所有元素上运行,但在字符串匹配后不在任何元素上运行。如果 y 包含列表的其余部分,为什么我看不到列表重复?我很难用一张纸“逐步”解决这个问题,并在每一步跟踪一些 y 实际指向的内容。
【解决方案2】:

除了 Jesper.Reenberg 提到的之外,我只想提一下,truefalse 上的匹配可以替换为 if-then-else。但是,有些人认为 if-then-else 比 case 语句更丑

【讨论】:

  • 没错,我想我就是其中之一 :)
【解决方案3】:
fun same_string( s1: string, s2: string ) = if String.compare( s1, s2 ) = EQUAL then true else false


fun contains( [],   s: string ) = false
|   contains( h::t, s: string ) = if same_string( s, h ) then true else contains( t, s )


fun all_except_option_successfully( s: string, [] )   = []
|   all_except_option_successfully( s: string, h::t ) = if same_string( s, h ) then t else ( h :: all_except_option_successfully( s, t ) )


fun all_except_option( s: string, [] )   = NONE
|   all_except_option( s: string, h::t ) = if same_string( s, h ) then SOME t else if contains( t, s ) then SOME ( h :: all_except_option_successfully( s, t ) ) else NONE

【讨论】:

  • 总有优化“if .. then true else false”的空间:-)
猜你喜欢
  • 1970-01-01
  • 2014-09-28
  • 2021-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 2010-10-30
  • 2016-05-13
  • 2016-02-21
相关资源
最近更新 更多