如果我知道跟踪输出的外观,我该如何开始创建我的函数? (方案)
If i know how a traced output looks, how can i begin creating my function? (Scheme)
我很难尝试学习在 scheme 中编程。我的教授说我一直陷入程序性思维的陷阱。我知道他是对的。我想学习如何做到这一点,但是,阅读书籍对我来说变得反直觉,因为这些应该是简单的项目,无论如何都不需要大量的阅读和研究。
从概念上讲,我了解跟踪函数的外观。 (虽然我可能是错的)
在这种情况下,我正在开发一个名为 ndelete 的程序,它接受一个列表和 returns 列表,每个元素都被删除。
下面是我认为我的函数应该是什么样子的。
ndelete( '( a b c d e) 2)
(a b c d e)
> (b c d e)
> > (c d e)
> > > (d e)
> > > > (e)
> > > > > ( )
< < < < < ( ) ; return null
< < < < (e) ; return e 1
< < < (e) ; return 'd 2 removed 'd,
< < (c e); return 'c 3
< (c e) ; return 'b 4 removed'b
(a c e) ; return 'a 5
我觉得我应该很容易知道这一点,这很令人沮丧。也许,有人可以为我指明正确的方向,或者告诉我如何利用我在概念上的理解。
这是我尝试的代码。我使用一些我认为可以从我教授的示例中使用的示例代码随意地将它组合在一起。
(define x '(1 2 3 4 5 6 7 8 9 10))
(define ndelete(lambda (alist n)
(if '()
(car alist)
(ndelete (cdr alist)
(- n 1))
)))
(ndelete x 10)
尝试从示例中概括是一种常见的做法,前提是:
你的例子并不太局限。您希望确保涵盖所有功能案例。跟踪对此有好处,因为不同的情况通常发生在递归函数的不同深度。此外,您可能需要尝试多个示例才能信任您的解决方案。
您确信跟踪代表了实际可能的执行,而不仅仅是伪造的(例如跳过一个步骤或 return 突然出现不同的结果)。请记住,走线可能形成不当。你最终会通过仔细检查并用你的例子来检验你的函数来发现这是否属实。
不要试图一次写完所有内容,根据您所看到的和可以推断的逐步构建您的函数。我相信大多数有经验的函数式程序员仍然会执行以下步骤,但可能只是在他们的脑海中(随着时间的推移,模式将开始出现)。
在这里,你知道你得到了一个列表和一个数字:你称它们为 lst
和 n
,因为在 Scheme 中其他人都是这样做的。您还知道函数应该 return 一个列表。
(a b c d e)
> (b c d e)
...
< (c e)
(a c e)
- 从顶部开始的第二行告诉您应该使用
(cdr lst)
递归调用该函数作为列表参数。
- 最后一行表明您必须 cons
(car lst)
在结果值之上。
你可以写初稿:
(define ndelete
(lambda (lst n)
(cons (car lst) (ndelete (cdr lst) n))))
但这还不够,因为你的函数没有解释trace的其他部分,像这样:
> > > > > ( )
< < < < < ( )
显然空列表应该有一个基本情况。
我们更新函数:
(define ndelete
(lambda (lst n)
(if (null? lst)
'()
(cons (car lst) (ndelete (cdr lst) n)))))
这是另一个不一致的地方:
> > > (d e)
> > > > (e)
....
< < < < (e)
< < < (e)
你并不总是 cons
。事实上,只有当你在跟踪中有偶数个 <
时才这样做,这对应于调用函数时的偶数个 >
。您了解 2 应该概括为 n
并且您必须添加一个计数器。
您可能想重用现有的 n
,但对于初稿,请添加另一个参数。如果真的可以从n
推导出来,以后有机会再写。
必须将计数器从一个级别传递(和修改)到另一个级别。我不会在这里复制粘贴,但结果是 Chris Jester-Young's answer。他使用了一个本地函数,但那是一种可以在之后完成的重构。
我很难尝试学习在 scheme 中编程。我的教授说我一直陷入程序性思维的陷阱。我知道他是对的。我想学习如何做到这一点,但是,阅读书籍对我来说变得反直觉,因为这些应该是简单的项目,无论如何都不需要大量的阅读和研究。
从概念上讲,我了解跟踪函数的外观。 (虽然我可能是错的) 在这种情况下,我正在开发一个名为 ndelete 的程序,它接受一个列表和 returns 列表,每个元素都被删除。
下面是我认为我的函数应该是什么样子的。
ndelete( '( a b c d e) 2)
(a b c d e)
> (b c d e)
> > (c d e)
> > > (d e)
> > > > (e)
> > > > > ( )
< < < < < ( ) ; return null
< < < < (e) ; return e 1
< < < (e) ; return 'd 2 removed 'd,
< < (c e); return 'c 3
< (c e) ; return 'b 4 removed'b
(a c e) ; return 'a 5
我觉得我应该很容易知道这一点,这很令人沮丧。也许,有人可以为我指明正确的方向,或者告诉我如何利用我在概念上的理解。
这是我尝试的代码。我使用一些我认为可以从我教授的示例中使用的示例代码随意地将它组合在一起。
(define x '(1 2 3 4 5 6 7 8 9 10))
(define ndelete(lambda (alist n)
(if '()
(car alist)
(ndelete (cdr alist)
(- n 1))
)))
(ndelete x 10)
尝试从示例中概括是一种常见的做法,前提是:
你的例子并不太局限。您希望确保涵盖所有功能案例。跟踪对此有好处,因为不同的情况通常发生在递归函数的不同深度。此外,您可能需要尝试多个示例才能信任您的解决方案。
您确信跟踪代表了实际可能的执行,而不仅仅是伪造的(例如跳过一个步骤或 return 突然出现不同的结果)。请记住,走线可能形成不当。你最终会通过仔细检查并用你的例子来检验你的函数来发现这是否属实。
不要试图一次写完所有内容,根据您所看到的和可以推断的逐步构建您的函数。我相信大多数有经验的函数式程序员仍然会执行以下步骤,但可能只是在他们的脑海中(随着时间的推移,模式将开始出现)。
在这里,你知道你得到了一个列表和一个数字:你称它们为 lst
和 n
,因为在 Scheme 中其他人都是这样做的。您还知道函数应该 return 一个列表。
(a b c d e)
> (b c d e)
...
< (c e)
(a c e)
- 从顶部开始的第二行告诉您应该使用
(cdr lst)
递归调用该函数作为列表参数。 - 最后一行表明您必须 cons
(car lst)
在结果值之上。
你可以写初稿:
(define ndelete
(lambda (lst n)
(cons (car lst) (ndelete (cdr lst) n))))
但这还不够,因为你的函数没有解释trace的其他部分,像这样:
> > > > > ( )
< < < < < ( )
显然空列表应该有一个基本情况。 我们更新函数:
(define ndelete
(lambda (lst n)
(if (null? lst)
'()
(cons (car lst) (ndelete (cdr lst) n)))))
这是另一个不一致的地方:
> > > (d e)
> > > > (e)
....
< < < < (e)
< < < (e)
你并不总是 cons
。事实上,只有当你在跟踪中有偶数个 <
时才这样做,这对应于调用函数时的偶数个 >
。您了解 2 应该概括为 n
并且您必须添加一个计数器。
您可能想重用现有的 n
,但对于初稿,请添加另一个参数。如果真的可以从n
推导出来,以后有机会再写。
必须将计数器从一个级别传递(和修改)到另一个级别。我不会在这里复制粘贴,但结果是 Chris Jester-Young's answer。他使用了一个本地函数,但那是一种可以在之后完成的重构。