【问题标题】:Where does "#" come from in SML?SML 中的“#”从何而来?
【发布时间】:2016-02-24 22:25:49
【问题描述】:

我正在尝试制作接受字符串并将其转换为布尔表达式的函数。例如:对于输入((x10+~1)*x132),它应该给出times(plus(var 10,compl 1),var 132),但它给出times(plus(var #,compl #),var 132)。标签从何而来??

datatype boolexp = zero
                 | one 
                 | plus of boolexp * boolexp 
                 | times of boolexp * boolexp
                 | var of int
                 | compl of boolexp

exception InvalidInput

(* takes the first n elements *)
fun take (_, 0) = nil
  | take (nil, _) = raise InvalidInput
  | take (h::t, n) = if n < 0
                     then raise InvalidInput
                     else h::take(t, n-1)

(* drops the frist n elements *)
fun drop (xs, 0) = xs
  | drop (nil, _) = raise InvalidInput
  | drop (h::t,n) = if n < 0
                    then raise InvalidInput
                    else drop (t, n-1)

(* converts string to integer *)
fun charlist_to_int (nil) = raise InvalidInput 
  | charlist_to_int (xs) =
    let fun helper_int_rev (nil) = 0
          | helper_int_rev (h::t) = if h >= #"0" andalso h <= #"9"
                                    then helper_int_rev t * 10 + (ord h - ord #"0")
                                    else raise InvalidInput
    in helper_int_rev (rev xs) end;

(* finds the operator and its position *)
fun searchfor_oper (nil,_,_) = raise InvalidInput
  | searchfor_oper (#"("::t, np, pos) = searchfor_oper (t, np+1, pos+1)
  | searchfor_oper (#")"::t, np, pos) = searchfor_oper(t, np-1, pos+1)
  | searchfor_oper (#"+"::t, 0, pos) = (pos, #"+")
  | searchfor_oper (#"*"::t, 0, pos) = (pos, #"*")
  | searchfor_oper (h::t, np, pos) = searchfor_oper (t, np, pos+1)

fun beparse_helper (nil) = raise InvalidInput
  | beparse_helper (h::t) =
    if h = #"x" then if hd(t)= #"0" then raise InvalidInput
    else var (charlist_to_int (t))
    else if h = #"0" then if t = nil then zero else raise InvalidInput
    else if h = #"1" then if t = nil then one else raise InvalidInput
    else if h = #"~" then compl(beparse_helper(t))
    else if h = #"(" then
    let
        val lst = if hd (rev t)= #")" then take(t, length(t)-1) else raise InvalidInput
        val (pos, oper) = searchfor_oper (lst, 0, 1)
    in
        if oper = (#"+")
        then plus(beparse_helper(take(lst,pos-1)), beparse_helper(drop(lst,pos)))
        else if oper = (#"*")
             then times(beparse_helper(take(lst,pos-1)),beparse_helper(drop(lst,pos)))
             else raise InvalidInput 
    end
    else raise InvalidInput;

fun beparse(s) = beparse_helper(explode(s));

(*TESTING*)
beparse ("((x10+~1)*x132)");

【问题讨论】:

    标签: sml smlnj


    【解决方案1】:

    我认为SML 本身不如SML/NJ 默认 REPL 输出。在事物的宏伟计划中,REPL 是用于开发/调试的——而不是完成程序运行它的环境。诸如树之类的递归数据结构可以迅速产生太大而无法方便打印的值。 REPL 以几种方式截断输出。对于列表,它将打印大约十几个元素,然后使用...。对于树木之类的东西,它会打印几个级别,然后使用# 表示您已达到截断发生的级别。如果您觉得这不方便,您可以做以下两件事之一:

    1) SML/NJ 中的逻辑打印深度可以通过评估 REPL 中的Control.Print.printDepth := 20;(或任何你想要的)来改变

    2) 也许更有原则但更多的工作——为你的价值观编写一个自定义的漂亮打印机(比如pprint)并评估例如REPL 中的pprint v; 而不仅仅是v;

    【讨论】:

      【解决方案2】:

      另外,考虑更多地使用模式匹配:

      fun beparse_helper [] = raise InvalidInput
        | beparse_helper (#"x"::cs) = var (charlist_to_int cs)
        | beparse_helper (#"0"::[]) = zero
        | beparse_helper (#"1"::[]) = one
        | beparse_helper (#"~"::cs) = compl (beparse_helper cs)
        | beparse_helper (#"("::(cs as (_::_))) =
          let val lst = if List.last cs = #")"
                        then take (cs, length cs - 1)
                        else raise InvalidInput
          in case searchfor_oper (lst, 0, 1) of
                (pos, #"+") => plus (beparse_helper (take (lst, pos-1)),
                                     beparse_helper(drop (lst, pos)))
              | (pos, #"*") => times (beparse_helper (take (lst, pos-1)),
                                      beparse_helper(drop (lst, pos)))
          end
        | beparse_helper _ = raise InvalidInput
      

      【讨论】:

      • 第 6 行的“as”是什么?
      • as 是一个以模式工作的运算符。对于fun foo (xs as (y::ys)) = ...,它将xs 绑定到完整的输入列表,y 绑定到列表的头部,ys 绑定到尾部。如果您想要完全限制模式匹配,但您仍然想要绑定完整值(而不是其组件),这很有用。在这种情况下,#"("::(cs as (_::_)) 匹配一个列表,其中至少包含两个以字符 ( 开头的元素,并且列表的其余部分(包括第二个元素)称为 cs。这样我就确信List.last 不会失败(因为它至少需要一个元素)。
      猜你喜欢
      • 2015-04-07
      • 2021-01-23
      • 1970-01-01
      • 2018-08-13
      • 1970-01-01
      • 2012-07-08
      • 2016-11-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多