我想要一个find
大小有界类型的流的函数,它类似于 Lists 和 Vects 的查找函数。
total
find : MaxBound a => (a -> Bool) -> Stream a -> Maybe a
挑战在于如何做到:
- 完全
- 消耗不超过
常数log_2 N 空间,其中 N 是编码最大所需的位数a
。 - 在编译时检查不超过一分钟
- 不强加运行时成本
通常,Streams 的总 find 实现听起来很荒谬。流是无限的,一个谓词const False
将使搜索永远持续下去。处理这种一般情况的一个好方法是无限燃料技术。
data Fuel = Dry | More (Lazy Fuel)
partial
forever : Fuel
forever = More forever
total
find : Fuel -> (a -> Bool) -> Stream a -> Maybe a
find Dry _ _ = Nothing
find (More fuel) f (value :: xs) = if f value
then Just value
else find fuel f xs
这对我的用例很有效,但我想知道在某些特殊情况下是否可以在不使用forever
. 否则,有人可能会忍受等待find forever ?predicateWhichHappensToAlwaysReturnFalse (iterate S Z)
结束的无聊生活。
考虑特殊情况 where a
is Bits32
。
find32 : (Bits32 -> Bool) -> Stream Bits32 -> Maybe Bits32
find32 f (value :: xs) = if f value then Just value else find32 f xs
Nothing
两个问题:它不是全部的,即使有有限数量的Bits32
居民可以尝试,它也不可能返回。也许我可以用它take (pow 2 32)
来构建一个 List,然后使用 List 的 find...呃,等等...单独的列表会占用 GBs 的空间。
原则上,这似乎不应该是困难的。有许多居民可以尝试,现代计算机可以在几秒钟内遍历所有 32 位排列。有没有办法让整体检查器验证the (Stream Bits32) $ iterate (+1) 0
最终循环回到0
并且一旦它断言所有元素都已经被尝试过,因为(+1)
它是纯的?
这是一个开始,虽然我不确定如何填补这些漏洞并find
足够专业化以使其完全。也许界面会有所帮助?
total
IsCyclic : (init : a) -> (succ : a -> a) -> Type
data FinStream : Type -> Type where
MkFinStream : (init : a) ->
(succ : a -> a) ->
{prf : IsCyclic init succ} ->
FinStream a
partial
find : Eq a => (a -> Bool) -> FinStream a -> Maybe a
find pred (MkFinStream {prf} init succ) = if pred init
then Just init
else find' (succ init)
where
partial
find' : a -> Maybe a
find' x = if x == init
then Nothing
else
if pred x
then Just x
else find' (succ x)
total
all32bits : FinStream Bits32
all32bits = MkFinStream 0 (+1) {prf=?prf}
有没有办法告诉整体检查器使用无限燃料来验证对特定流的搜索是否完全?