每次连续执行后如何打印出内存状态? [英] How do you print out a memory state after each consecutive execution?

查看:67
本文介绍了每次连续执行后如何打印出内存状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在调试功能方面遇到问题.我应该定义下面某些命令的执行,然后我必须创建一个调试函数,该函数在每次执行后都会递归打印出当前的内存值.

I have a problem regarding a debugging function. I'm supposed to define the execution of certain commands which are down below and then I have to create a debug function which recursively prints out the current memory values after each execution is called.

这里有我的exec(执行),调试和数据类型代码

Heres my code for exec (execution), debug and the data types

data Com = Ass Char Exp 
         | While Exp Com 
         | Seq Com Com
           deriving Show

exec :: Memory -> Com -> Memory
exec m (Ass c e) = update m (c, (eval m e))
exec m (While e c) = if (eval m e) == 0 then m
                     else exec (exec m c) (While e c)
exec m (Seq c1 c2) = exec (exec m c1) c2


debug :: Memory -> Com -> [Memory]
debug m (Ass c e) = update m (c, (eval m e)) : [m]
debug m (Seq c1 c2) = (exec (exec m c1) c2) :[m]
debug m (While e c) = if (eval m e) == 0 then [m]
                      else (exec (exec m c) (While e c)) : [m]

com1 :: Com
com1 =  Seq (Ass 'z' (Num 1))       
        (While (Var 'y') (Seq (Ass 'z' (Mul (Var 'z') (Var 'y')))
                              (Ass 'y' (Add (Var 'y') (Num (-1))))))

当我在某些内存状态和命令上运行该函数时,它只会打印出起始内存和终止内存,例如,如果我运行debug [('y',4)] com1,我得到的只是[[('y',0),('z',24)],[('y',4)]]而我需要打印

When I run the function onto certain memory states and commands it only prints out the starting memory and the terminated memory for example if I run debug [('y',4)] com1 all I get is [[('y',0),('z',24)],[('y',4)]] whereas I need it to print

  [('y',4)]
  [('y',4),('z',1)]
  [('y',4),('z',4)]
  [('y',3),('z',4)]
  [('y',3),('z',12)]
  [('y',2),('z',12)]
  [('y',2),('z',24)]
  [('y',1),('z',24)]
  [('y',1),('z',24)]
  [('y',0),('z',24)]

我想问的问题是,我需要在调试功能中进行哪些更改才能使其以递归方式打印?

The question I want to ask what do I need to change in my debug function to get it to print recursively?

推荐答案

比较您的execdebug函数,我们可以看到为什么您的debug并没有打印出所有中间状态:它只取状态exec返回并附加到原始内存状态m.

Comparing your exec and debug functions, we can see why your debug doesn't print out all intermediate states: it just takes the state returned by exec and attaches it to the original memory state m.

由于exec不会保存中间存储器状态,并且由于debug基本上已经是exec,所以我建议只重写debug来递归地调用自身,而不是exec.另外,让我们将debug的返回类型更改为([Memory], Memory) -第一个组件将是所有先前状态的列表,第二个组件将是最新的结果. (严格来说,由于最近的结果是历史的一部分,所以不需要这样做,但这将有助于使我们的代码更整洁,并且更通用一些-我们可以轻松地更改debug来保留内存以外的内容历史记录,例如执行的操作的日志.)

Since exec doesn't save the intermediate memory states and since the debug is basically exec already, I suggest just rewriting debug to call itself recursively instead of exec. Also, let's change the return type of debug to be ([Memory], Memory) -- the first component will be the list of all previous states, and the second will be the most recent result. (Strictly speaking, since the most recent result is part of the history, this isn't needed, but it will help keep our code cleaner, and is more general -- we could easily change debug to keep something other than the memory history, such as a log of operations performed.)

无论如何,我们得到这样的东西:

Anyway, we get something like this:

debug :: Memory -> Com -> ([Memory], Memory)
debug m (Ass c e)   = ([m'],m')
  where m' = update m (c, eval m e)

剩下的我留给你-不太困难.

I'll leave the rest to you -- it's not too difficult.

这还不错.但是,仍然存在一些问题:

This isn't too bad. However, there are still a few problems:

  • 完成的程序肯定会使用++,这有点令人恐惧-我们很容易以程序结束时,将时间记为日志长度的二次方(例如,如果我们的日志是按相反的时间顺序编写的) ,我们会重复将早期状态附加到长列表的末尾.
  • 我们基本上已经复制(并略微丑化了)原始的exec.
  • The finished program will certainly use ++, which is a bit frightening -- we could easily end up with a program taking time quadratic in the length of the log (for instance, if our log were written in reverse chronological order, we would repeatedly append the early states to the end of a long list).
  • We've basically duplicated (and slightly uglified) the original exec.

上面的程序是功能编程模式"的典型示例,称为对状态进行线程化".在该模式中,我们向函数调用的返回类型添加一些信息,以存储有关我们历史记录的信息程序.实际上,您可以将该程序视为线程化两种状态:我们都检查和修改的内存状态,以及仅写入但从未读取的日志.

The program above is a typical example of the functional programming "pattern" known as threading the state, where we add some information to the return type of function calls to store information about the history of our program. You can actually think of this program as threading two types of state: the memory, which we both examine and modify, and the log, which we only write to but never read.

当然,函数式编程完全与抽象有关,并且有解决上述问题并消除线程化"模式的著名方法:monads!

Of course, functional programming is all about abstraction, and there are well-known ways to solve the above problems and eliminate the "threading" pattern: monads!

您可以使用 Writer monad 消除日志的显式线程.

You can use the Writer monad to eliminate the explicit threading of the log.

奖金:您可以使用 state monad 并使用它来消除内存状态的显式线程化.

Bonus: you can use the state monad and use it to eliminate the explicit threading of the memory state.

您可以使用差异列表来消除对++的潜在昂贵使用.

You can use difference lists to eliminate potentially expensive use of ++.

要了解所有这些主题,我建议您倒数第二章了解您的Haskell ,之后您应该可以使用标准库中定义的monad.

To learn about all of these topics, I recommend the penultimate chapter of Learn You a Haskell, after which you should be able to use the monads defined in the standard libraries.

这篇关于每次连续执行后如何打印出内存状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆