相关疑难解决方法(0)

Haskell有尾递归优化吗?

我今天在unix中发现了"time"命令,并认为我会用它来检查Haskell中尾递归和正常递归函数之间运行时的差异.

我写了以下函数:

--tail recursive
fac :: (Integral a) => a -> a
fac x = fac' x 1 where
    fac' 1 y = y
    fac' x y = fac' (x-1) (x*y) 

--normal recursive
facSlow :: (Integral a) => a -> a
facSlow 1 = 1
facSlow x = x * facSlow (x-1)
Run Code Online (Sandbox Code Playgroud)

这些都是有效的,记住它们只是用于这个项目,所以我没有费心去检查零或负数.

但是,在为每个编写一个main方法,编译它们,并使用"time"命令运行它们时,两者都具有相似的运行时,正常的递归函数使尾递归函数边缘化.这与我在lisp中关于尾递归优化的内容相反.这是什么原因?

optimization haskell tail-recursion lazy-evaluation tail-call-optimization

82
推荐指数
3
解决办法
2万
查看次数

如何避免Haskell中的堆栈溢出?

Haskell不支持循环计算,而是提供使用递归算法.但是这种方法导致堆栈增长,甚至堆栈溢出.我认为应该有办法解决这个问题.这是样本.我想知道,每5秒可以调用多次getClockTime:

import System.Time

nSeconds = 5

main = do
    initTime <- totalPicoSeconds `fmap` getClockTime
    doWork initTime 1
    where
    doWork initTime n = do
        currTime <- totalPicoSeconds `fmap` getClockTime
        if (currTime - initTime) `div` 10 ^ 12 >= nSeconds
            then print n
            else doWork initTime (n+1)

totalPicoSeconds :: ClockTime -> Integer
totalPicoSeconds (TOD a b) = a * 10 ^ 12 + b
Run Code Online (Sandbox Code Playgroud)

该程序耗时5秒,但最终我得到了:

堆栈空间溢出:当前大小为8388608字节.
使用`+ RTS -Ksize -RTS'来增加它.

在特定情况下,手动管理堆栈大小可能有所帮助,但如果我希望运行此算法10秒钟,它可能会再次溢出.所以这不是一个解决方案.我怎样才能使这段代码有效?

stack-overflow recursion haskell

18
推荐指数
1
解决办法
3030
查看次数

什么可以是用Haskell编写的游戏的最小例子?

三个月后更新

我在下面的回答中使用netwire-5.0.1+ sdl,在使用Arrows和Kleisli Arrows进行I/O的功能反应编程结构中.虽然太简单,不能被称为"游戏",但它应该是非常可组合的并且非常可扩展.

原版的

我正在学习Haskell,并尝试用它制作一个小游戏.但是,我想看看小型(规范)文本游戏的结构.我也尽量保持代码尽可能纯净.我现在正在努力了解如何实施:

  1. 主循环.这里有一个例子如何在Haskell中编写游戏循环?但似乎接受的答案不是尾递归.我不确定这是否重要.据我了解,内存使用量会增长,对吧?
  2. 国家转型.不过,我认为这与第一个问题非常相关.我试了一下State,在http://www.gamedev.net/page/resources/_/technical/game-programming/haskell-game-object-design-or-how-functions-can-get-you中试了一下-apples-r3204,但是虽然单个组件可以在有限的步骤中工作和更新,但我看不出如何在无限循环中使用它.

如果可能的话,我想看一个基本上最小的例子:

  1. 要求玩家反复输入内容
  2. 满足某些条件时,请更改状态
  3. 当满足其他一些意愿时,退出
  4. 理论上可以无限时间运行而不会破坏内存

我没有任何可用的代码,因为我无法获得最基本的东西.我在网上找到的任何其他材料/示例都使用其他一些库,比如SDLGTK驱动事件.我发现在Haskell中完全写的唯一一个是http://jpmoresmau.blogspot.com/2006/11/my-first-haskell-adventure-game.html,但是那个在主循环中看起来不像是一个尾递归(同样,我不知道这是否重要).

或者,可能Haskell不打算做这样的事情?或者我可能应该放入mainC?

编辑1

所以我在https://wiki.haskell.org/Simple_StateT_use中修改了一个小例子,使它更简单(并且它不符合我的标准):

module Main where
import Control.Monad.State

main = do 
  putStrLn "I'm thinking of a number between 1 and 100, can you guess it?"
  guesses <- execStateT (guessSession answer) 0
  putStrLn $ "Success in " ++ (show guesses) ++ " tries."
  where
    answer = …
Run Code Online (Sandbox Code Playgroud)

haskell arrows game-engine frp netwire

5
推荐指数
1
解决办法
1448
查看次数

Haskell:TCO和懒惰的评估

我试图理解为什么第一个main在无效时终止c,而第二个终止.从描述来看, main只是一个未经评估的thunk,executing它只是构建数据结构.我试图在这里应用相同的原理,看看为什么第一个主要没有终止.如果有人可以帮助我理解这一部分,或者给我指点理解这将是伟大的.除此之外,为什么GHCI无法将其识别为TCO?不符合定义吗?

main = loop                                                                     
  where                                                                         
   loop =  do                                                                   
     c <- getChar                                                               
     case valid c of                                                            
       Nothing -> return ()                                                     
       Just b  -> print b                                                       
     print c                                                                    
     loop                                                                       

> main :: IO ()
> main = loop
>   where
>   loop =  do
>     c <- getChar
>     case validate c of
>       Nothing -> return ()
>       Just b  -> do
>         print b
>         loop
Run Code Online (Sandbox Code Playgroud)

谢谢.

haskell lazy-evaluation tail-call-optimization

0
推荐指数
1
解决办法
150
查看次数