2011-10-17 67 views
8

我在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,这需要一个字符串列表清单(字符串,换人名单列表)和一个字符串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

+10

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

回答

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) 

如果速度并不重要,那么你可以在第一个功能两种情况合并:

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功能?您可以直接进行比较。除非你打算在某些时候用一些特殊的逻辑来交换它,否则使用辅助函数是很奇怪的。然而你的函数名称并不能解决这个问题。

+0

当我尝试顶部的代码块,我得到编译错误说'错误:运算符不是一个函数' - 好像all_except_options(s,x)部分不能从get_substitutions1(x :: xs, s)块。如何告诉sml NONE和SOME是all_except_options返回的内容的情况,而不是get_substitutions的情况? – Sekm

+2

你可以说“有趣的关键字分解了这两个功能”。它的工作原理是SML/NJ 110.72,所以无论你是使用另一个解释器还是你做错了什么。你可以把嵌套的case表达式放在括号内。但是,您收到的错误消息听起来不像是与案件有什么关系? –

+0

@ Jesper.Reenberg我知道这是一个古老的线程,但我试图在'all_except_option'中找出'Some'中的内容。如果将其切换为返回SOME(x ::“wtf”:: y),您可以看到它在匹配字符串之前在所有元素上运行,但在匹配字符串之后没有在任何元素上运行。如果y包含列表的其余部分,为什么我看不到重复的列表?我很难用一张纸来“解决”这个问题,并且跟踪每个步骤中某些实际指向的内容。 – mat4nier

1

除了什么Jesper.Reenberg提到的,我只是想提一提,在booltruefalse匹配可以用if替代 - then - else。但是,有些人认为,如果 - 那么比案例陈述更丑陋

+1

没错,我想我就是其中一个人:) –

0
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 
+0

总是有空间来优化“if .. then true else false”:-) – ShiDoiSi