弗雷格列表中的长度函数是否有上限?

时间:2014-06-26 17:53:01

标签: haskell frege

对于真实世界的自由项目,我从真实世界中进行了练习,其中的任务是为列表创建长度函数并将其与内部长度函数进行比较。

我建议的解决方案在https://github.com/Dierk/Real_World_Frege/blob/master/realworld/chapter3/I_Exercise_1.fr

它的牛肉是:

mylength :: [a] -> Int

mylength (_:xs)       = 1 + (mylength xs)
mylength []           = 0

-- optLength uses tail recursion and forces eager argument evaluation
optLength xs = privateLength xs 0 where
    privateLength (_:rest) !count = privateLength rest (count + 1)
    privateLength []       !count = count

main _ = do
    assert (mylength [])  (length [])  "empty"
    assert (mylength [0]) (length [0]) "one element"
--  assert (mylength [0..30_000]) (length [0..30_000]) "many elements lead to stack overflow"
    assert (optLength [0..1_000_000])  (length [0..1_000_000])  "optLength can do a little more"
    assert (optLength [0..10_000_000]) (length [0..10_000_000]) "this takes 40 seconds (20 s each)"
--  println (length [0..100_000_000]) -- never stops 

我和内部长度函数都适用于100万条以下的列表,10米时速度非常慢,100毫米时根本不会停止。

弗雷格的内部长度函数(不是Haskell的)似乎有一个低于1亿的上限。是这样吗?

1 个答案:

答案 0 :(得分:1)

这里有两个问题。

mylength不会被尾递归,因此应该堆栈溢出。

以下证明长度函数本身没有限制(也适用于optlength函数):

enter image description here

(TimeoutException是由于云服务的限制,而不是来自Frege。)

但是,您正在将length [0..100_000_000]传递给assert,看起来assert也会懒散地获取他们的参数。不幸的是,这会导致对列表开头的引用保持活动状态。反过来,这会导致整个列表在内存中实现,因此事情变得非常缓慢,可能是因为你的堆在极限上并且GC试图为下一个参数找到一些空闲空间。

这与问题中的问题相同:https://github.com/Frege/frege/issues/65

试试-Xmx4g,我相信你的闪亮高级笔记本电脑没问题:)

一般的解决方案是在调用assert之前强制执行结果,如:

let 
    n = length [0..100_000_000]
    m = optlength [0..100_000_000] 
in n `seq` m `seq` assert n m "should be equal"