SML:计算String中'\ n'的数量

时间:2016-01-06 09:06:12

标签: algorithm functional-programming sml smlnj

我是标准ML中的新手,对于知道如何用这种语言编码的人来说,我有一个很明显的问题。

我有一个原始功能如下:

fun getBlocked w =
case BlockingMgr.listBlockedSuccessors w
    of nil => ""
    | ws =>
        concat (
            List.map
                (fn (r, w') => (
                    "v r1 w"
                    ^
                      Int.toString (Node.getId w))
                    ^ " w"
                    ^ (Int.toString (Node.getId (w')))
                    ^ "\n"
                )
            ws
        )       

这会给我一个完美的字符串,以便在我的程序中显示。

不幸的是,我还需要此字符串中'\ n'的数量。所以不是直接从字符串计算(这会很好),我想要制作另一个返回整数的函数:

fun getNbBlocked w =
    let res = 0;
    case BlockingMgr.listBlockedSuccessors w
        of nil => res
        | ws =>
            List.map
                (fn (r, w') => (
                    res = res+1
                )
            ws  

但是我的大脑对程序/对象的思考太过分了,我不知道如何用函数式语言表达我想要的东西。

如果有人可以帮我调试这个功能,因为我真的不知道是什么问题:/(甚至更好,通过告诉我如何编写一个函数来计算'\ n'的数量来帮助我现有的字符串)

提前感谢您的帮助!

最诚挚的问候!

修改

@molbdnilo你的解决方案似乎接近解决方案,但我没有设法使用它:/(不幸的是我是一个真正的初学者)。

我有这些功能(已经存在的功能和你的功能):

val res = 0

fun getBlocked w =
    case BlockingMgr.listBlockedSuccessors w
        of nil => ""
        | ws =>
            concat (
                List.map
                    (fn (r, w') => (
                        "v r1 w"
                        ^
                        Int.toString (Node.getId w))
                        ^ " w"
                        ^ (Int.toString (Node.getId (w')))
                        ^ "\n"
                        )
                    ws
                )       

fun count c s = List.length (List.filter (fn x => x = c) (String.explode s));;

fun count_newlines s = count #"\n" s;;

fun af w = print(getBlocked w)

fun aff w = count_newlines(getBlocked w)

当我调用函数getBlocked()以显示创建的字符串

我做的如下:

app af (Nodestore.listNodes ())

因为它正在调用print,所以它可以在任何地方调用。

但是对于你的函数,我需要使用它的返回值而我无法做到:/

我试着像:

res = (app aff Nodestore.listNodes())

(* We then, display the number of edges *)
print (Int.toString (res));

但遗憾的是,并不像我想的那么简单:/

我收到错误消息:

Error: src/output/modeloutput.sml 101.11.
  Function applied to incorrect argument.
    expects: _ -> [unit]
    but got: _ -> [int]
    in: app aff
Error: src/output/modeloutput.sml 101.11.
  Function applied to incorrect argument.
    expects: [Node.node list]
    but got: [unit -> Node.node list]
    in: (app aff) Nodestore.listNodes
Error: src/output/modeloutput.sml 101.11.
  Function not of arrow type.
    function: [unit]
    in: ((app aff) Nodestore.listNodes) ()
      pre codegen raised in 2.79 + 1.50 (35% GC)
      pre codegen raised: Fail
   Compile SML raised in 2.79 + 1.50 (35% GC)
   Compile SML raised: Fail

4 个答案:

答案 0 :(得分:2)

您的函数的主要问题是res = res + 1是比较,而不是作业。

你需要忘记分配,甚至忘记存在这样的事情。

这是一种做你想做的事情的方法:

  • 将字符串转换为字符列表
  • 过滤它并只保留您感兴趣的角色
  • 取结果的长度

看起来像这样:

fun count c s = List.length (List.filter (fn x => x = c) (String.explode s))
fun count_newlines s = count #"\n" s

答案 1 :(得分:2)

也可以直接对字符串进行递归,而无需先将它们扩展到列表中:

fun countChar c "" = 0
|   countChar c s = let val ch = String.sub (s,0) in
    (if ch = c then 1 else 0) + countChar c (String.extract (s,1,NONE))
end;

String.sub (s,0)对应于获取列表的头部,而String.extract (s,1,NONE)对应于获取尾部。我怀疑这比使用explode更有效,因为它不需要1次传递来构建列表然后另一次传递来处理列表,尽管这不太可能是显着的,甚至是显着的时间节省(除非你正在处理一些非常长的字符串)。

答案 2 :(得分:2)

我会在这里推荐John的解决方案,并可能将其扩展为尾递归:

fun countChar c s =
    let val len = String.size s
        fun cc i n = if i = len then n
                     else cc (i+1) (if String.sub (s, i) = c then n+1 else n)
    in cc 0 0
    end

答案 3 :(得分:0)

我不太清楚ML,但我相信你应该使用foldl,就像这样:

  foldl op+ 0 f

其中op +是加号运算符,0是初始值,f是您的自定义,可能是匿名函数。