在SML中,我创建了三个无限列表,即fibonacci
,evenfib
和oddfib
。现在我要做的是创建第四个列表,其中包含evenfib
的前10个数字和oddfib
的前10个数字,并将它们合并为一个evenfib
和一个{{ {1}}使用oddfib
函数创建第四个列表。
我已经编写了一个zip函数,但它不起作用。
zip
答案 0 :(得分:6)
首先,您可能需要考虑简化谓词函数,因为它们不必要地冗长。在我的拙见中,这相当于更好的风格:
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
类型的元素可以是Empty
,也可以是包含Cons
类型值的'a
以及能够生成的函数下一个流元素。
通过这个我们可以在评估第二个元素时有所不同,直到我们实际调用该函数。
例如,您可以定义一个无限的自然数流,如下所示:
fun from n = Cons(n, fn () => from(n +1))
val naturals = from(1)
这里自然是包含所有自然数的无限流。你可以看到Cons只包含第一个元素,第二个元素是一个函数,在评估时,它可以生成另一个stream元素,这次包含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流中获取偶数元素的函数。假设Fibonacci数量无限:
fun fibonacci() =
let
fun fib(a,b) = Cons(a+b, fn() => fib(b,a+b))
in
Cons(0, fn() => fib(0,1))
end
您现在可以使用filter odd
和filter even
函数仅滤除偶数或奇数Fibonacci数,然后使用zip
函数将这两个结果用于获取压缩流(赔率,均匀)斐波纳契数和从生成的流中,你可以take
出前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)
答案 1 :(得分:2)
您正在尝试获取无限列表并将其压缩到正常的元组列表中。这个问题是普通列表无法真正处理无穷大。相反,您可以将它们压缩到您自己的列表类型中:
zip : 'a inflist * 'b inflist -> ('a * 'b) inflist
如果可以避免,请不要将HD
和TL
(或hd
和tl
用于内置列表)。而是模式匹配:
fun zip (CONS (a, f), CONS (b, g)) = CONS (...) (* try to fill this one in yourself *)
| zip _ = NIL (* assuming your inflist datatype has a constructor for the
empty list called NIL *)