Binary 如何在标准ML中创建大小不断增加的按需呼叫列表?

Binary 如何在标准ML中创建大小不断增加的按需呼叫列表?,binary,sml,lazy-sequences,Binary,Sml,Lazy Sequences,我试图创建一个包含列表元素的惰性列表,这些元素一起表示所有0和1的组合 示例:[[],[0],[1],[0,0],[0,1],[1,0]…] 这在ML中可能吗?一旦定义了列表元素的模式,我似乎找不到改变它的方法。似乎还需要定义二进制模式的更改,这在函数式语言中是不可能的(我从未在函数式语言中遇到过二进制表示)这里似乎有两个不同的问题: 我们如何生成这种特殊的无限数据结构 在ML中,我们如何实现按需调用 让我们从考虑第一点开始。我将分步骤生成这个特定的数据结构,其中第n步的输入是长度为n的所有位

我试图创建一个包含列表元素的惰性列表,这些元素一起表示所有0和1的组合

示例:[[],[0],[1],[0,0],[0,1],[1,0]…]


这在ML中可能吗?一旦定义了列表元素的模式,我似乎找不到改变它的方法。似乎还需要定义二进制模式的更改,这在函数式语言中是不可能的(我从未在函数式语言中遇到过二进制表示)

这里似乎有两个不同的问题:

  • 我们如何生成这种特殊的无限数据结构
  • 在ML中,我们如何实现按需调用

  • 让我们从考虑第一点开始。我将分步骤生成这个特定的数据结构,其中第n步的输入是长度为n的所有位模式的列表。我们可以通过在每个长度为n的模式前加0和1来生成长度为n+1的所有位模式。代码:

    fun generate patterns =
      let
        val withZeros = List.map (fn pat => 0 :: pat) patterns
        val withOnes = List.map (fn pat => 1 :: pat) patterns
        val nextPatterns = withZeros @ withOnes
      in
        current @ generate nextPatterns
      end
    
    val allPatterns = generate [[]]
    
    如果您要在Haskell之类的按需调用语言中实现这种方法,它将在开箱即用的情况下运行良好。但是,如果您在ML中运行此代码,它将不会终止。这就引出了第二个问题:如何在ML中按需调用


    要在ML中按需调用,我们需要使用挂起。直观地说,暂停是一项计算,可能已经运行,也可能尚未运行。合适的接口和实现如下所示。我们可以使用
    延迟
    暂停计算,从而阻止它立即运行。稍后,当我们需要暂停计算的结果时,我们可以
    force
    。此实现使用引用来记住先前强制暂停的结果,从而保证对任何特定暂停最多进行一次评估

    structure Susp :>
    sig
      type 'a susp
      val delay : (unit -> 'a) -> 'a susp
      val force : 'a susp -> 'a
    end =
    struct
      type 'a susp = 'a option ref * (unit -> 'a)
      fun delay f = (ref NONE, f)
      fun force (r, f) =
        case !r of
          SOME x => x
        | NONE => let val x = f ()
                  in (r := SOME x; x)
                  end
    end
    
    接下来,我们可以根据暂停定义一个惰性列表类型,其中列表的尾部被延迟。这使我们能够创建看似无限的数据结构;例如,
    fun zeros()=delay(fn =>Cons(0,zeros())
    定义了一个无限的零列表

    structure LazyList :>
    sig
      datatype 'a t = Nil | Cons of 'a * 'a t susp
    
      val singleton : 'a -> 'a t susp
      val append : 'a t susp * 'a t susp -> 'a t susp
      val map : ('a -> 'b) -> 'a t susp -> 'b t susp
    
      val take : 'a t susp * int -> 'a list
    end =
    struct
    
      datatype 'a t = Nil | Cons of 'a * 'a t susp
    
      fun singleton x =
        delay (fn _ => Cons (x, delay (fn _ => Nil)))
    
      fun append (xs, ys) =
        delay (fn _ =>
          case force xs of
            Nil => force ys
          | Cons (x, xs') => Cons (x, append (xs', ys)))
    
      fun map f xs =
        delay (fn _ =>
          case force xs of
            Nil => Nil
          | Cons (x, xs') => Cons (f x, map f xs'))
    
      fun take (xs, n) =
        case force xs of
          Nil => []
        | Cons (x, xs') =>
            if n = 0 then []
            else x :: take (xs', n-1)
    end
    
    有了这种机制,我们可以调整原始代码,在正确的位置使用惰性列表和暂停:

    fun generate patterns =
      delay (fn _ =>
        let
          val withZeros = LazyList.map (fn pat => 0 :: pat) patterns
          val withOnes = LazyList.map (fn pat => 1 :: pat) patterns
          val nextPatterns = LazyList.append (withZeros, withOnes)
        in
          force (LazyList.append (patterns, generate nextPatterns))
        end)
    
    val allPatterns = generate (LazyList.singleton [])
    
    我们可以使用
    LazyList强制此列表的一部分。以
    为例:

    - LazyList.take (allPatterns, 10);
    val it = [[],[0],[1],[0,0],[0,1],[1,0],[1,1],[0,0,0],[0,0,1],[0,1,0]]
      : int list list