案例陈述和模式匹配

use*_*876 7 functional-programming case sml pattern-matching

我正在用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)  
    
    Run Code Online (Sandbox Code Playgroud)
  2. 编写一个函数get_substitutions1,它接受一个字符串列表列表(字符串列表,替换列表)和一个字符串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)
    
    Run Code Online (Sandbox Code Playgroud)

- same_string是提供的功能, fun same_string(s1 : string, s2 : string) = s1 = s2

Jes*_*erg 9

首先,我将开始在函数定义中使用模式匹配,而不是使用"顶级"case语句.去糖后它基本上归结为同样的东西.除非严格要求,否则我会删除显式类型注释:

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)
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

但是因为你在第二个函数中使用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)
Run Code Online (Sandbox Code Playgroud)

但这只是我的首选方式,如果我真的需要添加类型注释.

顺便说一下,为什么你有这个same_string功能呢?您可以直接进行比较.除非你打算在某些时候用一些特殊的逻辑来交换它,否则使用辅助功能是很奇怪的.但是,您的函数名称不会消耗它.

  • 你可以说"有趣的关键字打破了这两个功能".它适用于SML/NJ 110.72,所以要么你正在使用另一个解释器,要么你做错了什么.您可以将嵌套的case表达式放在括号内.但是,您收到的错误消息听起来与案件有什么关系? (2认同)