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