如何在整个 SML 程序中将元素保留在列表中?

How to keep elements in list through out the program in SML?

假设我必须在每次调用函数时更新列表,以便保留列表的前一个元素。

这是我的尝试:

local 
    val all_list = [];
in
    fun insert (x:int) : string  = int2string (list_len( ((all_list@[x])) ) )
end;

问题是每次调用insert时,得到的输出都是“1”,表示list又被初始化到[]

但是我期望第一次调用插入时输出 "1",第二次调用输出 "2",等等

我无法提供解决方法。应该怎么做?

值在 SML 中是不可变的。 insert 是在 all_list 的值为 [] 的上下文中定义的,您的代码不会更改该值。

all_list@[x] 

不会改变值 all_list -- 它 returns 一个全新的列表,您的代码会立即丢弃它(在获取其长度后)。

使用引用类型(SML 的不纯特性之一)可以完成您似乎想要做的事情,但生成的代码不会是惯用的 SML。它会破坏引用透明性(函数式编程语言的理想特性,其中使用相同输入调用的函数会产生相同的输出)。

您需要使用 side-effects。 大多数时候函数式程序员更喜欢使用 pure functions,它没有副作用。您的实现是一个纯函数,因此对于相同的输入,它总是 return 相同的值(在您的情况下,它 return 对于任何输入都是相同的值)。

您可以使用 参考资料 来解决这个问题。

标准 ML 参考速成班:

  • 使用ref创建一个新的引用,ref的类型是'a -> 'a ref,所以它把任意值打包到一个引用单元格中,你可以稍后修改;
  • ! 用于解包引用:(!) : 'a ref -> 'a,在大多数命令式语言中,此操作是隐式的,但在 SML 或 OCaml 中不是;
  • (:=) : 'a ref * 'a -> unit 是一个用于修改引用的中缀运算符,下面是如何递增整数引用的内容:r := !r + 1.

上面给出了以下代码(我将 xs 添加到列表中,而不是附加它们):

local
    val rxs = ref []
in
    fun insert (x:int) : string =
      (rxs := x :: !rxs;
       Int.toString (length (!rxs)))
end