是什么导致我的 SML 变量未绑定?

What is causing my SML variables to be unbound?

我是 SML 代码的新手,我正在尝试创建一个函数,该函数 returns 包含所有素数的列表,最多为用户给出的数字。除了我的数字、索引和 lst 变量不断出现未绑定变量或构造函数错误外,我的大部分函数都在工作。该代码应使用两个辅助函数 运行 通过两个索引并将它们相乘,从列表中获取非素数。这是我的代码:


fun removeMult (lst,n) = if null lst then lst else if hd lst mod n = 0 then removeMult(tl lst, n) else (hd lst) :: removeMult(tl lst, n);

fun helpertwo(lst, ind : int, n : int, indtwo : int) = if indtwo = n then lst else helpertwo(removeMult(lst , ind*indtwo),ind,n,indtwo+1);

fun test(lst,number,index) = 
if 
 number = index 
then 
 lst 
else
 helpertwo(lst, index, number, 2);
 test(lst,number,(index+1));

fun primes (n : int) = 
if 
 (n <= 1)
then
 []
else
  makelist(n);
  removeMult(lst , 1);
  test(lst, n , 2);

重新缩进代码得到如下结果:

fun test(lst,number,index) = 
    if 
    number = index 
    then 
    lst 
    else
    helpertwo(lst, index, number, 2);
test(lst,number,(index+1));

fun primes (n : int) = 
    if 
    (n <= 1)
    then
    []
    else
    makelist(n);
removeMult(lst , 1);
test(lst, n , 2);

一些表达式根本不是函数的一部分,这就是参数不在范围内的原因。你实际上可以在 else 中有多个表达式,如下所示:

    else
    (helpertwo(lst, index, number, 2);
     test(lst,number,(index+1)))

但这在你的情况下不起作用,因为 helpertwo 没有副作用,所以真正的解决方法是以某种方式使用 helpertwo 的结果。

这是使用筛子生成素数的另一种方法。

它不是特别有效,但它演示了惰性流。

流有点像列表,只是尾部用一个尚未计算的函数表示。下面流的特定定义没有表示 "end of stream" 的方法,而严格列表必须这样做。但由于素数是无限的,因此从概念上讲,容纳它们的流也可以是无限的。

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

素数是自然数的子集,

fun nats i =
  Cons (i, fn () => nats (i+1))

fun take 0 _ = []
  | take 1 (Cons (x, _)) = [x]
  | take n (Cons (x, stream)) = x :: take (n-1) (stream ())

- take 10 (nats 0);
> val it = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] : int list

关于用筛子挑素数,看Sieve of Eratosthenes(维基百科)的动画:我们挑第一个元素(从2开始),然后划掉后续的倍数(4,6,8,. ..).我们选择下一个元素(3)并划掉后续的倍数(6、9、12,...)。我们选择下一个元素(5,因为 4 被划掉)并划掉后续的倍数(10、15、20,...),依此类推。

使用惰性流的递归解决方案可能看起来像

fun sieve (Cons (n, stream)) =
  Cons (n, fn () => sieve (remove_multiples n (stream ())))

and remove_multiples i =
  filter (fn n => n mod i <> 0)

and filter p (Cons (x, stream)) =
  if p x
  then Cons (x, fn () => filter p (stream ()))
  else filter p (stream ())

这里 sieve 是一个递归的惰性定义,因为它在延迟计算的 fn () => ... 中调用自己。它会逐步过滤掉更多倍数,因为它不仅使用删除了一个元素的流来调用自己,而且在每次递归调用时使用删除了大量元素的流来调用自己。

您可以取前 10 个素数:

fun primes n =
  take n (sieve (nats 2))

- primes 10;
> val it = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] : int list

或者您可以取谓词成立的第一个素数:

fun takeWhile p (Cons (x, stream)) =
  if p x then x :: takeWhile p (stream ()) else []

fun primesUpto n =
  takeWhile (fn p => p <= n) (sieve (nats 2))

- primesUpto 100;
> val it =
    [2, 3, 5, 7, 11,
     13, 17, 19, 23,
     29, 31, 37, 41,
     43, 47, 53, 59,
     61, 67, 71, 73,
     79, 83, 89, 97] : int list

如果您想要更高效但仍然实用且懒惰的策略,请查看 wheel sieve