我有一个命令式编程背景,我决定研究函数式编程,将其应用于Euler和Rosalind等网站上的问题。我选择的语言是“计划”(我用鸡肉)。可以看到,我才刚开始。
这是在Rosalind上发现的第三个问题,类似于这:
在DNA字符串中,符号'A‘和'T’是相互补充的,'C‘和'G’也是互补的。DNA串s的反向补码是通过倒转S的符号形成的字符串sc,然后取每个符号的补码(例如,"GTCA“的反向补码是"TGAC")。给出:一条长度不超过1000 bp的DNA串S。回报: s的反向补足。
下面是我的代码,它解决了这个问题:
(define (complement-of char)
(cond
((eq? char #\A)
#\T)
((eq? char #\T)
#\A)
((eq? char #\C)
#\G)
((eq? char #\G)
#\C)
(else
char)))
(define (apply-complements dna-string)
(reverse-list->string
(map complement-of
(string->list dna-string))))
(define (solve-problem infile-name outfile-name)
(let ((outfile-port (open-output-file outfile-name))
(infile-port (open-input-file infile-name)))
(begin
(write-line
(apply-complements (read-line infile-port)) outfile-port)
(close-output-port outfile-port))))有更好的方法来编写complement-of吗?也许是像字典那样的东西,或者在这个特殊的情况下,这会不会是太多的工作呢?
solve-problem是否适合于样式POV,还是更合适?
(define (solve-problem infile-name outfile-name)
(let ((outfile-port (open-output-file outfile-name))
(infile-port (open-input-file infile-name)))
(begin
(write-line
(apply-complements
(read-line infile-port))
outfile-port)
(close-output-port outfile-port))))另外,是否有一种方法可以避免使用begin,同时仍然使事物看起来可读性?想到的唯一想法是提取一个函数,通过递归决定它是写到文件中还是关闭它。但这感觉很难直觉。
最后,我想听听我的代码还有什么其他问题。
发布于 2014-05-13 06:46:54
complement-of编写complement-of的更好方法是使用case而不是cond:
(case char
((#\A) #\T)
((#\T) #\A)
((#\C) #\G)
((#\G) #\C)
(else char))函数名一般不应该以-of结尾。(这是一种发音函数调用的方法,但它不是名称的一部分。) complement就足够了。(虽然有些方案有一个预先定义的函数,但最好不要与它发生冲突。)
提防eq? -它不可靠的字符。(这相当于Java的== on Character)。使用eqv?代替,除非你知道你在做什么。(case在内部使用eqv?。)
apply-complements您可以通过使用小鸡的一个库来简化apply-complements:(use (srfi 13))获取string-map,这与map类似,但可以节省转换为列表的费用。加上string-reverse,apply-complements变得容易了。
...but --我不称它为apply-complements,因为这听起来像是对apply函数的引用。它返回其参数的反向补码,因此应该是它的名称:reverse-complement。
如果您想使它更快,请尝试命令式方法:用make-string分配字符串,用do和string-set!循环。(知道如何编写命令式代码非常有用,即使在函数式语言中也是如此。)
solve-problemsolve-problem有一个非常普通的错误:您忘记关闭输入端口。)幸运的是,有些函数可以自动完成此操作,因此您不必记住:call-with-input-file和call-with-output-file。它们也更安全,因为它们像例外一样关闭非本地出口的端口。
let的主体是隐式begin,因此不需要solve-problem中的begin。
格式化:当函数调用被分割为多行时,参数通常是对齐的,如下所示:
(write-line (apply-complements (read-line infile-port))
outfile-port)solve-problem有一个模糊的名字。如何描述一下它所做的事情,如reverse-complement-file?(名字是最好的评论。)
...however,reverse-complement只是您可能希望以这种方式应用于文件的许多操作之一。我可能会把它写成一个通用的transform-file,它将操作作为参数:(transform-file reverse-complement src dest)。或者,我会把它写成两个独立的操作,用于读写,因为它们通常是分开使用的。(我还会使用read-string和write-string,而不是read-line和write-line,这样它们就可以处理多行文件。)
发布于 2014-05-12 23:55:10
您可以使用字典/散列,但对于4种选择,这是过分的。
在我看来,apply-compliments只是compliment-of之上的地图。我将调用核心函数reverse-compliment。顺便说一句,如果我正确地阅读了问题描述,那么您可以反转字符串,然后应用赞美词,但您似乎是在恭维,然后又倒转。当然,从功能上来说,这并不重要。
老实说,我的方案有点生疏,但我认为既然您是let格式的,您就不需要begin了。
我也会用同样的方式布置solve-problem。
https://codereview.stackexchange.com/questions/49369
复制相似问题