Scheme 为什么列表没有添加到球拍中

Scheme 为什么列表没有添加到球拍中,scheme,racket,Scheme,Racket,我有一个小文本文件,如下所示: one, 50, 40, 65, 500 two, 80, 70, 100, 250 three, 100, 55, 125, 100 four, 50, 45, 58, 850 我试图阅读它,并在每一行的第二列列出所有的值。以下是我正在使用的代码: #lang racket (define (testfn fname) (let ((sl '() ) (list2 (list)) (templist '()) (ss "") ) (set! sl (fil

我有一个小文本文件,如下所示:

one, 50, 40, 65, 500
two, 80, 70, 100, 250
three, 100, 55, 125, 100
four, 50, 45, 58, 850
我试图阅读它,并在每一行的第二列列出所有的值。以下是我正在使用的代码:

#lang racket
(define (testfn fname)
(let ((sl '() ) (list2 (list)) (templist '()) (ss "") )
  (set! sl (file->lines fname))
  (for ((line sl))
        (set! templist (string-split line ","))
        (println templist)
        (set! ss (list-ref templist 1))
        (println ss)
        (append list2 ss)        ; does not work
        (append list2 (list ss)) ; does not work
        (cons ss list2)          ; does not work
        (cons (list ss) list2)   ; does not work
        (cons list2 (list ss))   ; does not work
        (cons list2 ss)          ; does not work
        (println list2)
  )
  (println list2)))

(testfn "test.txt")
但是,在我上面使用的许多方法中,“list2”并没有附加字符串“ss”。输出显示:

'("one" " 50" " 40" " 65" " 500")
" 50"
'()
'("two" " 80" " 70" " 100" " 250")
" 80"
'()
'("three" " 100" " 55" " 125" " 100")
" 100"
'()
'("four" " 50" " 45" " 58" " 850")
" 50"
'()
'()
> 
问题在哪里?我如何解决

编辑:更正@JohnClements指出的错误后,以下代码起作用:

#lang racket
(define (testfn fname)
(let ((sl '() ) (list2 (list)) (templist '()) (ss "") )
  (set! sl (file->lines fname))
  (for ((line sl))
        (set! templist (string-split line ","))
        (set! ss (list-ref templist 1))
        (set! list2 (append list2 (list ss)))  
        (println list2)
  )
  (println list2)))

(testfn "test.txt")
输出:

'(" 50")
'(" 50" " 80")
'(" 50" " 80" " 100")
'(" 50" " 80" " 100" " 50")
'(" 50" " 80" " 100" " 50")
> 

哎呀!您的代码是以非常命令式的风格编写的。这种风格的代码很难阅读和维护。我想你会发现,如果你把你的代码分解成更小的函数,并按照“如何设计程序”的设计方法(www.htdp.org)开发代码,你会得到更干净的东西

您遇到的一个基本问题是假设“append”之类的函数会导致变异。具体地说,您假设如果调用,例如,
(append a b)
,则调用后这些列表中的一个或两个将不同。事实并非如此

要了解原因,请想象我编写了以下代码:

#lang racket

(define a 3)
(define b 6)
(+ a b)
(- b a)
(+ (* 2 a) b)
运行此代码后,
a
b
的值是多少

我想你可能会认为他们仍然是3岁和6岁。那是因为加法 减法不会改变他们的论点。同样的情况也适用于
cons
追加
。因此,调用
(append a b)
会生成一个新的列表,但如果不使用该值,那么它将不会出现在任何地方

在这里,让我为你写一些代码,非常快

编辑:

下面是一个使用HtDP样式返回每个列表的第二个元素的程序:

#lang racket

(require rackunit)

;; given a list of lists, return the second of each list:
;; list-of-lists -> list
(define (second-element-map lol)
  (cond [(empty? lol) empty]
        [else (cons (second (first lol))
                    (second-element-map (rest lol)))]))

;; let's test it:
(check-equal? (second-element-map '((a b c) (d e f g) (1 2 3)))
              '(b e 2))

;; given a list of lines, split each one into commas
(define (split-each-line lines)
  (cond [(empty? lines) empty]
        [else (cons (string-split (first lines) ",")
                    (split-each-line (rest lines)))]))

;; let's test it:
(check-equal? (split-each-line '("a,34,2987" "hn th, th"))
              '(("a" "34" "2987")
                ("hn th" " th")))

;; given a filename, return a list containing the second element of
;; each list
;; path-string -> list
(define (testfn fname)
  (second-element-map (split-each-line (file->lines fname))))

(testfn "/tmp/abc.txt")
能再短一点吗?当然HtDP样式干净,保证工作正常

。。。但以下是我为个人消费编写此程序的方式:

#lang racket
(define (testfn2 fname)
  (for/list ([l (in-list (file->lines fname))])
    (second (string-split l ","))))

(testfn2 "/tmp/abc.txt")

哎呀!您的代码是以非常命令式的风格编写的。这种风格的代码很难阅读和维护。我想你会发现,如果你把你的代码分解成更小的函数,并按照“如何设计程序”的设计方法(www.htdp.org)开发代码,你会得到更干净的东西

您遇到的一个基本问题是假设“append”之类的函数会导致变异。具体地说,您假设如果调用,例如,
(append a b)
,则调用后这些列表中的一个或两个将不同。事实并非如此

要了解原因,请想象我编写了以下代码:

#lang racket

(define a 3)
(define b 6)
(+ a b)
(- b a)
(+ (* 2 a) b)
运行此代码后,
a
b
的值是多少

我想你可能会认为他们仍然是3岁和6岁。那是因为加法 减法不会改变他们的论点。同样的情况也适用于
cons
追加
。因此,调用
(append a b)
会生成一个新的列表,但如果不使用该值,那么它将不会出现在任何地方

在这里,让我为你写一些代码,非常快

编辑:

下面是一个使用HtDP样式返回每个列表的第二个元素的程序:

#lang racket

(require rackunit)

;; given a list of lists, return the second of each list:
;; list-of-lists -> list
(define (second-element-map lol)
  (cond [(empty? lol) empty]
        [else (cons (second (first lol))
                    (second-element-map (rest lol)))]))

;; let's test it:
(check-equal? (second-element-map '((a b c) (d e f g) (1 2 3)))
              '(b e 2))

;; given a list of lines, split each one into commas
(define (split-each-line lines)
  (cond [(empty? lines) empty]
        [else (cons (string-split (first lines) ",")
                    (split-each-line (rest lines)))]))

;; let's test it:
(check-equal? (split-each-line '("a,34,2987" "hn th, th"))
              '(("a" "34" "2987")
                ("hn th" " th")))

;; given a filename, return a list containing the second element of
;; each list
;; path-string -> list
(define (testfn fname)
  (second-element-map (split-each-line (file->lines fname))))

(testfn "/tmp/abc.txt")
能再短一点吗?当然HtDP样式干净,保证工作正常

。。。但以下是我为个人消费编写此程序的方式:

#lang racket
(define (testfn2 fname)
  (for/list ([l (in-list (file->lines fname))])
    (second (string-split l ","))))

(testfn2 "/tmp/abc.txt")

是的,我知道了。(设置!列表2(附加列表2(列表ss))已工作。谢谢。如果你能解释一下第二个(较短的)程序是如何工作的,那就太好了。当然!这个程序说:testfn2是一个函数,带有一个名为“fname”的参数。当您调用它时,它会构建一个结果列表,通过考虑文件中的每一行,并在逗号处获取分割该行的第二个结果。因此,所有第二个项目都收集在一个列表中并返回,即使这里没有“collect”关键字(这在Lisp中是需要的)。为什么不只是返回最后一行的第二项?@mso
for/list
对每个元素的主体表达式进行隐式“collect”。它更像是
map
而不是CL循环宏。是的,我知道了。(设置!列表2(附加列表2(列表ss))已工作。谢谢。如果你能解释一下第二个(较短的)程序是如何工作的,那就太好了。当然!这个程序说:testfn2是一个函数,带有一个名为“fname”的参数。当您调用它时,它会构建一个结果列表,通过考虑文件中的每一行,并在逗号处获取分割该行的第二个结果。因此,所有第二个项目都收集在一个列表中并返回,即使这里没有“collect”关键字(这在Lisp中是需要的)。为什么不只是返回最后一行的第二项?@mso
for/list
对每个元素的主体表达式进行隐式“collect”。它更像是
map
,而不是CL循环宏。