【问题标题】:How to keep elements in list through out the program in SML?如何在 SML 中的整个程序中保持列表中的元素?
【发布时间】:2016-12-24 01:30:57
【问题描述】:

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

这是我的尝试:

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

问题是每次调用insert,都得到输出“1”,表示列表再次初始化到[]

但是,我希望第一次调用 insert 时输出 "1",第二次调用时输出 "2",等等。

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

【问题讨论】:

  • 在函数式编程中,用相同的输入重复调用一个函数会重复给出相同的结果。为什么你会期待其他情况?
  • 您永远不会更新变量(而且您不能!)。您只是在创建一个新列表,然后您确定其长度。
  • 我可以推荐阅读 R. Harper 的 Programming in Standard ML。一本好书!

标签: functional-programming sml smlnj


【解决方案1】:

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

您可以使用 reference 来解决这个问题。

标准机器学习参考速成课程:

  • 使用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

【讨论】:

    【解决方案2】:

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

    all_list@[x] 
    

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-18
      • 1970-01-01
      • 1970-01-01
      • 2019-03-07
      • 2021-03-25
      • 1970-01-01
      相关资源
      最近更新 更多