【问题标题】:How to return a SOME list instead of a normal list?如何返回一些列表而不是普通列表?
【发布时间】:2021-01-14 22:49:46
【问题描述】:
fun all_except_option ("string",["he","she","string"]) = SOME["he","she"]

我设法让它工作,但没有选项类型,我不知道如何让它返回 SOME list 而不是一个普通列表。

fun all_except_option(str,lst)=
    case lst of
         [] => []
      | x::lst' => if same_string(x,str) = false
                   then let fun append (word, list) = word::list
                        in append(x,[]) :: all_except_option(str,lst')
                        end
                   else all_except_option(str,lst')

【问题讨论】:

    标签: sml smlnj


    【解决方案1】:

    实现一个程序,它接受一个字符串和一个列表,如果没有找到任何匹配项,则返回 NONE,如果找到则返回不包含该元素的列表。

    all_except_option ("string",["he","she","string"]) = SOME ["he","she"]
    

    SOME []NONE 有何不同?例如,如果此函数只返回一个列表,则可以说删除 "string" 的出现不会导致其他字符串:列表已经为空,或者它仅包含 "string" 的出现。我不确定为什么 NONESOME [] 在一种情况下比另一种情况下得到保证。

    所以更好的函数是简单地返回一个简单的列表:

    fun except (x, ys) = List.filter (fn y => x <> y)
    

    什么时候返回'一个选项有用?

    例如当返回类型没有办法表明没有结果时:

    fun lookup k1 [] = NONE
      | lookup k1 ((k2,v)::pairs) =
          if k1 = k2
          then SOME v
          else lookup k1 pairs
    

    这个函数返回 0 或 1 个东西。但它也是一个简单的函数,因为它从不通过递归聚合结果。当递归函数需要解包递归结果时,返回复合数据类型(如'a option)会变得复杂。

    一个很好的例子是 eval 函数有时会失败:

    datatype expr
      = Add of expr * expr
      | Sub of expr * expr
      | Mul of expr * expr
      | Div of expr * expr
      | Int of int
    
    fun eval (Int n) = SOME n
      | eval (Add (e1, e2)) = evalHelper ( op+ ) (e1, e2)
      | eval (Sub (e1, e2)) = evalHelper ( op- ) (e1, e2)
      | eval (Mul (e1, e2)) = evalHelper ( op* ) (e1, e2)
      | eval (Div (e1, e2)) =
          case eval e1 of
               NONE => NONE
             | SOME x => case eval e2 of
                              NONE => NONE
                            | SOME 0 => NONE
                            | SOME y => SOME (x div y)
    
    and evalHelper binop (e1, e2) =
          case eval e1 of
               NONE => NONE
             | SOME x => case eval e2 of
                              NONE => NONE
                            | SOME y => SOME (binop (x, y))
    

    这里的返回类型是int option,这意味着你最常返回一个int,但如果你除以零,就会导致“没有值” ,因此我们不会引发异常,而是返回NONE,这需要我们在有结果时返回SOME n,以便类型适合两种情况。

    快速演示:

    - eval (Div (Int 5, Int 2));
    > val it = SOME 2 : int option
    - eval (Div (Int 5, Int 0));
    > val it = NONE : int option
    - eval (Div (Int 2, Sub (Int 3, Int 3)));
    > val it = NONE : int option
    - eval (Div (Int 0, Int 1));
    > val it = SOME 0 : int option
    

    这里SOME 0其实意思是“结果为0”,和“不能被零除”是不一样的。

    【讨论】:

    • “所有元素都是您要查找的元素”(即成功)与“未找到您的元素”(失败)不同。正如您自己注意到的那样,简单的列表无法表达差异。
    • 对,所以我质疑被告知列表为空的有用性,因为它以开头为空 ("所有 (non-existent) 元素都是你找”)。也许有一个比这个不只是返回输入的子列表的搜索功能更简单的搜索功能。我可以想到 int list option 是返回类型的问题,例如寻找给定一组硬币和一些现金返还金额的“返还确切零钱”任务,一些(可能是最少的)加起来现金返还的硬币数量。在这种情况下,SOME [] 表示“存在 0 个硬币的解决方案”。
    【解决方案2】:

    谢谢。我设法让它工作,但我仍然不明白“其他情况”以及我的程序如何处理它。这是工作代码。如果你能解释一下“else case all_except_option(str,list') of”,我会很高兴。

    fun all_except_option(str,list)=
        case list of
        [] => NONE
          | x::list' => if same_string(x,str)  then
                
                  SOME( list')
                                      
                else case  all_except_option(str,list') of
                     NONE=>NONE
                   | SOME list'=>SOME(x::list')
    

    【讨论】:

    • 这是不正确的。为什么要删除递归并将其替换为SOME?您的 NONE 案例也不正确。使用("a", ["a", "a"])("a", ["b"]) 进行测试。
    • 它适用于 ("a",["b"]),但它不适用于 ("a", ["a", "a"]) ,实际上很好,因为练习表明列表中的元素不会重复。
    • 好吧,我的错。下次我会更精确
    猜你喜欢
    • 1970-01-01
    • 2017-05-18
    • 1970-01-01
    • 2012-06-23
    • 1970-01-01
    • 1970-01-01
    • 2020-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多