首页 > 解决方案 > SMLNJ 函数以对形式返回列表开头的字符串

问题描述

所以我真的很困惑,因为我是 sml 的新手,而且我在如何创建函数的语法上遇到了麻烦。

说明如下...

numberPrefix: 字符列表 → 字符串 * 字符列表

编写一个名为 numberPrefix 的函数,它返回(作为一对)一个字符串,该字符串表示输入列表开头的数字字符和此前缀之后的剩余字符。你可以在你的实现中使用 Char.isDigit 和 String.implode 函数。例如,

val it = ("", [#"a", #"2", #"c", #" ", #"a") : 字符串 * 字符列表

val it = ("23", [#" ", #"a"]) : 字符串 * 字符列表

到目前为止,这是我的代码...

fun numberPrefix(c:char list):string*char list =
case c of
[] => []
|(first::rest) => if isDigit first
                  then  first::numberPrefix(rest)
                  else  

;

我想我想要做的是首先附加到一个单独的列表,如果它确实是一个数字,一旦我到达 char 列表的成员,然后我想使用 String.implode 返回该列表,但我正在敲我的头关于传递辅助函数甚至只是使用“let”表达式的想法。我怎样才能基本上创建一个单独的列表,同时跟踪我在原始列表中的位置,以便我可以以正确的格式返回结果?

标签: smlssml

解决方案


首先,函数应该产生一对,而不是列表。
基本情况应该是("", []), not [],并且您不能将递归结果传递给“未触及”。
(你几乎可以从类型中看出这一点。注意类型;他们想帮助你。)

如果将递归结果绑定在 alet中,则可以单独访问其部分并重新排列它们。
直接递归采取可能如下所示:

fun numberPrefix [] = ("", [])
  | numberPrefix (cs as (x::xs)) = 
        if Char.isDigit x
        then let val (number, rest) = numberPrefix xs 
             in
                 ((str x) ^ number, rest)
             end
        else ("", cs);

但是,根据谓词将列表一分为二——我们称之为“splitOn”,带有类型('a -> bool) -> 'a list -> 'a list * 'a list ——是一个相当有用的操作,如果你有这个函数,你只需要这样的东西:

fun numberPrefix xs = let val (nums, notnums) = splitOn Char.isDigit xs
                      in
                          (String.implode nums, notnums)
                      end;

(左分割作为练习。我怀疑你已经实现了这个分割功能,或者它的近亲“takeWhile”和“dropWhile”。)


推荐阅读