Заявления случая и сопоставление с образцом - PullRequest
7 голосов
/ 17 октября 2011

Я пишу код в 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

Ответы [ 3 ]

9 голосов
/ 17 октября 2011

Прежде всего я бы начал использовать сопоставление с образцом в определении функции вместо того, чтобы иметь "верхний уровень" оператора 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 (@), во второй функции, и так как она не хвост рекурсивный, я не верю, что это твоя главная проблема. Имейте в виду, что 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? Вы можете просто сделать сравнение напрямую вместо этого. Использование вспомогательной функции просто странно, если вы не планируете в какой-то момент заменить ее какой-то специальной логикой. Однако названия ваших функций этого не говорят.

1 голос
/ 18 октября 2011

В дополнение к тому, что упомянул Jesper.Reenberg, я просто хотел упомянуть, что совпадение на bool для true и false можно заменить на if - then - else. Тем не менее, некоторые люди считают, если-то-еще страшнее, чем заявление дела

0 голосов
/ 01 февраля 2013
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
...