使用 goto 与运行时代码评估

发布于 2024-08-04 17:03:58 字数 770 浏览 3 评论 0原文

最近,在编程课上,我们被分配用任何语言编写一个程序,给定n,将为大小<的数组p产生所有可能的混乱。 em>n 使得 p[i] != i 对于所有 i: 0 <= i <名词我们必须使用迭代器,例如yield

示例:n=3,[0, 1, 2] 不是乱序,但 [2, 0, 1] 和 [1, 2, 0] 一样。

我想出了一个可行的伪代码解决方案,但问题是它需要电源循环(即,n 个嵌套循环,其中 n 仅在运行时才知道)。为此,我在字符串中的 Ruby 代码中生成了n 个嵌套循环,然后对该字符串进行了eval-ed。我的解决方案有效,但是我的教授认为使用一些 goto 会比动态代码生成更好的解决方案(至少更容易阅读)。

我的印象是 goto 始终是一个糟糕的选择。为什么动态生成代码的运行时评估可能比 goto 更糟糕?生成的代码干净简单,对于给定的问题似乎相当有效。代码生成所依赖的唯一用户输入是n,它会被预先检查以确保它是一个整数值。它产生只是独特的混乱,正如它应该的那样。

我不是要求解决我的编程作业,我只是想知道使用 goto 而不是动态代码评估背后的原因,反之亦然。

编辑:澄清一下,作业包括使用迭代器编写一个程序和使用递归编写另一个程序,因此迭代版本不一定是高效的。

Recently for a programming class, we were given the assignment to write a program in any language that, given n, will produce all the possible derangements for an array p of size n such that p[i] != i for all i: 0 <= i < n. We had to use iterators, e.g. yield.

Example: n=3, [0, 1, 2] is not a derangement, but [2, 0, 1] is as well as [1, 2, 0].

I came up with a pseudocode solution that would work, but the problem was that it required power loops (that is, n nested loops where n is only known at runtime). To do this, I generated n nested loops in Ruby code in a string, then eval-ed the string. My solution worked, however my professor thought that using a few gotos would have been better solution (easier to read, at least) than dynamic code generation.

I was under the impression that goto was always a bad choice. Why might runtime evaluation of dynamically generated code be a worse choice than goto? The generated code is clean and simple, and seems fairly efficient for the given problem. The only user input upon which the code generation depends is n, which is checked to ensure it's an integer value beforehand. It yields only unique derangements, as it should.

I'm not asking for a solution to my programming assignment, I just want to know reasons behind the use of goto over dynamic code evaluation, or vice versa.

Edit: to clarify, the assignment included writing a program using iterators and another using recursion, so the iterative version wasn't necessarily meant to be efficient.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

半透明的墙 2024-08-11 17:03:58

在我看来,GOTO 和代码生成对于这个问题来说都是不优雅的解决方案。有一种递归算法可能是这里的正确答案。

Both GOTO and code generation are inelegant solutions to this problem IMO. There is a recursive algorithm that is probably the right answer here.

小梨窩很甜 2024-08-11 17:03:58

这是一个非常有趣的问题 - 我不确定是否有明确的答案。

goto 的问题在于它以非结构化方式使用 - goto 是一种“大规模随机跳跃”,因此在一般情况下,在跳跃之后,您不知道自己来自哪里,这会导致各种问题调试和可维护性,以及 - 在更正式的意义上证明代码的“正确性”。当然,在某些语言(我已经使用了一段时间)中,您无法选择在代码上强加结构。底线是,并不是 GOTO 不好,而是 goto 的使用(和滥用)方式不好,这使得它成为一个危险的结构。

使用代码生成然后评估结果是聪明的:)然而“聪明”并不总是一件好事,我怀疑使用它作为解决方案的部分问题在于它实际上没有按预期解决问题。从某种意义上说,这可能是“作弊”——至少就你的教授而言——不会使你的解决方案无效,但可能会使其“不优雅”。代码方面还存在调试和维护问题。

递归解决方案——尤其是我依稀记得有人教我(大约 25 年前),人们通常可以将递归展开到循环中——可能是最优雅的。

绝对是一个有趣的问题!

That's a really interesting question - I'm not sure that there's a definitive answer.

The problem with goto is its use in an unstructured fashion - a goto is a "massive random leap" so in the general instance, after the jump, you don't know where you came from which causes all kinds of issues both in terms of debugging and maintainability and - in a more formal sense with proving "correctness" of the code. Of course there are languages (I've been around a while) where you don't have an option at which point you impose structure on the code. The bottom line is that its not that GOTO is bad so much as the way that goto is used (and abused) that is bad and that makes its a dangerous construct to have available.

Using code generation and then evaluating the result is clever :) However "clever" is not always a good thing and I suspect that in part the issue with using that as a solution is that its not actually addressing the problem as intended. That may be "cheating" in a sense - at least so far as your professor is concerned - doesn't invalidate your solution but may render it "inelegant". The debugging and maintainance issues also arise in respect of the code.

A recursive solution - especially as I vaguely remember being taught (some 25 years ago) that one can usually unwind recursion into loops - would probably be the most elegant.

Definitely an interesting question!

黯然 2024-08-11 17:03:58

如果没有看到你的代码,我会倾向于站在教授一边。如果要在 GoTo 和动态代码之间进行选择,我会倾向于前者。 GoTo 并不总是一个糟糕的选择。

Without seeing your code, I would tend to side with the prof. If it's a choice between GoTo and dynamic code, I would lean towards the former. GoTo are not always a bad choice.

征棹 2024-08-11 17:03:58

无需使用 GoTos 即可解决几乎所有问题。特别是对于循环,您可以使用 break 和 continue 语句来隐式使用 goto,同时仍保持代码标准。

n 嵌套循环听起来像是一个糟糕的计划,我建议您转而研究递归函数。每次需要执行 n 循环时,您都应该始终考虑递归。

You can solve almost all problems without the use of GoTos. Specifically with loops you can use the break and continue statements to implitly use gotos while code standard are still maintained.

n nested loops sound like a bad plan, and I suggest that you instead look into a recursive functions. Every single time you need to do a n-loops you should always be thinking recursion.

§普罗旺斯的薰衣草 2024-08-11 17:03:58

动态代码在编译时不可检查,这意味着在运行时之前不会检测到任何错误。可能会使它们更难找到。对于 ruby​​,这意味着 IDE 或编辑器不会发现语法错误,无论您使用的是哪一个。这是选择 goto 的一个优点。

我认为在这种情况下我必须同时考虑双方的意见才能做出决定。我还没有看到代码,但我愿意打赌有一个很好的解决方案,不使用动态代码或 goto。 goto 并不总是不好,但如果您正在考虑使用它,那么您可能到目前为止还没有做出最佳的设计决策,并且可能想要重新审视您的解决方案。

Dynamic code is not compile time checkable, which means any errors will go undetected until run time. Potentially making them harder to find. For ruby, this would mean that syntax errors would not be found by the IDE or editor, whichever you happen to be using. That is a plus for choosing goto.

I think I would have to see both to make a decision in this case. I haven't seen the code, but I'm willing to bet there is a good solution that doesn't use dynamic code, or goto's. goto is not always bad, but if you are thinking of using it you probably have not made the best design decisions up to this point and probably want to revisit your solution.

北座城市 2024-08-11 17:03:58

在我大学的一项作业中,我曾经不得不做一些相对相似的事情
我的解决方案是使用递归函数,传递数组、数组的大小和嵌套级别作为参数。然后该函数以嵌套级别 +1 调用自身,直到嵌套级别等于数组的大小。没有 Goto,没有代码评估,只有干净的代码!

例子

function computeDerangement(yourArray, loopLevel, arraySize)
{
    //We check to see if the loop level is the same as the array size
    //if true, then we have executed exactly n loop
    if (loopLevel == arraySize) {
         display(yourArray); //Display being some kind of function that show the array,
                             //you get the idea
    } else {
        while(something) {
            //Here you put the logic that you execute at one level of the loop

            //Then you call yourself with one more level of nesting
            computeDerangement(yourArray, loopLevel + 1, arraySize);
        }
    }
}

希望有帮助!

我一生中从未使用过 goto,所以我很确定总有办法避免它们

In one of my assignement in college, I once had to do something that was relatively similar
My solution was to use a recursive function, passing the array, the size of the array and the nesting level as argument. The function then call itself with nesting level +1, until the nesting level is equal to the size of the array. No Goto, no code evaluation, only clean code!

Example

function computeDerangement(yourArray, loopLevel, arraySize)
{
    //We check to see if the loop level is the same as the array size
    //if true, then we have executed exactly n loop
    if (loopLevel == arraySize) {
         display(yourArray); //Display being some kind of function that show the array,
                             //you get the idea
    } else {
        while(something) {
            //Here you put the logic that you execute at one level of the loop

            //Then you call yourself with one more level of nesting
            computeDerangement(yourArray, loopLevel + 1, arraySize);
        }
    }
}

Hope that help!

I have never used goto in my life, so I'm pretty sure there is always a way to avoid them

苏大泽ㄣ 2024-08-11 17:03:58

人们避免使用 goto 语句的主要原因是它们会让你的程序更难理解。

如果没有看过你的代码,我猜它比使用 goto 的等效程序更难理解......

The main reason people avoid goto statements is that they can make your program more difficult to understand.

Without having seen your code, I'd guess it's more difficult to understand than the equivalent program using goto...

忆沫 2024-08-11 17:03:58

GOTO 解决方案——模拟函数调用时,goto 很方便。这是一个非递归解决方案,它使用堆栈和 goto 标签简单地模拟递归解决方案,以返回到函数调用发生的位置。

请参阅递归过程(我已将其作为单独的答案发布)进行比较。

选项严格开启
上显式选项

模块 Module1
Dim x As Stack

Private Sub printGeneratedList(ByVal generatedList As List(Of Integer))
    For Each el In generatedList
        Console.Write(el & " ")
    Next
    Console.WriteLine()
End Sub
Private Sub generateAux(ByVal i As Integer, ByVal n As Integer, _
                        ByVal generatedList As List(Of Integer))
    Dim stackI As Stack(Of Integer) = New Stack(Of Integer)
    Dim stackJ As Stack(Of Integer) = New Stack(Of Integer)


    Dim j As Integer

开始标签:

    j = 0

    If i >= n Then
        printGeneratedList(generatedList)
        If stackI.Count = 0 Then
            Return
        Else
            GoTo ReturnLabel
        End If
    End If

     While j < n
        If Not j = i Then
            If Not generatedList.Contains(j) Then
                generatedList.Add(j)
                stackI.Push(i)
                stackJ.Push(j)
                i = i + 1
                GoTo StartLabel

返回标签:

                i = stackI.Pop()
                j = stackJ.Pop()
                generatedList.Remove(j)
            End If
        End If
        j = j + 1
    End While
    If stackI.Count = 0 Then
        Return
    Else
        GoTo ReturnLabel
    End If
End Sub

Private Sub generate(ByVal n As Integer)
    Console.WriteLine("Generating for n = " & n.ToString())
    Dim l As List(Of Integer) = New List(Of Integer)
    If n < 0 Then
        Throw New Exception("n must be >= 0")
    End If
    generateAux(0, n, l)
End Sub

Sub Main()
    generate(0)
    Console.ReadLine()
    generate(1)
    Console.ReadLine()
    generate(2)
    Console.ReadLine()
    generate(3)
    Console.ReadLine()
    generate(4)
    Console.ReadLine()
End Sub

结束模块

GOTO Solution -- a goto is convenient when simulating a function call. Here's a non-recurisve solution that simply simulates the recursive solution using a stack and a goto label to return to the point where the function call would have occurred.

See the recursive procedure (I have posted this as a separate answer) for comparison.

Option Strict On
Option Explicit On

Module Module1
Dim x As Stack

Private Sub printGeneratedList(ByVal generatedList As List(Of Integer))
    For Each el In generatedList
        Console.Write(el & " ")
    Next
    Console.WriteLine()
End Sub
Private Sub generateAux(ByVal i As Integer, ByVal n As Integer, _
                        ByVal generatedList As List(Of Integer))
    Dim stackI As Stack(Of Integer) = New Stack(Of Integer)
    Dim stackJ As Stack(Of Integer) = New Stack(Of Integer)


    Dim j As Integer

StartLabel:

    j = 0

    If i >= n Then
        printGeneratedList(generatedList)
        If stackI.Count = 0 Then
            Return
        Else
            GoTo ReturnLabel
        End If
    End If

     While j < n
        If Not j = i Then
            If Not generatedList.Contains(j) Then
                generatedList.Add(j)
                stackI.Push(i)
                stackJ.Push(j)
                i = i + 1
                GoTo StartLabel

ReturnLabel:

                i = stackI.Pop()
                j = stackJ.Pop()
                generatedList.Remove(j)
            End If
        End If
        j = j + 1
    End While
    If stackI.Count = 0 Then
        Return
    Else
        GoTo ReturnLabel
    End If
End Sub

Private Sub generate(ByVal n As Integer)
    Console.WriteLine("Generating for n = " & n.ToString())
    Dim l As List(Of Integer) = New List(Of Integer)
    If n < 0 Then
        Throw New Exception("n must be >= 0")
    End If
    generateAux(0, n, l)
End Sub

Sub Main()
    generate(0)
    Console.ReadLine()
    generate(1)
    Console.ReadLine()
    generate(2)
    Console.ReadLine()
    generate(3)
    Console.ReadLine()
    generate(4)
    Console.ReadLine()
End Sub

End Module

锦上情书 2024-08-11 17:03:58

goto 不干净。但是如果需要高性能,有时您需要打破一些编码规则...

如果速度确实很重要,例如,如果您想编写一个非常迫切的库或代码,您可能会考虑使用 goto 。当然你必须注意一切顺利。

评论:最后,执行的CPU除了简单的跳转之外什么也不做。只是编程语言/编译器创建它们。谨慎使用,不要乱用。

goto's are not clean. but if high performance is required, you need to break some of those coding rules sometimes...

if speed is really an important matter, for example if you want to write a library or code you have big exigeance on, you might consider using goto. for sure you have to pay attention that everything goes well.

Comment: At the end, the executing CPU does nothing else than simple jumps. Just only that the programming language / the compiler creates them. use with caution and don't mess with it.

一笔一画续写前缘 2024-08-11 17:03:58

goto 解决方案和动态代码生成想法都不好。正如其他人提到的,这可以通过递归解决方案轻松解决。您只需递归地生成所有排列(标准递归解决方案),并且当生成完成时(即在递归的叶子处),只需跳过返回不是混乱的排列。

Both the goto solution and dynamic code generation ideas are bad. This is easily solved with a recursive solution as mentioned by others. You simply recursively generate all permutations (standard recursive solution) and when generation is complete (ie at the leaf of the recursion) simply skip returning permutations that are not derangements.

扶醉桌前 2024-08-11 17:03:58

递归解决方案——这是一个早期修剪的解决方案。我唯一的问题是关于枚举:他是否希望您创建一个枚举器,在每次成功调用时都会生成列表中的下一项?通过创建该程序的 lambda 版本,这可能是最简单的实现方法 - 在编写查询生成器时,我一直在 lisp 中执行此操作,该查询生成器在执行 prolog 解释器样式查询时生成问题的下一个答案。

选项严格开启
模块上显式选项

Module1

Private Sub printGeneratedList(ByVal generatedList As List(Of Integer))
    For Each el In generatedList
        Console.Write(el & " ")
    Next
    Console.WriteLine()
End Sub

Private Sub generateAux(ByVal i As Integer, ByVal n As Integer, _
                    ByVal generatedList As List(Of Integer))
    If i >= n Then
        printGeneratedList(generatedList)
        Return
    End If
    For j As Integer = 0 To n - 1
        If Not j = i Then
            If Not generatedList.Contains(j) Then
                generatedList.Add(j)
                generateAux(i + 1, n, generatedList)
                generatedList.Remove(j)
            End If
        End If
    Next
End Sub

Private Sub generate(ByVal n As Integer)
    Console.WriteLine("Generating for n = " & n.ToString())
    Dim l As List(Of Integer) = New List(Of Integer)
    If n < 0 Then
        Throw New Exception("n must be >= 0")
    End If
    generateAux(0, n, l)
End Sub

Sub Main()
     generate(0)

    Console.ReadLine()
    generate(1)

    Console.ReadLine()
    generate(2)

    Console.ReadLine()
    generate(3)

    Console.ReadLine()
    generate(4)

    Console.ReadLine()

End Sub

终端模块

Recursive solution -- here's a solution with early pruning. My only question is regarding enumerations: did he want you to create an enumerator that on each successful call would generate the next item in the list? This would probably be easiest implemented by creating a lambda version of this program - I used to do this in lisp all the time when writing query generators that would generate the next answer to a question when doing prolog-interpreter style queries.

Option Strict On
Option Explicit On

Module Module1

Private Sub printGeneratedList(ByVal generatedList As List(Of Integer))
    For Each el In generatedList
        Console.Write(el & " ")
    Next
    Console.WriteLine()
End Sub

Private Sub generateAux(ByVal i As Integer, ByVal n As Integer, _
                    ByVal generatedList As List(Of Integer))
    If i >= n Then
        printGeneratedList(generatedList)
        Return
    End If
    For j As Integer = 0 To n - 1
        If Not j = i Then
            If Not generatedList.Contains(j) Then
                generatedList.Add(j)
                generateAux(i + 1, n, generatedList)
                generatedList.Remove(j)
            End If
        End If
    Next
End Sub

Private Sub generate(ByVal n As Integer)
    Console.WriteLine("Generating for n = " & n.ToString())
    Dim l As List(Of Integer) = New List(Of Integer)
    If n < 0 Then
        Throw New Exception("n must be >= 0")
    End If
    generateAux(0, n, l)
End Sub

Sub Main()
     generate(0)

    Console.ReadLine()
    generate(1)

    Console.ReadLine()
    generate(2)

    Console.ReadLine()
    generate(3)

    Console.ReadLine()
    generate(4)

    Console.ReadLine()

End Sub

End Module

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文