我只想知道这里的XL变量是什么,它没有在任何地方声明?如果字符串不在列表中,则此函数返回NONE。否则,返回原始字符串列表但没有匹配的字符串。
if (e.which === 1) {
//do anything
}
答案 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
和::
,但不声明它们;而确实声明了值标识符h
和t
。这种不一致可能看起来很奇怪;原因是nil
和::
是值构造函数,这意味着它们已经使用datatype
(datatype 'a list = nil | :: of 'a * 'a list
)声明,所以它们可以用于模式。像这样:
val nil = 3
实际上是完全非法的,因为nil
指的是已经声明的构造函数,nil
和3
的类型不兼容。相反,如果标识符不已经是值构造函数,则模式中的外观构成声明(即使标识符已经 值变量:新声明将隐藏现有声明。这对于该语言的新手来说可能有点棘手,但只要有一点经验你会发现它很有意义。
答案 1 :(得分:2)
这似乎是一个有用的库函数。以下是有关如何改进它的几点建议:
不要编写自己的same_string
函数,该函数与=
运算符完全等效。只需使用=
运算符即可。这样做是因为可读性:其他SML程序员将识别=
运算符,但会想知道same_string
是否会做更多事情。为什么不让该功能适用于' 而不仅仅是字符串?
(次要的)不要在他们返回的类型后命名你的函数。类型本身应该是足够的注释。即您不会意外地使用此功能,并且没有意识到它实际上正在返回列表选项 。
过了一会儿,出现以下模式:
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]
您可能需要考虑在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}}。