list - 合并 SML 中的无限列表

标签 list zip sml

在 SML 中,我创建了三个无限列表,即 fibonaccievenfiboddfib。现在我想做的是创建第四个列表,它将包含 evenfib 的前 10 个数字和 oddfib 的前 10 个数字,并将它们合并成一对 evenfib 和一个 oddfib 使用 zip 函数并创建第四个列表。

我写了一个 zip 函数如下,但是它不起作用。

fun fib a b = CONS(a, fn () => fib b (a + b));
fun odd n = if ( n mod 2 = 1) then true else false;
fun even n = if (n mod 2 = 0) then true else false;
val fibs = fib 0 1;
fun evenfibs l = FILTER even l;
fun oddfibs l = FILTER odd l;
fun zip x = case x of (L 'a inflist , N 'b inflist) => (HD L, HD N) :: zip (TL L, TL N) | => _ nil;   

最佳答案

首先,您可能需要考虑简化谓词函数,因为它们不必要地冗长。在我看来,这是等效的且具有更好的风格:

fun even n = n mod 2 = 0
fun odd n = n mod 2 <> 0

关于流数据类型

由于 SML 具有严格的评估,因此传统的列表将无法解决问题。您必须首先定义自己的流数据类型。 stream是延迟列表。

您对 fibs 函数的定义似乎暗示了这种数据类型的存在:

datatype 'a stream =  Empty | Cons of 'a  *  (unit -> 'a stream)

如您所见,'a stream 类型的元素可以是 EmptyCons 包含一些 类型的值>'a 和一个能够生成下一个流元素的函数。

通过这种方式,我们可以在计算第二个元素时有所不同,直到我们实际调用该函数为止。

无限的自然数流

例如,您可以像这样定义无限的自然数流:

fun from n = Cons(n, fn () => from(n +1))
val naturals = from(1)

这里的 naturals 是一个包含所有自然数的无限流。您可以看到 Cons 仅包含第一个元素,第二个元素是一个函数,在求值时,它可以生成另一个流元素,这次包含 2,依此类推。

流函数库的需求

显然,您不能将此数据结构与传统的列表函数一起使用。您需要编写自己的函数来处理这种数据类型。

例如,您可以编写自己的 take 函数,从流中取出 n 个元素,从原始流中创建有限流:

fun take n xs =
    if n = 0
    then Empty
    else case xs of
            Empty => Empty
          | Cons(h,t) => Cons(h, fn() => take (n-1) (t()))

或者您可以创建自己的 filter 函数来过滤流中的元素,并在此过程中创建一个新的流。

fun filter f xs = 
   case xs of
      Empty => Empty
    | Cons(h,t) => if f(h)
                   then Cons(h, fn () => filter f (t()))
                   else filter f (t())

并且您需要一个 zip 函数将两个流的元素压缩到另一个压缩流中,如下所示:

fun zip(xs,ys) = 
    case (xs,ys) of
        (Empty,_) => Empty
      | (_, Empty) => Empty
      | (Cons(h1,t1), Cons(h2,t2)) => Cons( (h1,h2), fn () => zip(t1(),t2()))

您甚至可能希望有一个将有限流转换为列表的函数,仅用于调试目的,因为列表在 REPL 中更易于阅读:

fun toList xs =
    case xs of
        Empty => []
      | Cons(h,t) => h::toList(t())

例如:

  • toList (take 10 (from 1)) 将获取前 10 个自然数作为列表。
  • filter odd 将生成一个函数,该函数仅从 int 流中获取奇数元素。
  • filter even 将生成一个函数,该函数仅从 int 流中获取偶数元素。
  • 等等,

无限的斐波那契数列

假设有无限的斐波那契数流:

fun fibonacci() = 
   let
      fun fib(a,b) = Cons(a+b, fn() => fib(b,a+b))
   in
      Cons(0, fn() => fib(0,1))
   end  

您现在可以使用 filter oddfilter even 函数仅过滤掉偶数或奇数斐波那契数,然后使用 zip函数与这两个结果一起获得压缩的(奇数,偶数)斐波那契数流,从生成的流中,您可以取出前 10 个元素...

val fibs = fibonacci()
val evens = filter even
val odds = filter odd
val zipped = zip(evens fibs, odds fibs)

...您最终可以将其转换为如下列表:

val r = toList (take 10 zipped)

关于list - 合并 SML 中的无限列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19739421/

相关文章:

list - 如何列出 Azure Blob 存储中的子目录

compression - zlib、gzip 和 zip 有什么关系?它们有什么共同点,又有什么不同?

php - 压缩 .htaccess 文件

sml - 在 Poly/ML 中检查结构中的值

sml - 我得到了数据类型,但是在 sml 中定义类型有什么意义呢?

python - 如何获取每个嵌套列表的第三个元素,但如果第三个元素不存在则将其设置为 null?

python - 如何将 infile 中数据的平均值写入 out 文件

c - 为什么我得到这个错误的输出?

java - 使用java解压文件

compiler-errors - SML代码并且无法编译,要求andalso