代码之家  ›  专栏  ›  技术社区  ›  Sarah Vessels

Goto与运行时代码评估的使用

  •  4
  • Sarah Vessels  · 技术社区  · 15 年前

    最近在一个编程课上,我们被指派用任何语言编写一个程序。 N号 ,将为数组生成所有可能的异常 尺寸的 N号 这样 P [我]!=i代表所有i:0<=i<n。我们必须使用迭代器,例如 yield .

    例如:n=3,[0,1,2]不是一种精神错乱,但[2,0,1]和[1,2,0]一样。

    我想出了一个可行的伪代码解决方案,但问题是它需要电源循环(也就是说, n 嵌套循环,其中 N号 只有在运行时才知道)。为此,我生成 n 以字符串形式嵌套Ruby代码中的循环,然后 eval -Ed那根绳子。我的解决方案有效,但是我的教授认为 goto 与动态代码生成相比,S是更好的解决方案(至少更容易阅读)。

    我觉得 古托 总是一个糟糕的选择。为什么动态生成代码的运行时评估比 古托 ?生成的代码干净简单,对于给定的问题似乎相当有效。代码生成所依赖的唯一用户输入是 n ,检查以确保它是一个整数值。它 产量 只不过是独特的精神错乱。

    我不是在要求解决我的编程任务,我只是想知道使用 古托 动态代码评估,反之亦然。

    编辑: 为了澄清,这个分配包括使用迭代器编写程序和使用递归编写另一个程序,因此迭代版本并不一定意味着高效。

    11 回复  |  直到 12 年前
        1
  •  2
  •   Murph    15 年前

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

    goto的问题在于它以非结构化的方式使用——goto是一个“巨大的随机跳跃”,因此在一般情况下,在跳跃之后,您不知道从何而来,这会导致调试和可维护性方面的各种问题,并且——在更正式的意义上,证明代码的“正确性”。当然,有些语言(我已经使用了一段时间)是没有选择的,在这种情况下,您可以将结构强加于代码。归根结底,并不是说goto是坏的,而是goto被使用(和滥用)的方式是坏的,这使得goto成为可用的危险构造。

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

    一个递归的解决方案——特别是当我隐约记得(大约25年前)被教导通常可以将递归展开为循环时——可能是最优雅的。

    绝对是个有趣的问题!

        2
  •  6
  •   Asaph    15 年前

    goto和代码生成都是针对imo这个问题的不完美的解决方案。 正确的 这里回答。

        3
  •  2
  •   Ralph Shillington    15 年前

    如果没有看到您的代码,我倾向于站在教授一边。如果这是goto和动态代码之间的选择,我会倾向于前者。Goto不是 总是 一个糟糕的选择。

        4
  •  2
  •   Kasper Holdum    15 年前

    你几乎可以解决所有的问题而不使用goto。特别是对于循环,您可以使用break和continue语句在代码标准仍然保持不变的情况下隐式使用goto。

    n 嵌套循环听起来像是一个糟糕的计划,我建议您改为研究递归函数。每次你需要做一个n循环时,你都应该考虑递归。

        5
  •  2
  •   Matthew Vines    15 年前

    动态代码是不可编译时检查的,这意味着在运行时才会检测到任何错误。可能使他们更难找到。对于Ruby,这意味着无论您使用哪种语言,IDE或编辑器都不会发现语法错误。这是选择Goto的好处。

    我想在这种情况下,我必须看到两者都做出决定。我没有看到代码,但我敢打赌,有一个好的解决方案不使用动态代码,也不使用goto的。goto并不总是坏的,但是如果你想使用它,你可能到目前为止还没有做出最佳的设计决策,可能想重新访问你的解决方案。

        6
  •  1
  •   Laurent Bourgault-Roy    15 年前

    在我大学的一次任务中,我曾经做过一些相对相似的事情。 我的解决方案是使用递归函数,将数组、数组大小和嵌套级别作为参数传递。然后函数用嵌套级别+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,所以我很肯定总有办法避免它们。

        7
  •  1
  •   Nick    15 年前

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

    如果没有看到您的代码,我想比使用goto的等效程序更难理解…

        8
  •  1
  •   Larry Watanabe    15 年前

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

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

    选项严格打开 选项显式打开

    模块模块1 作为堆栈的模糊X

    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
    

    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
    

    端模块

        9
  •  0
  •   Atmocreations    15 年前

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

    如果速度真的是一件重要的事情,例如,如果你想写一个库或代码,你有很大的存在,你可以考虑使用goto。你一定要注意一切都很顺利。

    评论 :最后,执行CPU只执行简单的跳转。只是编程语言/编译器创建它们。小心使用,不要弄乱。

        10
  •  0
  •   Larry Watanabe    15 年前

    Goto解决方案和动态代码生成思想都不好。这很容易用其他人提到的递归解决方案来解决。您只需递归地生成所有置换(标准递归解决方案),当生成完成(即在递归的叶中)时,只需跳过返回的不是混乱的置换。

        11
  •  0
  •   Larry Watanabe    15 年前

    递归解决方案——这里有一个早期修剪的解决方案。我唯一的问题是关于枚举:他是否希望您创建一个枚举器,以便在每次成功调用时都生成列表中的下一项?通过创建这个程序的lambda版本,这可能是最容易实现的——在编写查询生成器时,我经常在lisp中这样做,在执行prolog解释器样式的查询时,查询生成器将生成问题的下一个答案。

    选项严格打开 选项显式打开

    模块模块1

    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
    

    端模块