SML中的模式匹配?

时间:2017-01-07 22:19:24

标签: pattern-matching sml

我只想知道这里的XL变量是什么,它没有在任何地方声明?如果字符串不在列表中,则此函数返回NONE。否则,返回原始字符串列表但没有匹配的字符串。

if (e.which === 1) {
       //do anything
    }

2 个答案:

答案 0 :(得分:3)

正如上面评论的melpomene,该行上的xl实际 xl的声明。

在标准ML中,使用 patterns 声明(绑定)变量,然后匹配 values 。即使使用val也是如此;例如,我们可以写:

val (x, y) = (1, "y")

声明x(将其绑定到1)和y(将其绑定到"y")。

case表达式和fn表达式中,模式匹配也可以作为条件加倍;例如,这个:

val rec sum =
  fn nil => 0
   | h :: t => h + sum t

创建一个函数来检查它的参数是否为nil,在这种情况下它会做一件事,而它的参数的形式是value1 :: value2(意思是非空列表),其中case它做了不同的事情(使用这些值)。 (假设,如果论证是既不那些形式,那么函数最终会提升Match;但是当它发生时,任何类型的值int list将强制使用这两种形式中的一种,因此该函数永远不会引发Match。)

顺便提一下,请注意,该示例使用值标识符nil::,但声明它们;而确实声明了值标识符ht。这种不一致可能看起来很奇怪;原因是nil::是值构造函数,这意味着它们已经使用datatypedatatype 'a list = nil | :: of 'a * 'a list)声明,所以它们可以用于模式。像这样:

val nil = 3

实际上是完全非法的,因为nil指的是已经声明的构造函数,nil3的类型不兼容。相反,如果标识符已经是值构造函数,则模式中的外观构成声明(即使标识符已经 变量:新声明将隐藏现有声明。这对于该语言的新手来说可能有点棘手,但只要有一点经验你会发现它很有意义。

答案 1 :(得分:2)

这似乎是一个有用的库函数。以下是有关如何改进它的几点建议:

  1. 不要编写自己的same_string函数,该函数与=运算符完全等效。只需使用=运算符即可。这样做是因为可读性:其他SML程序员将识别=运算符,但会想知道same_string是否会做更多事情。为什么不让该功能适用​​于' 而不仅仅是字符串

  2. (次要的)不要在他们返回的类型后命名你的函数。类型本身应该是足够的注释。即您不会意外地使用此功能,并且没有意识到它实际上正在返回列表选项

  3. 过了一会儿,出现以下模式:

    case f x of
         NONE => NONE
       | SOME y => SOME (g y)
    

    变得有点乏味,你想抽象出SOME / NONE部分,因为同样的事情总是发生(要么它是NONE并且没有任何反应,或者它是SOME y并且y发生了一些事情。使用类型为的库函数Option.map(' a→' b)→' a选项→' b选项

    Option.map (fn y => g y) (f x)
    

    就像你在列表中映射一样。它可能看起来像:

    fun all_except (_, []) = NONE
      | all_except (x1, x2::xs) =
        if x1 = x2
        then SOME xs
        else Option.map (fn ys => x2::ys) (all_except (x1, xs))
    

    你可能会像这样粗略地测试一下:

    val test_all_except_1 = all_except (4, [1,2,3]) = NONE
    val test_all_except_2 = all_except (1, [1,2,3]) = SOME [2,3]
    val test_all_except_3 = all_except (2, [1,2,3]) = SOME [1,3]
    val test_all_except_4 = all_except (3, [1,2,3]) = SOME [1,2]
    val test_all_except_5 = all_except (1, [1,1,1]) = SOME [1,1]
    val test_all_except_6 = all_except (1, [1,2,1]) = SOME [2,1]
    
  4. 您可能需要考虑在curried form中编写函数:

    fun curry f x y = f (x, y)
    
    fun all_except _ [] = NONE
      | all_except x1 (x2::xs) =
        if x1 = x2
        then SOME xs
        else Option.map (curry op:: x2) (all_except x1 xs)
    

    在这里,all_except将其两个参数彼此分开,而不是在(x1, x2::xs)元组/对中。并且在以下步骤中使用辅助函数(fn ys => x2::ys)重写了值curry

    (fn ys => x2::ys)           (* original *)
    (fn ys => op:: (x2, ys))    (* converting :: to a function *)
    (fn ys => curry op:: x2 ys) (* making it a curried function *)
    (curry op:: x2)             (* performing eta conversion *)
    

    最后一步可能看起来很神秘。函数curry op:: x2是一个列表并在其前面添加x2的函数,因此它具有'列表→'列表的类型。如果我们暂时将其称为f,我们会(fn ys => f ys),但这只是f的{​​{3}}。