如何使用函数式语言对链接列表执行这些基本操作?

时间:2018-01-06 22:38:41

标签: linked-list sml

将列表转换为链接列表

我试图在标准ML中将列表转换为单链表(不确定双链表是否可行)。但是,我不确定这是怎么做的,但是到目前为止还是会显示我的尝试。

datatype 'a mlist = Nil
        | Cons of 'a * 'a mlist ref

fun listToLL [] = Nil
    | listToLL (x::xs) = Cons(x, (ref (listToLL xs)))

我首先在数据类型上创建了一个链接列表,但是我对#ref;'功能。我想避免将链表放入惰性列表中,因此ref允许我明确地将下一个序列作为前一个序列的引用。但问题是这个函数根本没有使用链表数据类型,即使我不使用这个链表定义也能工作。那么我的实现是否正确?

作为一个附带问题,唯一可以将链接列表与惰性列表区分开来的' ref'功能?从他们的数据类型定义来看,这似乎就是这样。

将两个链接列表连接在一起

fun joining (mlpx, mlpy) = 
    case !mlpx of
        Nil => mlpx := mlpy
    |   Cons(_, mlp) => joining(mlp, mlpy)          


fun join (mlpx, mlpy) = 
    let
        val mlp = ref mlpx
    in
        joining(mlp, mlpy);
        !mlp
    end;    

对于第二个操作,我对第二个连接函数中ref的需求感到非常困惑。当我处理链表时,我是否希望我处理一个引用,或者我是否处理包含来自内部引用的整个Cons结构?我不明白为什么我们不能单独使用joining函数,因为它似乎已经足够了。为什么需要在ref函数中创建join

2 个答案:

答案 0 :(得分:1)

  

我首先在数据类型上创建了一个链接列表,但是我对#ref;'功能。我想避免将链表放入惰性列表[...]

     

[...]

     

作为一个附带问题,唯一可以将链接列表与惰性列表区分开来的' ref'功能?

懒惰列表完全不同,因为它们需要"暂停"计算,通常通过创建闭包(例如,参见this answer以获取SML中的惰性列表的实现)。你的实现并不懒惰。 ref的使用只允许可变性。

  

但问题是这个函数根本没有使用链表数据类型,即使我不使用这个链表定义也能工作。那么我的实现是否正确?

您对listToLL的实施是正确的。我不确定我理解你对这个问题的其余部分的意思。您的函数 使用链接列表数据类型,因为它使用构造函数NilCons

  

我对第二个连接功能中的ref需要感到非常困惑。当我处理一个链表时,我是否期望我处理一个引用,或者我是否处理包含来自内部引用的整个Cons结构?

你的困惑很自然。我记得当我第一次尝试在SML中实现可变链接列表时,我对完全相同的问题感到非常困惑。

您提供的join实现创建了一个额外的引用来干净地处理第一个列表为空的情况,因为帮助函数joining'a mlist ref类型的对象进行操作而不是{ {1}}。但是,可以避免创建这个额外的引用。以下是我将如何做到这一点:

'a mlist

答案 1 :(得分:1)

  

将列表转换为单链表

SML中的列表已经实现为链接列表。

定义类似

的数据类型时
datatype 'a mylist = Nil | Cons of 'a * 'a mylist

您正在使用[]nil)和::创建一个与内置'列表类型同构的类型( >缺点)。

您的尝试似乎是如何使用引用创建可变链接列表。

  

我想避免将链表放入惰性列表

正如Sam Westrick所指出的,懒惰列表通常是使用闭包进行的:

datatype 'a lazylist = Nil | Cons of 'a * (unit -> 'a lazylist)

编辑:有关详细信息,请参阅他的example of suspensions [stackoverflow.com]。

  

不确定双向链表是否可行

可变链接列表和双链表都可以使用引用,但我不建议在SML中使用此方法。如果您需要向前和向后遍历列表,或者如果您需要对其进行更新,则可以使用 zippers 完全在功能上执行此操作:

原始文章在OCaml中有例子,LYAH章节在Haskell中有例子。

我想在标准ML中看到一些很好的例子,但我没有找到任何例子。